summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/Makefile.am13
-rw-r--r--sql/event_data_objects.cc31
-rw-r--r--sql/event_db_repository.cc1
-rw-r--r--sql/event_queue.cc6
-rw-r--r--sql/event_scheduler.cc61
-rw-r--r--sql/events.cc5
-rw-r--r--sql/field.cc211
-rw-r--r--sql/field.h74
-rw-r--r--sql/field_conv.cc15
-rw-r--r--sql/filesort.cc12
-rw-r--r--sql/gen_lex_hash.cc22
-rw-r--r--sql/ha_ndbcluster.cc669
-rw-r--r--sql/ha_ndbcluster.h1
-rw-r--r--sql/ha_ndbcluster_binlog.cc362
-rw-r--r--sql/ha_ndbcluster_binlog.h5
-rw-r--r--sql/ha_partition.cc45
-rw-r--r--sql/ha_partition.h6
-rw-r--r--sql/handler.cc206
-rw-r--r--sql/init.cc6
-rw-r--r--sql/item.cc249
-rw-r--r--sql/item.h91
-rw-r--r--sql/item_cmpfunc.cc296
-rw-r--r--sql/item_cmpfunc.h135
-rw-r--r--sql/item_func.cc102
-rw-r--r--sql/item_func.h2
-rw-r--r--sql/item_geofunc.cc5
-rw-r--r--sql/item_row.h2
-rw-r--r--sql/item_strfunc.cc20
-rw-r--r--sql/item_subselect.cc368
-rw-r--r--sql/item_subselect.h118
-rw-r--r--sql/item_sum.cc31
-rw-r--r--sql/item_timefunc.cc24
-rw-r--r--sql/item_xmlfunc.cc96
-rw-r--r--sql/lex.h2
-rw-r--r--sql/lock.cc4
-rw-r--r--sql/log.cc111
-rw-r--r--sql/log.h10
-rw-r--r--sql/log_event.cc256
-rw-r--r--sql/log_event.h53
-rw-r--r--sql/mysql_priv.h131
-rw-r--r--sql/mysqld.cc565
-rw-r--r--sql/mysqld.cc.rej17
-rw-r--r--sql/net_serv.cc40
-rw-r--r--sql/opt_range.cc222
-rw-r--r--sql/opt_range.h2
-rw-r--r--sql/opt_sum.cc10
-rw-r--r--sql/parse_file.cc2
-rw-r--r--sql/partition_info.cc1
-rw-r--r--sql/password.c7
-rw-r--r--sql/protocol.cc8
-rw-r--r--sql/protocol.h2
-rw-r--r--sql/repl_failsafe.cc33
-rw-r--r--sql/rpl_injector.h2
-rw-r--r--sql/rpl_rli.cc20
-rw-r--r--sql/rpl_rli.h15
-rw-r--r--sql/rpl_utility.h109
-rw-r--r--sql/scheduler.cc88
-rw-r--r--sql/scheduler.h60
-rw-r--r--sql/set_var.cc35
-rw-r--r--sql/set_var.h98
-rw-r--r--sql/slave.cc133
-rw-r--r--sql/slave.h3
-rw-r--r--sql/sp.cc28
-rw-r--r--sql/sp_head.cc80
-rw-r--r--sql/sp_head.h42
-rw-r--r--sql/spatial.cc26
-rw-r--r--sql/spatial.h12
-rw-r--r--sql/sql_acl.cc58
-rw-r--r--sql/sql_analyse.cc10
-rw-r--r--sql/sql_base.cc353
-rw-r--r--sql/sql_binlog.cc2
-rw-r--r--sql/sql_cache.h6
-rw-r--r--sql/sql_class.cc139
-rw-r--r--sql/sql_class.h161
-rw-r--r--sql/sql_connect.cc1108
-rw-r--r--sql/sql_delete.cc18
-rw-r--r--sql/sql_derived.cc2
-rw-r--r--sql/sql_help.cc2
-rw-r--r--sql/sql_insert.cc305
-rw-r--r--sql/sql_lex.cc96
-rw-r--r--sql/sql_lex.h42
-rw-r--r--sql/sql_list.h2
-rw-r--r--sql/sql_load.cc12
-rw-r--r--sql/sql_parse.cc1409
-rw-r--r--sql/sql_parse.cc.rej166
-rw-r--r--sql/sql_partition.cc7
-rw-r--r--sql/sql_plugin.cc32
-rw-r--r--sql/sql_prepare.cc206
-rw-r--r--sql/sql_repl.cc16
-rw-r--r--sql/sql_select.cc627
-rw-r--r--sql/sql_select.h42
-rw-r--r--sql/sql_servers.cc11
-rw-r--r--sql/sql_servers.h1
-rw-r--r--sql/sql_show.cc251
-rw-r--r--sql/sql_string.cc19
-rw-r--r--sql/sql_string.h3
-rw-r--r--sql/sql_table.cc126
-rw-r--r--sql/sql_test.cc12
-rw-r--r--sql/sql_trigger.cc39
-rw-r--r--sql/sql_trigger.h9
-rw-r--r--sql/sql_union.cc92
-rw-r--r--sql/sql_update.cc21
-rw-r--r--sql/sql_view.cc11
-rw-r--r--sql/sql_yacc.yy1131
-rw-r--r--sql/table.cc74
-rw-r--r--sql/table.cc.rej17
-rw-r--r--sql/table.h41
-rw-r--r--sql/tztime.cc8
-rw-r--r--sql/udf_example.c2
-rw-r--r--sql/udf_example.def1
-rw-r--r--sql/unireg.cc13
112 files changed, 7574 insertions, 4647 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 37707fe3963..002aabb91b0 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -69,6 +69,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc
sql_tablespace.cc events.cc ../sql-common/my_user.c
partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc
rpl_rli.cc rpl_mi.cc sql_servers.cc
+ sql_connect.cc scheduler.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
${PROJECT_SOURCE_DIR}/include/mysqld_error.h
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 264b469cd8c..c3a692615dd 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -40,7 +40,8 @@ mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \
@pstack_libs@ \
@mysql_plugin_libs@ \
$(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ \
- @yassl_libs@ @openssl_libs@
+ $(yassl_libs) $(openssl_libs)
+
noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
item_strfunc.h item_timefunc.h \
item_xmlfunc.h \
@@ -63,10 +64,11 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
tztime.h my_decimal.h\
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
parse_file.h sql_view.h sql_trigger.h \
- sql_array.h sql_cursor.h events.h \
+ sql_array.h sql_cursor.h events.h scheduler.h \
event_db_repository.h event_queue.h \
- sql_plugin.h authors.h sql_partition.h event_data_objects.h \
- partition_info.h partition_element.h event_scheduler.h \
+ sql_plugin.h authors.h \
+ event_data_objects.h event_scheduler.h \
+ sql_partition.h partition_info.h partition_element.h \
contributors.h sql_servers.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
@@ -78,7 +80,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
lock.cc my_lock.c \
sql_string.cc sql_manager.cc sql_map.cc \
mysqld.cc password.c hash_filo.cc hostname.cc \
- set_var.cc sql_parse.cc sql_yacc.yy \
+ sql_connect.cc scheduler.cc sql_parse.cc \
+ set_var.cc sql_yacc.yy \
sql_base.cc table.cc sql_select.cc sql_insert.cc \
sql_prepare.cc sql_error.cc sql_locale.cc \
sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 198f6518184..dad8aeb2e20 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -611,16 +611,18 @@ Event_parse_data::check_parse_data(THD *thd)
void
Event_parse_data::init_definer(THD *thd)
{
- int definer_user_len;
- int definer_host_len;
DBUG_ENTER("Event_parse_data::init_definer");
- DBUG_PRINT("info",("init definer_user thd->mem_root: 0x%lx "
- "thd->sec_ctx->priv_user: 0x%lx", (long) thd->mem_root,
- (long) thd->security_ctx->priv_user));
+ DBUG_ASSERT(thd->lex->definer);
+
+ const char *definer_user= thd->lex->definer->user.str;
+ const char *definer_host= thd->lex->definer->host.str;
+ int definer_user_len= thd->lex->definer->user.length;
+ int definer_host_len= thd->lex->definer->host.length;
- definer_user_len= strlen(thd->security_ctx->priv_user);
- definer_host_len= strlen(thd->security_ctx->priv_host);
+ DBUG_PRINT("info",("init definer_user thd->mem_root: 0x%lx "
+ "definer_user: 0x%lx", (long) thd->mem_root,
+ (long) definer_user));
/* + 1 for @ */
DBUG_PRINT("info",("init definer as whole"));
@@ -628,12 +630,11 @@ Event_parse_data::init_definer(THD *thd)
definer.str= thd->alloc(definer.length + 1);
DBUG_PRINT("info",("copy the user"));
- memcpy(definer.str, thd->security_ctx->priv_user, definer_user_len);
+ memcpy(definer.str, definer_user, definer_user_len);
definer.str[definer_user_len]= '@';
DBUG_PRINT("info",("copy the host"));
- memcpy(definer.str + definer_user_len + 1, thd->security_ctx->priv_host,
- definer_host_len);
+ memcpy(definer.str + definer_user_len + 1, definer_host, definer_host_len);
definer.str[definer.length]= '\0';
DBUG_PRINT("info",("definer [%s] initted", definer.str));
@@ -1578,7 +1579,6 @@ done:
int
Event_timed::get_create_event(THD *thd, String *buf)
{
- int multipl= 0;
char tmp_buf[2 * STRING_BUFFER_USUAL_SIZE];
String expr_buf(tmp_buf, sizeof(tmp_buf), system_charset_info);
expr_buf.length(0);
@@ -1810,17 +1810,12 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
{
DBUG_PRINT("error", ("error during compile or thd->is_fatal_error: %d",
thd->is_fatal_error));
- /*
- Free lex associated resources
- QQ: Do we really need all this stuff here?
- */
+ lex.unit.cleanup();
+
sql_print_error("SCHEDULER: Error during compilation of %s.%s or "
"thd->is_fatal_error: %d",
dbname.str, name.str, thd->is_fatal_error);
- lex.unit.cleanup();
- delete lex.sphead;
- sphead= lex.sphead= NULL;
ret= EVEX_COMPILE_ERROR;
goto done;
}
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index bcc7d476fff..940930ec4c6 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -518,7 +518,6 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
my_bool create_if_not)
{
int ret= 0;
- CHARSET_INFO *scs= system_charset_info;
TABLE *table= NULL;
char old_db_buf[NAME_LEN+1];
LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) };
diff --git a/sql/event_queue.cc b/sql/event_queue.cc
index c4e6a518974..296c30506f6 100644
--- a/sql/event_queue.cc
+++ b/sql/event_queue.cc
@@ -137,8 +137,6 @@ Event_queue::deinit_mutexes()
bool
Event_queue::init_queue(THD *thd)
{
- struct event_queue_param *event_queue_param_value= NULL;
-
DBUG_ENTER("Event_queue::init_queue");
DBUG_PRINT("enter", ("this: 0x%lx", (long) this));
@@ -203,7 +201,7 @@ void
Event_queue::create_event(THD *thd, Event_queue_element *new_element)
{
DBUG_ENTER("Event_queue::create_event");
- DBUG_PRINT("enter", ("thd=0x%lx et=%s.%s",thd,
+ DBUG_PRINT("enter", ("thd: 0x%lx et=%s.%s", (long) thd,
new_element->dbname.str, new_element->name.str));
if (new_element->status == Event_queue_element::DISABLED)
@@ -211,7 +209,7 @@ Event_queue::create_event(THD *thd, Event_queue_element *new_element)
else
{
new_element->compute_next_execution_time();
- DBUG_PRINT("info", ("new event in the queue 0x%lx", new_element));
+ DBUG_PRINT("info", ("new event in the queue: 0x%lx", (long) new_element));
LOCK_QUEUE_DATA();
queue_insert_safe(&queue, (byte *) new_element);
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index 1013f5af3a8..64bba756be9 100644
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -110,25 +110,22 @@ Event_worker_thread::print_warnings(THD *thd, Event_job_data *et)
SYNOPSIS
post_init_event_thread()
thd Thread
+
+ NOTES
+ Before this is called, one should not do any DBUG_XXX() calls.
+
*/
bool
post_init_event_thread(THD *thd)
{
- my_thread_init();
- pthread_detach_this_thread();
- thd->real_id= pthread_self();
+ (void) init_new_connection_handler_thread();
if (init_thr_lock() || thd->store_globals())
{
thd->cleanup();
return TRUE;
}
-#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
pthread_mutex_lock(&LOCK_thread_count);
threads.append(thd);
thread_count++;
@@ -193,7 +190,7 @@ pre_init_event_thread(THD* thd)
thd->options|= OPTION_AUTO_IS_NULL;
thd->client_capabilities|= CLIENT_MULTI_RESULTS;
pthread_mutex_lock(&LOCK_thread_count);
- thd->thread_id= thread_id++;
+ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
pthread_mutex_unlock(&LOCK_thread_count);
/*
@@ -224,20 +221,20 @@ pthread_handler_t
event_scheduler_thread(void *arg)
{
/* needs to be first for thread_stack */
- THD *thd= (THD *)((struct scheduler_param *) arg)->thd;
+ THD *thd= (THD *) ((struct scheduler_param *) arg)->thd;
Event_scheduler *scheduler= ((struct scheduler_param *) arg)->scheduler;
-
- my_free((char*)arg, MYF(0));
+ bool res;
thd->thread_stack= (char *)&thd; // remember where our stack is
+ res= post_init_event_thread(thd);
DBUG_ENTER("event_scheduler_thread");
-
- if (!post_init_event_thread(thd))
+ my_free((char*)arg, MYF(0));
+ if (!res)
scheduler->run(thd);
deinit_event_thread(thd);
-
+ pthread_exit(0);
DBUG_RETURN(0); // Against gcc warnings
}
@@ -257,17 +254,13 @@ event_scheduler_thread(void *arg)
pthread_handler_t
event_worker_thread(void *arg)
{
- /* needs to be first for thread_stack */
THD *thd;
Event_queue_element_for_exec *event= (Event_queue_element_for_exec *)arg;
thd= event->thd;
- thd->thread_stack= (char *) &thd; // remember where our stack is
Event_worker_thread worker_thread;
- worker_thread.run(thd, (Event_queue_element_for_exec *)arg);
-
- deinit_event_thread(thd);
+ worker_thread.run(thd, event);
return 0; // Can't return anything here
}
@@ -286,13 +279,20 @@ event_worker_thread(void *arg)
void
Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event)
{
+ /* needs to be first for thread_stack */
+ char my_stack;
int ret;
Event_job_data *job_data= NULL;
+ bool res;
+
+ thd->thread_stack= &my_stack; // remember where our stack is
+ res= post_init_event_thread(thd);
+
DBUG_ENTER("Event_worker_thread::run");
- DBUG_PRINT("info", ("Baikonur, time is %d, BURAN reporting and operational."
- "THD=0x%lx", time(NULL), thd));
+ DBUG_PRINT("info", ("Time is %ld, THD: 0x%lx",
+ (long) time(NULL), (long) thd));
- if (post_init_event_thread(thd))
+ if (res)
goto end;
if (!(job_data= new Event_job_data()))
@@ -322,6 +322,8 @@ Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event)
job_data->dbname.str, job_data->name.str,
job_data->definer.str);
else if (ret == EVEX_MICROSECOND_UNSUP)
+ sql_print_information("SCHEDULER: MICROSECOND is not supported");
+
end:
delete job_data;
@@ -346,10 +348,12 @@ end:
*/
events_facade->drop_event(thd, event->dbname, event->name, FALSE);
}
- DBUG_PRINT("info", ("BURAN %s.%s is landing!", event->dbname.str,
+ DBUG_PRINT("info", ("Done with Event %s.%s", event->dbname.str,
event->name.str));
delete event;
+ deinit_event_thread(thd);
+ pthread_exit(0);
}
@@ -517,7 +521,8 @@ Event_scheduler::run(THD *thd)
break;
}
- DBUG_PRINT("info", ("get_top returned job_data=0x%lx", event_name));
+ DBUG_PRINT("info", ("get_top_for_execution_if_time returned "
+ "event_name=0x%lx", (long) event_name));
if (event_name)
{
if ((res= execute_top(thd, event_name)))
@@ -566,7 +571,7 @@ Event_scheduler::execute_top(THD *thd, Event_queue_element_for_exec *event_name)
pre_init_event_thread(new_thd);
new_thd->system_thread= SYSTEM_THREAD_EVENT_WORKER;
event_name->thd= new_thd;
- DBUG_PRINT("info", ("BURAN %s@%s ready for start t-3..2..1..0..ignition",
+ DBUG_PRINT("info", ("Event %s@%s ready for start",
event_name->dbname.str, event_name->name.str));
/* Major failure */
@@ -576,11 +581,11 @@ Event_scheduler::execute_top(THD *thd, Event_queue_element_for_exec *event_name)
++started_events;
- DBUG_PRINT("info", ("Launch succeeded. BURAN is in THD: 0x%lx", (long) new_thd));
+ DBUG_PRINT("info", ("Event is in THD: 0x%lx", (long) new_thd));
DBUG_RETURN(FALSE);
error:
- DBUG_PRINT("error", ("Baikonur, we have a problem! res: %d", res));
+ DBUG_PRINT("error", ("Event_scheduler::execute_top() res: %d", res));
if (new_thd)
{
new_thd->proc_info= "Clearing";
diff --git a/sql/events.cc b/sql/events.cc
index 425e288dfb7..f73dc97e7c2 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -923,7 +923,7 @@ Events::load_events_from_db(THD *thd)
bool clean_the_queue= TRUE;
DBUG_ENTER("Events::load_events_from_db");
- DBUG_PRINT("enter", ("thd=0x%lx", thd));
+ DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
if ((ret= db_repository->open_event_table(thd, TL_READ, &table)))
{
@@ -994,7 +994,8 @@ Events::load_events_from_db(THD *thd)
goto end;
}
- DBUG_PRINT("load_events_from_db", ("Adding 0x%lx to the exec list."));
+ DBUG_PRINT("load_events_from_db", ("Adding 0x%lx to the exec list.",
+ (long) et));
event_queue->create_event(thd, et);
count++;
}
diff --git a/sql/field.cc b/sql/field.cc
index 3114c8b595e..d406459b6c7 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1415,12 +1415,12 @@ my_decimal* Field_num::val_decimal(my_decimal *decimal_value)
Field_str::Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
- const char *field_name_arg, CHARSET_INFO *charset)
+ const char *field_name_arg, CHARSET_INFO *charset_arg)
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg)
{
- field_charset=charset;
- if (charset->state & MY_CS_BINSORT)
+ field_charset= charset_arg;
+ if (charset_arg->state & MY_CS_BINSORT)
flags|=BINARY_FLAG;
field_derivation= DERIVATION_IMPLICIT;
}
@@ -1527,7 +1527,7 @@ bool Field::get_time(TIME *ltime)
Needs to be changed if/when we want to support different time formats
*/
-int Field::store_time(TIME *ltime, timestamp_type type)
+int Field::store_time(TIME *ltime, timestamp_type type_arg)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[MAX_DATE_STRING_REP_LENGTH];
@@ -2242,12 +2242,12 @@ Field_new_decimal::Field_new_decimal(char *ptr_arg,
Field_new_decimal::Field_new_decimal(uint32 len_arg,
- bool maybe_null,
+ bool maybe_null_arg,
const char *name,
uint8 dec_arg,
bool unsigned_arg)
:Field_num((char*) 0, len_arg,
- maybe_null ? (uchar*) "": 0, 0,
+ maybe_null_arg ? (uchar*) "": 0, 0,
NONE, name, dec_arg, 0, unsigned_arg)
{
precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
@@ -2351,7 +2351,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
int Field_new_decimal::store(const char *from, uint length,
- CHARSET_INFO *charset)
+ CHARSET_INFO *charset_arg)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
int err;
@@ -2360,7 +2360,7 @@ int Field_new_decimal::store(const char *from, uint length,
if ((err= str2my_decimal(E_DEC_FATAL_ERROR &
~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
- from, length, charset, &decimal_value)) &&
+ from, length, charset_arg, &decimal_value)) &&
table->in_use->abort_on_warning)
{
/* Because "from" is not NUL-terminated and we use %s in the ER() */
@@ -2556,7 +2556,7 @@ uint Field_new_decimal::is_equal(create_field *new_field)
(uint) (flags & UNSIGNED_FLAG)) &&
((new_field->flags & AUTO_INCREMENT_FLAG) ==
(uint) (flags & AUTO_INCREMENT_FLAG)) &&
- (new_field->length == max_length()) &&
+ (new_field->length == max_display_length()) &&
(new_field->decimals == dec));
}
@@ -3282,25 +3282,6 @@ void Field_medium::sql_type(String &res) const
** long int
****************************************************************************/
-/*
- A helper function to check whether the next character
- in the string "s" is MINUS SIGN.
-*/
-#ifdef HAVE_CHARSET_ucs2
-static bool test_if_minus(CHARSET_INFO *cs,
- const char *s, const char *e)
-{
- my_wc_t wc;
- return cs->cset->mb_wc(cs, &wc, (uchar*) s, (uchar*) e) > 0 && wc == '-';
-}
-#else
-/*
- If not UCS2 support is compiled then it is easier
-*/
-#define test_if_minus(cs, s, e) (*s == '-')
-#endif
-
-
int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
@@ -4163,7 +4144,7 @@ int Field_double::store(double nr)
else
{
double max_value;
- if (dec >= NOT_FIXED_DEC)
+ if (not_fixed)
{
max_value= DBL_MAX;
}
@@ -4912,7 +4893,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
}
-int Field_time::store_time(TIME *ltime, timestamp_type type)
+int Field_time::store_time(TIME *ltime, timestamp_type time_type)
{
long tmp= ((ltime->month ? 0 : ltime->day * 24L) + ltime->hour) * 10000L +
(ltime->minute * 100 + ltime->second);
@@ -5523,12 +5504,13 @@ int Field_newdate::store(longlong nr, bool unsigned_val)
}
-int Field_newdate::store_time(TIME *ltime,timestamp_type type)
+int Field_newdate::store_time(TIME *ltime,timestamp_type time_type)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
long tmp;
int error= 0;
- if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME)
+ if (time_type == MYSQL_TIMESTAMP_DATE ||
+ time_type == MYSQL_TIMESTAMP_DATETIME)
{
tmp=ltime->year*16*32+ltime->month*32+ltime->day;
if (check_date(ltime, tmp != 0,
@@ -5748,7 +5730,7 @@ int Field_datetime::store(longlong nr, bool unsigned_val)
}
-int Field_datetime::store_time(TIME *ltime,timestamp_type type)
+int Field_datetime::store_time(TIME *ltime,timestamp_type time_type)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
longlong tmp;
@@ -5757,7 +5739,8 @@ int Field_datetime::store_time(TIME *ltime,timestamp_type type)
We don't perform range checking here since values stored in TIME
structure always fit into DATETIME range.
*/
- if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME)
+ if (time_type == MYSQL_TIMESTAMP_DATE ||
+ time_type == MYSQL_TIMESTAMP_DATETIME)
{
tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+
(ltime->hour*10000L+ltime->minute*100+ltime->second));
@@ -6136,32 +6119,32 @@ int Field_str::store(double nr)
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
uint length;
bool use_scientific_notation= TRUE;
- uint char_length= field_length / charset()->mbmaxlen;
+ uint local_char_length= field_length / charset()->mbmaxlen;
/*
Check fabs(nr) against longest value that can be stored in field,
which depends on whether the value is < 1 or not, and negative or not
*/
double anr= fabs(nr);
int neg= (nr < 0.0) ? 1 : 0;
- if (char_length > 4 && char_length < 32 &&
- (anr < 1.0 ? anr > 1/(log_10[max(0,(int) char_length-neg-2)]) /* -2 for "0." */
- : anr < log_10[char_length-neg]-1))
+ if (local_char_length > 4 && local_char_length < 32 &&
+ (anr < 1.0 ? anr > 1/(log_10[max(0,(int) local_char_length-neg-2)]) /* -2 for "0." */
+ : anr < log_10[local_char_length-neg]-1))
use_scientific_notation= FALSE;
length= (uint) my_sprintf(buff, (buff, "%-.*g",
(use_scientific_notation ?
- max(0, (int)char_length-neg-5) :
- char_length),
+ max(0, (int)local_char_length-neg-5) :
+ local_char_length),
nr));
/*
+1 below is because "precision" in %g above means the
max. number of significant digits, not the output width.
Thus the width can be larger than number of significant digits by 1
(for decimal point)
- the test for char_length < 5 is for extreme cases,
+ the test for local_char_length < 5 is for extreme cases,
like inserting 500.0 in char(1)
*/
- DBUG_ASSERT(char_length < 5 || length <= char_length+1);
+ DBUG_ASSERT(local_char_length < 5 || length <= local_char_length+1);
return store((const char *) buff, length, charset());
}
@@ -6182,7 +6165,7 @@ uint Field_str::is_equal(create_field *new_field)
return ((new_field->sql_type == real_type()) &&
new_field->charset == field_charset &&
- new_field->length == max_length());
+ new_field->length == max_display_length());
}
@@ -6314,9 +6297,9 @@ int Field_string::cmp(const char *a_ptr, const char *b_ptr)
void Field_string::sort_string(char *to,uint length)
{
- uint tmp= my_strnxfrm(field_charset,
- (uchar*) to, length,
- (uchar*) ptr, field_length);
+ IF_DBUG(uint tmp=) my_strnxfrm(field_charset,
+ (uchar*) to, length,
+ (uchar*) ptr, field_length);
DBUG_ASSERT(tmp == length);
}
@@ -6344,10 +6327,11 @@ void Field_string::sql_type(String &res) const
char *Field_string::pack(char *to, const char *from, uint max_length)
{
uint length= min(field_length,max_length);
- uint char_length= max_length/field_charset->mbmaxlen;
- if (length > char_length)
- char_length= my_charpos(field_charset, from, from+length, char_length);
- set_if_smaller(length, char_length);
+ uint local_char_length= max_length/field_charset->mbmaxlen;
+ if (length > local_char_length)
+ local_char_length= my_charpos(field_charset, from, from+length,
+ local_char_length);
+ set_if_smaller(length, local_char_length);
while (length && from[length-1] == ' ')
length--;
*to++= (char) (uchar) length;
@@ -6431,15 +6415,15 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length,
int Field_string::pack_cmp(const char *key, uint length,
my_bool insert_or_update)
{
- uint row_length, key_length;
+ uint row_length, local_key_length;
char *end;
if (length > 255)
{
- key_length= uint2korr(key);
+ local_key_length= uint2korr(key);
key+= 2;
}
else
- key_length= (uint) (uchar) *key++;
+ local_key_length= (uint) (uchar) *key++;
/* Only use 'length' of key, not field_length */
end= ptr + length;
@@ -6449,7 +6433,7 @@ int Field_string::pack_cmp(const char *key, uint length,
return field_charset->coll->strnncollsp(field_charset,
(const uchar*) ptr, row_length,
- (const uchar*) key, key_length,
+ (const uchar*) key, local_key_length,
insert_or_update);
}
@@ -6641,11 +6625,11 @@ int Field_varstring::cmp_max(const char *a_ptr, const char *b_ptr,
int Field_varstring::key_cmp(const byte *key_ptr, uint max_key_length)
{
uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
- uint char_length= max_key_length / field_charset->mbmaxlen;
+ uint local_char_length= max_key_length / field_charset->mbmaxlen;
- char_length= my_charpos(field_charset, ptr + length_bytes,
- ptr + length_bytes + length, char_length);
- set_if_smaller(length, char_length);
+ local_char_length= my_charpos(field_charset, ptr + length_bytes,
+ ptr + length_bytes + length, local_char_length);
+ set_if_smaller(length, local_char_length);
return field_charset->coll->strnncollsp(field_charset,
(const uchar*) ptr + length_bytes,
length,
@@ -6755,13 +6739,14 @@ char *Field_varstring::pack(char *to, const char *from, uint max_length)
char *Field_varstring::pack_key(char *to, const char *key, uint max_length)
{
uint length= length_bytes == 1 ? (uint) (uchar) *key : uint2korr(key);
- uint char_length= ((field_charset->mbmaxlen > 1) ?
+ uint local_char_length= ((field_charset->mbmaxlen > 1) ?
max_length/field_charset->mbmaxlen : max_length);
key+= length_bytes;
- if (length > char_length)
+ if (length > local_char_length)
{
- char_length= my_charpos(field_charset, key, key+length, char_length);
- set_if_smaller(length, char_length);
+ local_char_length= my_charpos(field_charset, key, key+length,
+ local_char_length);
+ set_if_smaller(length, local_char_length);
}
*to++= (char) (length & 255);
if (max_length > 255)
@@ -6857,11 +6842,12 @@ const char *Field_varstring::unpack(char *to, const char *from)
}
-int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length,
+int Field_varstring::pack_cmp(const char *a, const char *b,
+ uint key_length_arg,
my_bool insert_or_update)
{
uint a_length, b_length;
- if (key_length > 255)
+ if (key_length_arg > 255)
{
a_length=uint2korr(a); a+= 2;
b_length=uint2korr(b); b+= 2;
@@ -6878,26 +6864,28 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length,
}
-int Field_varstring::pack_cmp(const char *b, uint key_length,
+int Field_varstring::pack_cmp(const char *b, uint key_length_arg,
my_bool insert_or_update)
{
char *a= ptr+ length_bytes;
uint a_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
uint b_length;
- uint char_length= ((field_charset->mbmaxlen > 1) ?
- key_length / field_charset->mbmaxlen : key_length);
+ uint local_char_length= ((field_charset->mbmaxlen > 1) ?
+ key_length_arg / field_charset->mbmaxlen :
+ key_length_arg);
- if (key_length > 255)
+ if (key_length_arg > 255)
{
b_length=uint2korr(b); b+= HA_KEY_BLOB_LENGTH;
}
else
b_length= (uint) (uchar) *b++;
- if (a_length > char_length)
+ if (a_length > local_char_length)
{
- char_length= my_charpos(field_charset, a, a+a_length, char_length);
- set_if_smaller(a_length, char_length);
+ local_char_length= my_charpos(field_charset, a, a+a_length,
+ local_char_length);
+ set_if_smaller(a_length, local_char_length);
}
return field_charset->coll->strnncollsp(field_charset,
@@ -6922,13 +6910,15 @@ uint Field_varstring::max_packed_col_length(uint max_length)
}
-void Field_varstring::get_key_image(char *buff, uint length, imagetype type)
+void Field_varstring::get_key_image(char *buff, uint length,
+ imagetype type_arg)
{
uint f_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
- uint char_length= length / field_charset->mbmaxlen;
+ uint local_char_length= length / field_charset->mbmaxlen;
char *pos= ptr+length_bytes;
- char_length= my_charpos(field_charset, pos, pos + f_length, char_length);
- set_if_smaller(f_length, char_length);
+ local_char_length= my_charpos(field_charset, pos, pos + f_length,
+ local_char_length);
+ set_if_smaller(f_length, local_char_length);
/* Key is always stored with 2 bytes */
int2store(buff,f_length);
memcpy(buff+HA_KEY_BLOB_LENGTH, pos, f_length);
@@ -7009,11 +6999,11 @@ uint Field_varstring::is_equal(create_field *new_field)
if (new_field->sql_type == real_type() &&
new_field->charset == field_charset)
{
- if (new_field->length == max_length())
+ if (new_field->length == max_display_length())
return IS_EQUAL_YES;
- if (new_field->length > max_length() &&
- ((new_field->length <= 255 && max_length() <= 255) ||
- (new_field->length > 255 && max_length() > 255)))
+ if (new_field->length > max_display_length() &&
+ ((new_field->length <= 255 && max_display_length() <= 255) ||
+ (new_field->length > 255 && max_display_length() > 255)))
return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer variable length
}
return IS_EQUAL_NO;
@@ -7213,7 +7203,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
cannot_convert_error_pos, from + length))
return 2;
- if (copy_length < length)
+ if (from_end_pos < from + length)
{
report_data_too_long(this);
return 2;
@@ -7344,13 +7334,13 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
/* The following is used only when comparing a key */
-void Field_blob::get_key_image(char *buff, uint length, imagetype type)
+void Field_blob::get_key_image(char *buff, uint length, imagetype type_arg)
{
uint32 blob_length= get_length(ptr);
char *blob;
#ifdef HAVE_SPATIAL
- if (type == itMBR)
+ if (type_arg == itMBR)
{
const char *dummy;
MBR mbr;
@@ -7378,10 +7368,10 @@ void Field_blob::get_key_image(char *buff, uint length, imagetype type)
#endif /*HAVE_SPATIAL*/
get_ptr(&blob);
- uint char_length= length / field_charset->mbmaxlen;
- char_length= my_charpos(field_charset, blob, blob + blob_length,
- char_length);
- set_if_smaller(blob_length, char_length);
+ uint local_char_length= length / field_charset->mbmaxlen;
+ local_char_length= my_charpos(field_charset, blob, blob + blob_length,
+ local_char_length);
+ set_if_smaller(blob_length, local_char_length);
if ((uint32) length > blob_length)
{
@@ -7410,9 +7400,10 @@ int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
uint blob_length=get_length(ptr);
memcpy_fixed(&blob1,ptr+packlength,sizeof(char*));
CHARSET_INFO *cs= charset();
- uint char_length= max_key_length / cs->mbmaxlen;
- char_length= my_charpos(cs, blob1, blob1+blob_length, char_length);
- set_if_smaller(blob_length, char_length);
+ uint local_char_length= max_key_length / cs->mbmaxlen;
+ local_char_length= my_charpos(cs, blob1, blob1+blob_length,
+ local_char_length);
+ set_if_smaller(blob_length, local_char_length);
return Field_blob::cmp(blob1, blob_length,
(char*) key_ptr+HA_KEY_BLOB_LENGTH,
uint2korr(key_ptr));
@@ -7534,11 +7525,11 @@ const char *Field_blob::unpack(char *to, const char *from)
/* Keys for blobs are like keys on varchars */
-int Field_blob::pack_cmp(const char *a, const char *b, uint key_length,
+int Field_blob::pack_cmp(const char *a, const char *b, uint key_length_arg,
my_bool insert_or_update)
{
uint a_length, b_length;
- if (key_length > 255)
+ if (key_length_arg > 255)
{
a_length=uint2korr(a); a+=2;
b_length=uint2korr(b); b+=2;
@@ -7555,19 +7546,19 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length,
}
-int Field_blob::pack_cmp(const char *b, uint key_length,
+int Field_blob::pack_cmp(const char *b, uint key_length_arg,
my_bool insert_or_update)
{
char *a;
+ uint a_length, b_length;
memcpy_fixed(&a,ptr+packlength,sizeof(char*));
if (!a)
- return key_length > 0 ? -1 : 0;
- uint a_length=get_length(ptr);
- uint b_length;
+ return key_length_arg > 0 ? -1 : 0;
- if (key_length > 255)
+ a_length= get_length(ptr);
+ if (key_length_arg > 255)
{
- b_length=uint2korr(b); b+=2;
+ b_length= uint2korr(b); b+=2;
}
else
b_length= (uint) (uchar) *b++;
@@ -7584,13 +7575,14 @@ char *Field_blob::pack_key(char *to, const char *from, uint max_length)
char *save=ptr;
ptr=(char*) from;
uint32 length=get_length(); // Length of from string
- uint char_length= ((field_charset->mbmaxlen > 1) ?
+ uint local_char_length= ((field_charset->mbmaxlen > 1) ?
max_length/field_charset->mbmaxlen : max_length);
if (length)
get_ptr((char**) &from);
- if (length > char_length)
- char_length= my_charpos(field_charset, from, from+length, char_length);
- set_if_smaller(length, char_length);
+ if (length > local_char_length)
+ local_char_length= my_charpos(field_charset, from, from+length,
+ local_char_length);
+ set_if_smaller(length, local_char_length);
*to++= (uchar) length;
if (max_length > 255) // 2 byte length
*to++= (uchar) (length >> 8);
@@ -7677,7 +7669,7 @@ uint Field_blob::max_packed_col_length(uint max_length)
#ifdef HAVE_SPATIAL
-void Field_geom::get_key_image(char *buff, uint length, imagetype type)
+void Field_geom::get_key_image(char *buff, uint length, imagetype type_arg)
{
char *blob;
const char *dummy;
@@ -7775,7 +7767,7 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
goto err;
wkb_type= uint4korr(from + SRID_SIZE + 1);
if (wkb_type < (uint32) Geometry::wkb_point ||
- wkb_type > (uint32) Geometry::wkb_end)
+ wkb_type > (uint32) Geometry::wkb_last)
goto err;
Field_blob::store_length(length);
if (table->copy_blobs || length <= MAX_FIELD_WIDTH)
@@ -8204,7 +8196,7 @@ uint Field_num::is_equal(create_field *new_field)
UNSIGNED_FLAG)) &&
((new_field->flags & AUTO_INCREMENT_FLAG) ==
(uint) (flags & AUTO_INCREMENT_FLAG)) &&
- (new_field->length <= max_length()));
+ (new_field->length <= max_display_length()));
}
@@ -8485,7 +8477,7 @@ int Field_bit::cmp_offset(uint row_offset)
}
-void Field_bit::get_key_image(char *buff, uint length, imagetype type)
+void Field_bit::get_key_image(char *buff, uint length, imagetype type_arg)
{
if (bit_len)
{
@@ -8659,7 +8651,7 @@ void create_field::create_length_to_internal_length(void)
void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
- uint32 length_arg, uint32 decimals,
+ uint32 length_arg, uint32 decimals_arg,
bool maybe_null, bool is_unsigned)
{
field_name= "";
@@ -8670,7 +8662,7 @@ void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
charset= &my_charset_bin;
geom_type= Field::GEOM_GEOMETRY;
pack_flag= (FIELDFLAG_NUMBER |
- ((decimals & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) |
+ ((decimals_arg & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) |
(maybe_null ? FIELDFLAG_MAYBE_NULL : 0) |
(is_unsigned ? 0 : FIELDFLAG_DECIMAL));
}
@@ -9378,12 +9370,13 @@ create_field::create_field(Field *old_field,Field *orig_field)
maximum possible display length for blob
SYNOPSIS
- Field_blob::max_length()
+ Field_blob::max_display_length()
RETURN
length
*/
-uint32 Field_blob::max_length()
+
+uint32 Field_blob::max_display_length()
{
switch (packlength)
{
diff --git a/sql/field.h b/sql/field.h
index d0a2e0ca225..f27ed8b9394 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -30,7 +30,7 @@ class Send_field;
class Protocol;
class create_field;
struct st_cache_field;
-void field_conv(Field *to,Field *from);
+int field_conv(Field *to,Field *from);
inline uint get_enum_pack_length(int elements)
{
@@ -158,12 +158,12 @@ public:
virtual void reset_fields() {}
virtual void set_default()
{
- my_ptrdiff_t offset = (my_ptrdiff_t) (table->s->default_values -
+ my_ptrdiff_t l_offset= (my_ptrdiff_t) (table->s->default_values -
table->record[0]);
- memcpy(ptr, ptr + offset, pack_length());
+ memcpy(ptr, ptr + l_offset, pack_length());
if (null_ptr)
*null_ptr= ((*null_ptr & (uchar) ~null_bit) |
- null_ptr[offset] & null_bit);
+ null_ptr[l_offset] & null_bit);
}
virtual bool binary() const { return 1; }
virtual bool zero_pack() const { return 1; }
@@ -276,7 +276,7 @@ public:
{ memcpy(buff,ptr,length); }
inline void set_image(char *buff,uint length, CHARSET_INFO *cs)
{ memcpy(ptr,buff,length); }
- virtual void get_key_image(char *buff, uint length, imagetype type)
+ virtual void get_key_image(char *buff, uint length, imagetype type_arg)
{ get_image(buff,length, &my_charset_bin); }
virtual void set_key_image(char *buff,uint length)
{ set_image(buff,length, &my_charset_bin); }
@@ -352,10 +352,10 @@ public:
virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
virtual bool has_charset(void) const { return FALSE; }
- virtual void set_charset(CHARSET_INFO *charset) { }
+ virtual void set_charset(CHARSET_INFO *charset_arg) { }
virtual enum Derivation derivation(void) const
{ return DERIVATION_IMPLICIT; }
- virtual void set_derivation(enum Derivation derivation) { }
+ virtual void set_derivation(enum Derivation derivation_arg) { }
bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code,
int cuted_increment);
bool check_int(const char *str, int length, const char *int_end,
@@ -380,7 +380,7 @@ public:
}
/* maximum possible display length */
- virtual uint32 max_length()= 0;
+ virtual uint32 max_display_length()= 0;
virtual uint is_equal(create_field *new_field);
/* convert decimal to longlong with overflow check */
@@ -464,12 +464,12 @@ public:
int store(const char *to,uint length,CHARSET_INFO *cs)=0;
uint size_of() const { return sizeof(*this); }
CHARSET_INFO *charset(void) const { return field_charset; }
- void set_charset(CHARSET_INFO *charset) { field_charset=charset; }
+ void set_charset(CHARSET_INFO *charset_arg) { field_charset= charset_arg; }
enum Derivation derivation(void) const { return field_derivation; }
virtual void set_derivation(enum Derivation derivation_arg)
{ field_derivation= derivation_arg; }
bool binary() const { return field_charset == &my_charset_bin; }
- uint32 max_length() { return field_length; }
+ uint32 max_display_length() { return field_length; }
friend class create_field;
my_decimal *val_decimal(my_decimal *);
virtual bool str_needs_quotes() { return TRUE; }
@@ -484,9 +484,9 @@ class Field_longstr :public Field_str
public:
Field_longstr(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
- const char *field_name_arg, CHARSET_INFO *charset)
+ const char *field_name_arg, CHARSET_INFO *charset_arg)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
- field_name_arg, charset)
+ field_name_arg, charset_arg)
{}
int store_decimal(const my_decimal *d);
@@ -532,7 +532,7 @@ public:
void overflow(bool negative);
bool zero_pack() const { return 0; }
void sql_type(String &str) const;
- uint32 max_length() { return field_length; }
+ uint32 max_display_length() { return field_length; }
};
@@ -574,7 +574,7 @@ public:
void sort_string(char *buff, uint length);
bool zero_pack() const { return 0; }
void sql_type(String &str) const;
- uint32 max_length() { return field_length; }
+ uint32 max_display_length() { return field_length; }
uint size_of() const { return sizeof(*this); }
uint32 pack_length() const { return (uint32) bin_size; }
uint is_equal(create_field *new_field);
@@ -607,7 +607,7 @@ public:
void sort_string(char *buff,uint length);
uint32 pack_length() const { return 1; }
void sql_type(String &str) const;
- uint32 max_length() { return 4; }
+ uint32 max_display_length() { return 4; }
};
@@ -642,7 +642,7 @@ public:
void sort_string(char *buff,uint length);
uint32 pack_length() const { return 2; }
void sql_type(String &str) const;
- uint32 max_length() { return 6; }
+ uint32 max_display_length() { return 6; }
};
@@ -672,7 +672,7 @@ public:
void sort_string(char *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
- uint32 max_length() { return 8; }
+ uint32 max_display_length() { return 8; }
};
@@ -707,7 +707,7 @@ public:
void sort_string(char *buff,uint length);
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
- uint32 max_length() { return 11; }
+ uint32 max_display_length() { return 11; }
};
@@ -749,7 +749,7 @@ public:
uint32 pack_length() const { return 8; }
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
- uint32 max_length() { return 20; }
+ uint32 max_display_length() { return 20; }
};
#endif
@@ -783,24 +783,33 @@ public:
void sort_string(char *buff,uint length);
uint32 pack_length() const { return sizeof(float); }
void sql_type(String &str) const;
- uint32 max_length() { return 24; }
+ uint32 max_display_length() { return 24; }
};
class Field_double :public Field_real {
public:
+ my_bool not_fixed;
Field_double(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
uint8 dec_arg,bool zero_arg,bool unsigned_arg)
:Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg,
- dec_arg, zero_arg, unsigned_arg)
+ dec_arg, zero_arg, unsigned_arg),
+ not_fixed(dec_arg >= NOT_FIXED_DEC)
{}
Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
uint8 dec_arg)
- :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
- NONE, field_name_arg, dec_arg, 0, 0)
+ :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
+ NONE, field_name_arg, dec_arg, 0, 0),
+ not_fixed(dec_arg >= NOT_FIXED_DEC)
+ {}
+ Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
+ uint8 dec_arg, my_bool not_fixed_srg)
+ :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
+ NONE, field_name_arg, dec_arg, 0, 0),
+ not_fixed(not_fixed_srg)
{}
enum_field_types type() const { return MYSQL_TYPE_DOUBLE;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
@@ -816,7 +825,8 @@ public:
void sort_string(char *buff,uint length);
uint32 pack_length() const { return sizeof(double); }
void sql_type(String &str) const;
- uint32 max_length() { return 53; }
+ uint32 max_display_length() { return 53; }
+ uint size_of() const { return sizeof(*this); }
};
@@ -848,7 +858,7 @@ public:
uint32 pack_length() const { return 0; }
void sql_type(String &str) const;
uint size_of() const { return sizeof(*this); }
- uint32 max_length() { return 4; }
+ uint32 max_display_length() { return 4; }
};
@@ -1229,10 +1239,10 @@ public:
packlength= 4;
if (set_packlength)
{
- uint32 char_length= len_arg/cs->mbmaxlen;
- packlength= char_length <= 255 ? 1 :
- char_length <= 65535 ? 2 :
- char_length <= 16777215 ? 3 : 4;
+ uint32 l_char_length= len_arg/cs->mbmaxlen;
+ packlength= l_char_length <= 255 ? 1 :
+ l_char_length <= 65535 ? 2 :
+ l_char_length <= 16777215 ? 3 : 4;
}
}
enum_field_types type() const { return MYSQL_TYPE_BLOB;}
@@ -1312,11 +1322,11 @@ public:
uint max_packed_col_length(uint max_length);
void free() { value.free(); }
inline void clear_temporary() { bzero((char*) &value,sizeof(value)); }
- friend void field_conv(Field *to,Field *from);
+ friend int field_conv(Field *to,Field *from);
uint size_of() const { return sizeof(*this); }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
- uint32 max_length();
+ uint32 max_display_length();
};
@@ -1445,7 +1455,7 @@ public:
enum_field_types type() const { return MYSQL_TYPE_BIT; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; }
uint32 key_length() const { return (uint32) (field_length + 7) / 8; }
- uint32 max_length() { return field_length; }
+ uint32 max_display_length() { return field_length; }
uint size_of() const { return sizeof(*this); }
Item_result result_type () const { return INT_RESULT; }
int reset(void) { bzero(ptr, bytes_in_rec); return 0; }
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 2670de0387b..805aba01754 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -678,7 +678,7 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
/* Simple quick field convert that is called on insert */
-void field_conv(Field *to,Field *from)
+int field_conv(Field *to,Field *from)
{
if (to->real_type() == from->real_type() &&
!(to->type() == MYSQL_TYPE_BLOB && to->table->copy_blobs))
@@ -706,7 +706,7 @@ void field_conv(Field *to,Field *from)
if (to->ptr != from->ptr)
#endif
memcpy(to->ptr,from->ptr,to->pack_length());
- return;
+ return 0;
}
}
if (to->type() == MYSQL_TYPE_BLOB)
@@ -722,8 +722,7 @@ void field_conv(Field *to,Field *from)
from->real_type() != MYSQL_TYPE_STRING &&
from->real_type() != MYSQL_TYPE_VARCHAR))
blob->value.copy();
- blob->store(blob->value.ptr(),blob->value.length(),from->charset());
- return;
+ return blob->store(blob->value.ptr(),blob->value.length(),from->charset());
}
if ((from->result_type() == STRING_RESULT &&
(to->result_type() == STRING_RESULT ||
@@ -740,15 +739,15 @@ void field_conv(Field *to,Field *from)
end with \0. Can be replaced with .ptr() when we have our own
string->double conversion.
*/
- to->store(result.c_ptr_quick(),result.length(),from->charset());
+ return to->store(result.c_ptr_quick(),result.length(),from->charset());
}
else if (from->result_type() == REAL_RESULT)
- to->store(from->val_real());
+ return to->store(from->val_real());
else if (from->result_type() == DECIMAL_RESULT)
{
my_decimal buff;
- to->store_decimal(from->val_decimal(&buff));
+ return to->store_decimal(from->val_decimal(&buff));
}
else
- to->store(from->val_int(), test(from->flags & UNSIGNED_FLAG));
+ return to->store(from->val_int(), test(from->flags & UNSIGNED_FLAG));
}
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 46ef9c9a553..2f9a96472ca 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -104,7 +104,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
uint maxbuffer;
BUFFPEK *buffpek;
ha_rows records= HA_POS_ERROR;
- uchar **sort_keys;
+ uchar **sort_keys= 0;
IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile;
SORTPARAM param;
bool multi_byte_charset;
@@ -434,7 +434,8 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
byte *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
my_off_t record;
TABLE *sort_form;
- volatile THD::killed_state *killed= &current_thd->killed;
+ THD *thd= current_thd;
+ volatile THD::killed_state *killed= &thd->killed;
handler *file;
MY_BITMAP *save_read_set, *save_write_set;
DBUG_ENTER("find_all_keys");
@@ -547,6 +548,9 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
}
else
file->unlock_row();
+ /* It does not make sense to read more keys in case of a fatal error */
+ if (thd->net.report_error)
+ DBUG_RETURN(HA_POS_ERROR);
}
if (quick_select)
{
@@ -886,12 +890,14 @@ static void make_sortkey(register SORTPARAM *param,
}
else
{
- uchar *end= (uchar*) field->pack((char *) to, field->ptr);
#ifdef HAVE_purify
+ uchar *end= (uchar*) field->pack((char *) to, field->ptr);
uint length= (uint) ((to + addonf->length) - end);
DBUG_ASSERT((int) length >= 0);
if (length)
bzero(end, length);
+#else
+ (void) field->pack((char *) to, field->ptr);
#endif
}
to+= addonf->length;
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index 7abdb5f488c..2d78999017a 100644
--- a/sql/gen_lex_hash.cc
+++ b/sql/gen_lex_hash.cc
@@ -445,10 +445,24 @@ int main(int argc,char **argv)
/* Broken up to indicate that it's not advice to you, gentle reader. */
printf("/*\n\n Do " "not " "edit " "this " "file " "directly!\n\n*/\n");
- printf("/* Copyright (C) 2001-2004 MySQL AB\n\
- This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
- and you are welcome to modify and redistribute it under the GPL license\n\
- \n*/\n\n");
+ printf("\
+/* Copyright (C) 2001-2004 MySQL AB\n\
+\n\
+ This program is free software; you can redistribute it and/or modify\n\
+ it under the terms of the GNU General Public License as published by\n\
+ the Free Software Foundation; version 2 of the License.\n\
+\n\
+ This program is distributed in the hope that it will be useful,\n\
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
+ GNU General Public License for more details.\n\
+\n\
+ You should have received a copy of the GNU General Public License\n\
+ along with this program; see the file COPYING. If not, write to the\n\
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston\n\
+ MA 02110-1301 USA. */\n\
+\n\
+");
/* Broken up to indicate that it's not advice to you, gentle reader. */
printf("/* Do " "not " "edit " "this " "file! This is generated by "
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 21697be83aa..872d97a6fa8 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -150,7 +150,6 @@ static byte *ndbcluster_get_key(NDB_SHARE *share,uint *length,
#ifdef HAVE_NDB_BINLOG
static int rename_share(NDB_SHARE *share, const char *new_key);
#endif
-static void ndb_set_fragmentation(NDBTAB &tab, TABLE *table, uint pk_len);
static int ndb_get_table_statistics(ha_ndbcluster*, bool, Ndb*, const NDBTAB *,
struct Ndb_statistics *);
@@ -260,16 +259,16 @@ static int ndb_to_mysql_error(const NdbError *ndberr)
int execute_no_commit_ignore_no_key(ha_ndbcluster *h, NdbTransaction *trans)
{
- int res= trans->execute(NdbTransaction::NoCommit,
- NdbTransaction::AO_IgnoreError,
- h->m_force_send);
- if (res == 0)
- return 0;
+ if (trans->execute(NdbTransaction::NoCommit,
+ NdbOperation::AO_IgnoreError,
+ h->m_force_send) == -1)
+ return -1;
const NdbError &err= trans->getNdbError();
- if (err.classification != NdbError::ConstraintViolation &&
+ if (err.classification != NdbError::NoError &&
+ err.classification != NdbError::ConstraintViolation &&
err.classification != NdbError::NoDataFound)
- return res;
+ return -1;
return 0;
}
@@ -287,7 +286,7 @@ int execute_no_commit(ha_ndbcluster *h, NdbTransaction *trans,
return h->m_ignore_no_key ?
execute_no_commit_ignore_no_key(h,trans) :
trans->execute(NdbTransaction::NoCommit,
- NdbTransaction::AbortOnError,
+ NdbOperation::AbortOnError,
h->m_force_send);
}
@@ -300,7 +299,7 @@ int execute_commit(ha_ndbcluster *h, NdbTransaction *trans)
return 0;
#endif
return trans->execute(NdbTransaction::Commit,
- NdbTransaction::AbortOnError,
+ NdbOperation::AbortOnError,
h->m_force_send);
}
@@ -313,7 +312,7 @@ int execute_commit(THD *thd, NdbTransaction *trans)
return 0;
#endif
return trans->execute(NdbTransaction::Commit,
- NdbTransaction::AbortOnError,
+ NdbOperation::AbortOnError,
thd->variables.ndb_force_send);
}
@@ -328,7 +327,7 @@ int execute_no_commit_ie(ha_ndbcluster *h, NdbTransaction *trans,
#endif
h->release_completed_operations(trans, force_release);
return trans->execute(NdbTransaction::NoCommit,
- NdbTransaction::AO_IgnoreError,
+ NdbOperation::AO_IgnoreError,
h->m_force_send);
}
@@ -443,15 +442,15 @@ ha_rows ha_ndbcluster::records()
{
ha_rows retval;
DBUG_ENTER("ha_ndbcluster::records");
- struct Ndb_local_table_statistics *info= m_table_info;
+ struct Ndb_local_table_statistics *local_info= m_table_info;
DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
((const NDBTAB *)m_table)->getTableId(),
- info->no_uncommitted_rows_count));
+ local_info->no_uncommitted_rows_count));
Ndb *ndb= get_ndb();
ndb->setDatabaseName(m_dbname);
struct Ndb_statistics stat;
- if (ndb_get_table_statistics(this, true, ndb, m_table, &stat) == 0)
+ if (ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat) == 0)
{
retval= stat.row_count;
}
@@ -462,9 +461,9 @@ ha_rows ha_ndbcluster::records()
THD *thd= current_thd;
if (get_thd_ndb(thd)->error)
- info->no_uncommitted_rows_count= 0;
+ local_info->no_uncommitted_rows_count= 0;
- DBUG_RETURN(retval + info->no_uncommitted_rows_count);
+ DBUG_RETURN(retval + local_info->no_uncommitted_rows_count);
}
int ha_ndbcluster::records_update()
@@ -474,30 +473,29 @@ int ha_ndbcluster::records_update()
DBUG_ENTER("ha_ndbcluster::records_update");
int result= 0;
- struct Ndb_local_table_statistics *info= m_table_info;
+ struct Ndb_local_table_statistics *local_info= m_table_info;
DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
((const NDBTAB *)m_table)->getTableId(),
- info->no_uncommitted_rows_count));
- // if (info->records == ~(ha_rows)0)
+ local_info->no_uncommitted_rows_count));
{
Ndb *ndb= get_ndb();
struct Ndb_statistics stat;
ndb->setDatabaseName(m_dbname);
- result= ndb_get_table_statistics(this, true, ndb, m_table, &stat);
+ result= ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat);
if (result == 0)
{
stats.mean_rec_length= stat.row_size;
stats.data_file_length= stat.fragment_memory;
- info->records= stat.row_count;
+ local_info->records= stat.row_count;
}
}
{
THD *thd= current_thd;
if (get_thd_ndb(thd)->error)
- info->no_uncommitted_rows_count= 0;
+ local_info->no_uncommitted_rows_count= 0;
}
- if(result==0)
- stats.records= info->records+ info->no_uncommitted_rows_count;
+ if (result == 0)
+ stats.records= local_info->records+ local_info->no_uncommitted_rows_count;
DBUG_RETURN(result);
}
@@ -515,11 +513,11 @@ void ha_ndbcluster::no_uncommitted_rows_update(int c)
if (m_ha_not_exact_count)
return;
DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_update");
- struct Ndb_local_table_statistics *info= m_table_info;
- info->no_uncommitted_rows_count+= c;
+ struct Ndb_local_table_statistics *local_info= m_table_info;
+ local_info->no_uncommitted_rows_count+= c;
DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
((const NDBTAB *)m_table)->getTableId(),
- info->no_uncommitted_rows_count));
+ local_info->no_uncommitted_rows_count));
DBUG_VOID_RETURN;
}
@@ -956,7 +954,6 @@ int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op)
bool ha_ndbcluster::uses_blob_value()
{
- uint blob_fields;
MY_BITMAP *bitmap;
uint *blob_index, *blob_index_end;
if (table_share->blob_fields == 0)
@@ -1106,7 +1103,6 @@ int ha_ndbcluster::create_indexes(Ndb *ndb, TABLE *tab)
const char *index_name;
KEY* key_info= tab->key_info;
const char **key_name= tab->s->keynames.type_names;
- NDBDICT *dict= ndb->getDictionary();
DBUG_ENTER("ha_ndbcluster::create_indexes");
for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
@@ -1244,7 +1240,6 @@ int ha_ndbcluster::open_indexes(Ndb *ndb, TABLE *tab, bool ignore_error)
int error= 0;
THD *thd=current_thd;
NDBDICT *dict= ndb->getDictionary();
- const char *index_name;
KEY* key_info= tab->key_info;
const char **key_name= tab->s->keynames.type_names;
DBUG_ENTER("ha_ndbcluster::open_indexes");
@@ -1256,9 +1251,9 @@ int ha_ndbcluster::open_indexes(Ndb *ndb, TABLE *tab, bool ignore_error)
m_index[i].index= m_index[i].unique_index= NULL;
else
break;
- m_index[i].null_in_unique_index= false;
+ m_index[i].null_in_unique_index= FALSE;
if (check_index_fields_not_null(key_info))
- m_index[i].null_in_unique_index= true;
+ m_index[i].null_in_unique_index= TRUE;
}
if (error && !ignore_error)
@@ -1294,7 +1289,6 @@ void ha_ndbcluster::renumber_indexes(Ndb *ndb, TABLE *tab)
const char *index_name;
KEY* key_info= tab->key_info;
const char **key_name= tab->s->keynames.type_names;
- NDBDICT *dict= ndb->getDictionary();
DBUG_ENTER("ha_ndbcluster::renumber_indexes");
for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
@@ -1411,10 +1405,10 @@ bool ha_ndbcluster::check_index_fields_not_null(KEY* key_info)
{
Field* field= key_part->field;
if (field->maybe_null())
- DBUG_RETURN(true);
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN(false);
+ DBUG_RETURN(FALSE);
}
void ha_ndbcluster::release_metadata(THD *thd, Ndb *ndb)
@@ -1732,7 +1726,8 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf,
ERR_RETURN(trans->getNdbError());
}
- if (execute_no_commit_ie(this,trans,false) != 0)
+ if ((res = execute_no_commit_ie(this,trans,FALSE)) != 0 ||
+ op->getNdbError().code)
{
table->status= STATUS_NOT_FOUND;
DBUG_RETURN(ndb_err(trans));
@@ -1797,7 +1792,7 @@ int ha_ndbcluster::complemented_read(const byte *old_data, byte *new_data,
}
}
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
{
table->status= STATUS_NOT_FOUND;
DBUG_RETURN(ndb_err(trans));
@@ -1843,7 +1838,7 @@ bool ha_ndbcluster::check_all_operations_for_error(NdbTransaction *trans,
if (err.status != NdbError::Success)
{
if (ndb_to_mysql_error(&err) != (int) errcode)
- DBUG_RETURN(false);
+ DBUG_RETURN(FALSE);
if (op == last) break;
op= trans->getNextCompletedOperation(op);
}
@@ -1874,10 +1869,10 @@ bool ha_ndbcluster::check_all_operations_for_error(NdbTransaction *trans,
if (errcode == HA_ERR_KEY_NOT_FOUND)
m_dupkey= table->s->primary_key;
}
- DBUG_RETURN(false);
+ DBUG_RETURN(FALSE);
}
}
- DBUG_RETURN(true);
+ DBUG_RETURN(TRUE);
}
@@ -1955,7 +1950,7 @@ int ha_ndbcluster::peek_indexed_rows(const byte *record,
}
last= trans->getLastDefinedOperation();
if (first)
- res= execute_no_commit_ie(this,trans,false);
+ res= execute_no_commit_ie(this,trans,FALSE);
else
{
// Table has no keys
@@ -2004,7 +1999,8 @@ int ha_ndbcluster::unique_index_read(const byte *key,
if ((res= define_read_attrs(buf, op)))
DBUG_RETURN(res);
- if (execute_no_commit_ie(this,trans,false) != 0)
+ if (execute_no_commit_ie(this,trans,FALSE) != 0 ||
+ op->getNdbError().code)
{
table->status= STATUS_NOT_FOUND;
DBUG_RETURN(ndb_err(trans));
@@ -2018,7 +2014,7 @@ int ha_ndbcluster::unique_index_read(const byte *key,
inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
{
DBUG_ENTER("fetch_next");
- int check;
+ int local_check;
NdbTransaction *trans= m_active_trans;
if (m_lock_tuple)
@@ -2029,19 +2025,21 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
LOCK WITH SHARE MODE) and row was not explictly unlocked
with unlock_row() call
*/
- NdbConnection *trans= m_active_trans;
+ NdbConnection *con_trans= m_active_trans;
NdbOperation *op;
// Lock row
DBUG_PRINT("info", ("Keeping lock on scanned row"));
if (!(op= m_active_cursor->lockCurrentTuple()))
{
- m_lock_tuple= false;
- ERR_RETURN(trans->getNdbError());
+ /* purecov: begin inspected */
+ m_lock_tuple= FALSE;
+ ERR_RETURN(con_trans->getNdbError());
+ /* purecov: end */
}
m_ops_pending++;
}
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
bool contact_ndb= m_lock.type < TL_WRITE_ALLOW_WRITE &&
m_lock.type != TL_READ_WITH_SHARED_LOCKS;;
@@ -2052,13 +2050,13 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
*/
if (m_ops_pending && m_blobs_pending)
{
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
DBUG_RETURN(ndb_err(trans));
m_ops_pending= 0;
m_blobs_pending= FALSE;
}
- if ((check= cursor->nextResult(contact_ndb, m_force_send)) == 0)
+ if ((local_check= cursor->nextResult(contact_ndb, m_force_send)) == 0)
{
/*
Explicitly lock tuple if "select for update" or
@@ -2069,7 +2067,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
m_lock.type == TL_READ_WITH_SHARED_LOCKS);
DBUG_RETURN(0);
}
- else if (check == 1 || check == 2)
+ else if (local_check == 1 || local_check == 2)
{
// 1: No more records
// 2: No more cached records
@@ -2084,7 +2082,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
{
if (m_transaction_on)
{
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
DBUG_RETURN(-1);
}
else
@@ -2099,13 +2097,13 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
}
m_ops_pending= 0;
}
- contact_ndb= (check == 2);
+ contact_ndb= (local_check == 2);
}
else
{
DBUG_RETURN(-1);
}
- } while (check == 2);
+ } while (local_check == 2);
DBUG_RETURN(1);
}
@@ -2282,8 +2280,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
DBUG_PRINT("error", ("key %d unknown flag %d", j, p.key->flag));
DBUG_ASSERT(FALSE);
// Stop setting bounds but continue with what we have
- op->end_of_bound(range_no);
- DBUG_RETURN(0);
+ DBUG_RETURN(op->end_of_bound(range_no));
}
}
}
@@ -2330,8 +2327,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
tot_len+= part_store_len;
}
- op->end_of_bound(range_no);
- DBUG_RETURN(0);
+ DBUG_RETURN(op->end_of_bound(range_no));
}
/*
@@ -2365,7 +2361,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
bool need_pk = (lm == NdbOperation::LM_Read);
if (!(op= trans->getNdbIndexScanOperation(m_index[active_index].index,
m_table)) ||
- op->readTuples(lm, 0, parallelism, sorted, descending, false, need_pk))
+ op->readTuples(lm, 0, parallelism, sorted, descending, FALSE, need_pk))
ERR_RETURN(trans->getNdbError());
if (m_use_partition_function && part_spec != NULL &&
part_spec->start_part == part_spec->end_part)
@@ -2387,7 +2383,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
{
const key_range *keys[2]= { start_key, end_key };
- res= set_bounds(op, active_index, false, keys);
+ res= set_bounds(op, active_index, FALSE, keys);
if (res)
DBUG_RETURN(res);
}
@@ -2411,7 +2407,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
ERR_RETURN(trans->getNdbError());
}
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
DBUG_RETURN(ndb_err(trans));
DBUG_RETURN(next_result(buf));
@@ -2506,7 +2502,7 @@ int ha_ndbcluster::unique_index_scan(const KEY* key_info,
if ((res= define_read_attrs(buf, op)))
DBUG_RETURN(res);
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
DBUG_RETURN(ndb_err(trans));
DBUG_PRINT("exit", ("Scan started successfully"));
DBUG_RETURN(next_result(buf));
@@ -2575,7 +2571,7 @@ int ha_ndbcluster::full_table_scan(byte *buf)
if ((res= define_read_attrs(buf, op)))
DBUG_RETURN(res);
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
DBUG_RETURN(ndb_err(trans));
DBUG_PRINT("exit", ("Scan started successfully"));
DBUG_RETURN(next_result(buf));
@@ -2591,7 +2587,7 @@ int ha_ndbcluster::write_row(byte *record)
NdbTransaction *trans= m_active_trans;
NdbOperation *op;
int res;
- THD *thd= current_thd;
+ THD *thd= table->in_use;
longlong func_value= 0;
DBUG_ENTER("ha_ndbcluster::write_row");
@@ -2604,7 +2600,6 @@ int ha_ndbcluster::write_row(byte *record)
*/
if (has_auto_increment)
{
- THD *thd= table->in_use;
int error;
m_skip_auto_increment= FALSE;
@@ -2624,7 +2619,7 @@ int ha_ndbcluster::write_row(byte *record)
start_bulk_insert will set parameters to ensure that each
write_row is committed individually
*/
- int peek_res= peek_indexed_rows(record, true);
+ int peek_res= peek_indexed_rows(record, TRUE);
if (!peek_res)
{
@@ -2743,7 +2738,7 @@ int ha_ndbcluster::write_row(byte *record)
m_bulk_insert_not_flushed= FALSE;
if (m_transaction_on)
{
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
{
m_skip_auto_increment= TRUE;
no_uncommitted_rows_execute_failure();
@@ -2769,10 +2764,12 @@ int ha_ndbcluster::write_row(byte *record)
{
Ndb *ndb= get_ndb();
Uint64 next_val= (Uint64) table->next_number_field->val_int() + 1;
+#ifndef DBUG_OFF
char buff[22];
DBUG_PRINT("info",
("Trying to set next auto increment value to %s",
llstr(next_val, buff)));
+#endif
Ndb_tuple_id_range_guard g(m_share);
if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE)
== -1)
@@ -2825,7 +2822,7 @@ int ha_ndbcluster::key_cmp(uint keynr, const byte * old_row,
int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
{
- THD *thd= current_thd;
+ THD *thd= table->in_use;
NdbTransaction *trans= m_active_trans;
NdbScanOperation* cursor= m_active_cursor;
NdbOperation *op;
@@ -2934,7 +2931,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
DBUG_PRINT("info", ("Calling updateTuple on cursor"));
if (!(op= cursor->updateCurrentTuple()))
ERR_RETURN(trans->getNdbError());
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
m_ops_pending++;
if (uses_blob_value())
m_blobs_pending= TRUE;
@@ -2997,7 +2994,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
op->setValue(no_fields, part_func_value);
}
// Execute update operation
- if (!cursor && execute_no_commit(this,trans,false) != 0) {
+ if (!cursor && execute_no_commit(this,trans,FALSE) != 0) {
no_uncommitted_rows_execute_failure();
DBUG_RETURN(ndb_err(trans));
}
@@ -3012,7 +3009,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
int ha_ndbcluster::delete_row(const byte *record)
{
- THD *thd= current_thd;
+ THD *thd= table->in_use;
NdbTransaction *trans= m_active_trans;
NdbScanOperation* cursor= m_active_cursor;
NdbOperation *op;
@@ -3043,7 +3040,7 @@ int ha_ndbcluster::delete_row(const byte *record)
DBUG_PRINT("info", ("Calling deleteTuple on cursor"));
if (cursor->deleteCurrentTuple() != 0)
ERR_RETURN(trans->getNdbError());
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
m_ops_pending++;
if (m_use_partition_function)
@@ -3083,7 +3080,7 @@ int ha_ndbcluster::delete_row(const byte *record)
}
// Execute delete operation
- if (execute_no_commit(this,trans,false) != 0) {
+ if (execute_no_commit(this,trans,FALSE) != 0) {
no_uncommitted_rows_execute_failure();
DBUG_RETURN(ndb_err(trans));
}
@@ -3311,8 +3308,7 @@ int ha_ndbcluster::index_init(uint index, bool sorted)
unless m_lock.type == TL_READ_HIGH_PRIORITY
and no sub-sequent call to unlock_row()
*/
- m_lock_tuple= false;
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
DBUG_RETURN(0);
}
@@ -3334,7 +3330,6 @@ check_null_in_key(const KEY* key_info, const byte *key, uint key_len)
const byte* end_ptr= key + key_len;
curr_part= key_info->key_part;
end_part= curr_part + key_info->key_parts;
-
for (; curr_part != end_part && key < end_ptr; curr_part++)
{
@@ -3572,12 +3567,12 @@ int ha_ndbcluster::close_scan()
if (!(op= cursor->lockCurrentTuple()))
{
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
ERR_RETURN(trans->getNdbError());
}
m_ops_pending++;
}
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
if (m_ops_pending)
{
/*
@@ -3585,7 +3580,7 @@ int ha_ndbcluster::close_scan()
deleteing/updating transaction before closing the scan
*/
DBUG_PRINT("info", ("ops_pending: %ld", (long) m_ops_pending));
- if (execute_no_commit(this,trans,false) != 0) {
+ if (execute_no_commit(this,trans,FALSE) != 0) {
no_uncommitted_rows_execute_failure();
DBUG_RETURN(ndb_err(trans));
}
@@ -3790,7 +3785,7 @@ int ha_ndbcluster::info(uint flag)
struct Ndb_statistics stat;
ndb->setDatabaseName(m_dbname);
if (current_thd->variables.ndb_use_exact_count &&
- (result= ndb_get_table_statistics(this, true, ndb, m_table, &stat))
+ (result= ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat))
== 0)
{
stats.mean_rec_length= stat.row_size;
@@ -3817,7 +3812,7 @@ int ha_ndbcluster::info(uint flag)
if (flag & HA_STATUS_AUTO)
{
DBUG_PRINT("info", ("HA_STATUS_AUTO"));
- if (m_table)
+ if (m_table && table->found_next_number_field)
{
Ndb *ndb= get_ndb();
Ndb_tuple_id_range_guard g(m_share);
@@ -3991,7 +3986,7 @@ int ha_ndbcluster::end_bulk_insert()
m_bulk_insert_not_flushed= FALSE;
if (m_transaction_on)
{
- if (execute_no_commit(this, trans,false) != 0)
+ if (execute_no_commit(this, trans,FALSE) != 0)
{
no_uncommitted_rows_execute_failure();
my_errno= error= ndb_err(trans);
@@ -4006,7 +4001,7 @@ int ha_ndbcluster::end_bulk_insert()
}
else
{
- int res= trans->restart();
+ IF_DBUG(int res=) trans->restart();
DBUG_ASSERT(res == 0);
}
}
@@ -4316,7 +4311,7 @@ void ha_ndbcluster::unlock_row()
DBUG_ENTER("unlock_row");
DBUG_PRINT("info", ("Unlocking row"));
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
DBUG_VOID_RETURN;
}
@@ -4344,11 +4339,10 @@ int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type)
ERR_RETURN(ndb->getNdbError());
no_uncommitted_rows_reset(thd);
thd_ndb->stmt= trans;
+ thd_ndb->query_state&= NDB_QUERY_NORMAL;
trans_register_ha(thd, FALSE, ndbcluster_hton);
}
- thd_ndb->query_state&= NDB_QUERY_NORMAL;
m_active_trans= trans;
-
// Start of statement
m_ops_pending= 0;
thd->set_current_stmt_binlog_row_based_if_mixed();
@@ -4725,7 +4719,9 @@ static int create_ndb_column(NDBCOL &col,
// Set autoincrement
if (field->flags & AUTO_INCREMENT_FLAG)
{
+#ifndef DBUG_OFF
char buff[22];
+#endif
col.setAutoIncrement(TRUE);
ulonglong value= info->auto_increment_value ?
info->auto_increment_value : (ulonglong) 1;
@@ -4743,14 +4739,14 @@ static int create_ndb_column(NDBCOL &col,
int ha_ndbcluster::create(const char *name,
TABLE *form,
- HA_CREATE_INFO *info)
+ HA_CREATE_INFO *create_info)
{
THD *thd= current_thd;
NDBTAB tab;
NDBCOL col;
uint pack_length, length, i, pk_length= 0;
const void *data, *pack_data;
- bool create_from_engine= (info->table_options & HA_OPTION_CREATE_FROM_ENGINE);
+ bool create_from_engine= (create_info->table_options & HA_OPTION_CREATE_FROM_ENGINE);
bool is_truncate= (thd->lex->sql_command == SQLCOM_TRUNCATE);
char tablespace[FN_LEN];
@@ -4774,7 +4770,7 @@ int ha_ndbcluster::create(const char *name,
if (!(m_table= ndbtab_g.get_table()))
ERR_RETURN(dict->getNdbError());
if ((get_tablespace_name(thd, tablespace, FN_LEN)))
- info->tablespace= tablespace;
+ create_info->tablespace= tablespace;
m_table= NULL;
}
DBUG_PRINT("info", ("Dropping and re-creating table for TRUNCATE"));
@@ -4815,7 +4811,7 @@ int ha_ndbcluster::create(const char *name,
DBUG_PRINT("table", ("name: %s", m_tabname));
tab.setName(m_tabname);
- tab.setLogging(!(info->options & HA_LEX_CREATE_TMP_TABLE));
+ tab.setLogging(!(create_info->options & HA_LEX_CREATE_TMP_TABLE));
// Save frm data for this table
if (readfrm(name, &data, &length))
@@ -4836,10 +4832,10 @@ int ha_ndbcluster::create(const char *name,
DBUG_PRINT("info", ("name: %s, type: %u, pack_length: %d",
field->field_name, field->real_type(),
field->pack_length()));
- if ((my_errno= create_ndb_column(col, field, info)))
+ if ((my_errno= create_ndb_column(col, field, create_info)))
DBUG_RETURN(my_errno);
- if (info->storage_media == HA_SM_DISK)
+ if (create_info->storage_media == HA_SM_DISK)
col.setStorageType(NdbDictionary::Column::StorageTypeDisk);
else
col.setStorageType(NdbDictionary::Column::StorageTypeMemory);
@@ -4859,16 +4855,16 @@ int ha_ndbcluster::create(const char *name,
NdbDictionary::Column::StorageTypeMemory);
}
- if (info->storage_media == HA_SM_DISK)
+ if (create_info->storage_media == HA_SM_DISK)
{
- if (info->tablespace)
- tab.setTablespaceName(info->tablespace);
+ if (create_info->tablespace)
+ tab.setTablespaceName(create_info->tablespace);
else
tab.setTablespaceName("DEFAULT-TS");
}
- else if (info->tablespace)
+ else if (create_info->tablespace)
{
- if (info->storage_media == HA_SM_MEMORY)
+ if (create_info->storage_media == HA_SM_MEMORY)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_ILLEGAL_HA_CREATE_OPTION,
@@ -4878,8 +4874,8 @@ int ha_ndbcluster::create(const char *name,
"STORAGE DISK");
DBUG_RETURN(HA_ERR_UNSUPPORTED);
}
- tab.setTablespaceName(info->tablespace);
- info->storage_media = HA_SM_DISK; //if use tablespace, that also means store on disk
+ tab.setTablespaceName(create_info->tablespace);
+ create_info->storage_media = HA_SM_DISK; //if use tablespace, that also means store on disk
}
// No primary key, create shadow key as 64 bit, auto increment
@@ -4910,13 +4906,13 @@ int ha_ndbcluster::create(const char *name,
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
{
- NdbDictionary::Column * col= tab.getColumn(i);
- int size= pk_length + (col->getPartSize()+3)/4 + 7;
+ NdbDictionary::Column * column= tab.getColumn(i);
+ int size= pk_length + (column->getPartSize()+3)/4 + 7;
if (size > NDB_MAX_TUPLE_SIZE_IN_WORDS &&
(pk_length+7) < NDB_MAX_TUPLE_SIZE_IN_WORDS)
{
size= NDB_MAX_TUPLE_SIZE_IN_WORDS - pk_length - 7;
- col->setPartSize(4*size);
+ column->setPartSize(4*size);
}
/**
* If size > NDB_MAX and pk_length+7 >= NDB_MAX
@@ -5009,11 +5005,17 @@ int ha_ndbcluster::create(const char *name,
get a new share
*/
- if (!(share= get_share(name, form, true, true)))
+ /* ndb_share reference create */
+ if (!(share= get_share(name, form, TRUE, TRUE)))
{
sql_print_error("NDB: allocating table share for %s failed", name);
/* my_errno is set */
}
+ else
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s binlog create use_count: %u",
+ share->key, share->use_count));
+ }
pthread_mutex_unlock(&ndbcluster_mutex);
while (!IS_TMP_PREFIX(m_tabname))
@@ -5037,7 +5039,7 @@ int ha_ndbcluster::create(const char *name,
if (ndb_extra_logging)
sql_print_information("NDB Binlog: CREATE TABLE Event: %s",
event_name.c_ptr());
- if (share && do_event_op &&
+ if (share &&
ndbcluster_create_event_ops(share, m_table, event_name.c_ptr()))
{
sql_print_error("NDB Binlog: FAILED CREATE TABLE event operations."
@@ -5071,10 +5073,8 @@ int ha_ndbcluster::create(const char *name,
int ha_ndbcluster::create_handler_files(const char *file,
const char *old_name,
int action_flag,
- HA_CREATE_INFO *info)
+ HA_CREATE_INFO *create_info)
{
- char path[FN_REFLEN];
- const char *name;
Ndb* ndb;
const NDBTAB *tab;
const void *data, *pack_data;
@@ -5092,7 +5092,7 @@ int ha_ndbcluster::create_handler_files(const char *file,
DBUG_RETURN(HA_ERR_NO_CONNECTION);
NDBDICT *dict= ndb->getDictionary();
- if (!info->frm_only)
+ if (!create_info->frm_only)
DBUG_RETURN(0); // Must be a create, ignore since frm is saved in create
// TODO handle this
@@ -5129,6 +5129,9 @@ int ha_ndbcluster::create_handler_files(const char *file,
}
set_ndb_share_state(m_share, NSS_INITIAL);
+ /* ndb_share reference schema(?) free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog schema(?) free use_count: %u",
+ m_share->key, m_share->use_count));
free_share(&m_share); // Decrease ref_count
DBUG_RETURN(error);
@@ -5255,7 +5258,10 @@ int ha_ndbcluster::create_ndb_index(const char *name,
*/
void ha_ndbcluster::prepare_for_alter()
{
+ /* ndb_share reference schema */
ndbcluster_get_share(m_share); // Increase ref_count
+ DBUG_PRINT("NDB_SHARE", ("%s binlog schema use_count: %u",
+ m_share->key, m_share->use_count));
set_ndb_share_state(m_share, NSS_ALTERED);
}
@@ -5289,6 +5295,9 @@ int ha_ndbcluster::add_index(TABLE *table_arg,
if (error)
{
set_ndb_share_state(m_share, NSS_INITIAL);
+ /* ndb_share reference schema free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog schema free use_count: %u",
+ m_share->key, m_share->use_count));
free_share(&m_share); // Decrease ref_count
}
DBUG_RETURN(error);
@@ -5333,6 +5342,9 @@ int ha_ndbcluster::final_drop_index(TABLE *table_arg)
if((error= drop_indexes(ndb, table_arg)))
{
m_share->state= NSS_INITIAL;
+ /* ndb_share reference schema free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog schema free use_count: %u",
+ m_share->key, m_share->use_count));
free_share(&m_share); // Decrease ref_count
}
DBUG_RETURN(error);
@@ -5374,10 +5386,13 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
int ndb_table_id= orig_tab->getObjectId();
int ndb_table_version= orig_tab->getObjectVersion();
- NDB_SHARE *share= get_share(from, 0, false);
+ /* ndb_share reference temporary */
+ NDB_SHARE *share= get_share(from, 0, FALSE);
if (share)
{
- int r= rename_share(share, to);
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
+ IF_DBUG(int r=) rename_share(share, to);
DBUG_ASSERT(r == 0);
}
#endif
@@ -5398,8 +5413,11 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
#ifdef HAVE_NDB_BINLOG
if (share)
{
- int r= rename_share(share, from);
- DBUG_ASSERT(r == 0);
+ IF_DBUG(int ret=) rename_share(share, from);
+ DBUG_ASSERT(ret == 0);
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
}
#endif
@@ -5412,7 +5430,12 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
// ToDo in 4.1 should rollback alter table...
#ifdef HAVE_NDB_BINLOG
if (share)
+ {
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
free_share(&share);
+ }
#endif
DBUG_RETURN(result);
}
@@ -5446,7 +5469,7 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
if (ndb_extra_logging)
sql_print_information("NDB Binlog: RENAME Event: %s",
event_name.c_ptr());
- if (share && ndb_binlog_running &&
+ if (share &&
ndbcluster_create_event_ops(share, ndbtab, event_name.c_ptr()))
{
sql_print_error("NDB Binlog: FAILED create event operations "
@@ -5493,7 +5516,12 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
}
}
if (share)
+ {
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
+ }
#endif
DBUG_RETURN(result);
@@ -5528,7 +5556,13 @@ ha_ndbcluster::delete_table(ha_ndbcluster *h, Ndb *ndb,
DBUG_PRINT("info", ("Schema distribution table not setup"));
DBUG_RETURN(HA_ERR_NO_CONNECTION);
}
- NDB_SHARE *share= get_share(path, 0, false);
+ /* ndb_share reference temporary */
+ NDB_SHARE *share= get_share(path, 0, FALSE);
+ if (share)
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
+ }
#endif
/* Drop the table from NDB */
@@ -5608,9 +5642,14 @@ retry_temporary_error1:
The share kept by the server has not been freed, free it
*/
share->state= NSS_DROPPED;
+ /* ndb_share reference create free */
+ DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
+ share->key, share->use_count));
free_share(&share, TRUE);
}
- /* free the share taken above */
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share, TRUE);
pthread_mutex_unlock(&ndbcluster_mutex);
}
@@ -5660,9 +5699,14 @@ retry_temporary_error1:
The share kept by the server has not been freed, free it
*/
share->state= NSS_DROPPED;
+ /* ndb_share reference create free */
+ DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
+ share->key, share->use_count));
free_share(&share, TRUE);
}
- /* free the share taken above */
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share, TRUE);
pthread_mutex_unlock(&ndbcluster_mutex);
}
@@ -5838,6 +5882,9 @@ ha_ndbcluster::~ha_ndbcluster()
if (m_share)
{
+ /* ndb_share reference handler free */
+ DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u",
+ m_share->key, m_share->use_count));
free_share(&m_share);
}
release_metadata(thd, ndb);
@@ -5900,14 +5947,21 @@ int ha_ndbcluster::open(const char *name, int mode, uint test_if_locked)
DBUG_PRINT("info", ("ref_length: %d", ref_length));
// Init table lock structure
+ /* ndb_share reference handler */
if (!(m_share=get_share(name, table)))
DBUG_RETURN(1);
+ DBUG_PRINT("NDB_SHARE", ("%s handler use_count: %u",
+ m_share->key, m_share->use_count));
thr_lock_data_init(&m_share->lock,&m_lock,(void*) 0);
set_dbname(name);
set_tabname(name);
- if (check_ndb_connection()) {
+ if (check_ndb_connection())
+ {
+ /* ndb_share reference handler free */
+ DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u",
+ m_share->key, m_share->use_count));
free_share(&m_share);
m_share= 0;
DBUG_RETURN(HA_ERR_NO_CONNECTION);
@@ -5919,7 +5973,7 @@ int ha_ndbcluster::open(const char *name, int mode, uint test_if_locked)
Ndb *ndb= get_ndb();
ndb->setDatabaseName(m_dbname);
struct Ndb_statistics stat;
- res= ndb_get_table_statistics(NULL, false, ndb, m_table, &stat);
+ res= ndb_get_table_statistics(NULL, FALSE, ndb, m_table, &stat);
stats.mean_rec_length= stat.row_size;
stats.data_file_length= stat.fragment_memory;
stats.records= stat.row_count;
@@ -5966,8 +6020,11 @@ void ha_ndbcluster::set_part_info(partition_info *part_info)
int ha_ndbcluster::close(void)
{
DBUG_ENTER("close");
- THD *thd= current_thd;
+ THD *thd= table->in_use;
Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb;
+ /* ndb_share reference handler free */
+ DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u",
+ m_share->key, m_share->use_count));
free_share(&m_share);
m_share= 0;
release_metadata(thd, ndb);
@@ -6074,7 +6131,13 @@ int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
ndb->setDatabaseName(db);
NDBDICT* dict= ndb->getDictionary();
build_table_filename(key, sizeof(key), db, name, "", 0);
- NDB_SHARE *share= get_share(key, 0, false);
+ /* ndb_share reference temporary */
+ NDB_SHARE *share= get_share(key, 0, FALSE);
+ if (share)
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
+ }
if (share && get_ndb_share_state(share) == NSS_ALTERED)
{
// Frm has been altered on disk, but not yet written to ndb
@@ -6120,12 +6183,22 @@ int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
*frmblob= data;
if (share)
+ {
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
+ }
DBUG_RETURN(0);
err:
if (share)
+ {
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
+ }
if (ndb_error.code)
{
ERR_RETURN(ndb_error);
@@ -6241,7 +6314,6 @@ int ndbcluster_drop_database_impl(const char *path)
static void ndbcluster_drop_database(handlerton *hton, char *path)
{
- THD *thd= current_thd;
DBUG_ENTER("ndbcluster_drop_database");
#ifdef HAVE_NDB_BINLOG
/*
@@ -6258,6 +6330,7 @@ static void ndbcluster_drop_database(handlerton *hton, char *path)
ndbcluster_drop_database_impl(path);
#ifdef HAVE_NDB_BINLOG
char db[FN_REFLEN];
+ THD *thd= current_thd;
ha_ndbcluster::set_dbname(path, db);
ndbcluster_log_schema_op(thd, 0,
thd->query, thd->query_length,
@@ -6283,16 +6356,17 @@ int ndb_create_table_from_engine(THD *thd, const char *db,
*/
int ndbcluster_find_all_files(THD *thd)
{
- DBUG_ENTER("ndbcluster_find_all_files");
Ndb* ndb;
char key[FN_REFLEN];
+ NDBDICT *dict;
+ int unhandled, retries= 5, skipped;
+ DBUG_ENTER("ndbcluster_find_all_files");
if (!(ndb= check_ndb_in_thd(thd)))
DBUG_RETURN(HA_ERR_NO_CONNECTION);
- NDBDICT *dict= ndb->getDictionary();
+ dict= ndb->getDictionary();
- int unhandled, retries= 5, skipped;
LINT_INIT(unhandled);
LINT_INIT(skipped);
do
@@ -6362,7 +6436,13 @@ int ndbcluster_find_all_files(THD *thd)
}
else if (cmp_frm(ndbtab, pack_data, pack_length))
{
- NDB_SHARE *share= get_share(key, 0, false);
+ /* ndb_share reference temporary */
+ NDB_SHARE *share= get_share(key, 0, FALSE);
+ if (share)
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
+ }
if (!share || get_ndb_share_state(share) != NSS_ALTERED)
{
discover= 1;
@@ -6370,7 +6450,12 @@ int ndbcluster_find_all_files(THD *thd)
elmt.database, elmt.name);
}
if (share)
+ {
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
+ }
}
my_free((char*) data, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) pack_data, MYF(MY_ALLOW_ZERO_PTR));
@@ -6476,12 +6561,12 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
List<char> delete_list;
while ((file_name=it++))
{
- bool file_on_disk= false;
+ bool file_on_disk= FALSE;
DBUG_PRINT("info", ("%s", file_name));
if (hash_search(&ndb_tables, file_name, strlen(file_name)))
{
DBUG_PRINT("info", ("%s existed in NDB _and_ on disk ", file_name));
- file_on_disk= true;
+ file_on_disk= TRUE;
}
// Check for .ndb file with this name
@@ -6837,7 +6922,7 @@ static int ndbcluster_end(handlerton *hton, ha_panic_function type)
fprintf(stderr, "NDB: table share %s with use_count %d not freed\n",
share->key, share->use_count);
#endif
- real_free_share(&share);
+ ndbcluster_real_free_share(&share);
}
pthread_mutex_unlock(&ndbcluster_mutex);
}
@@ -7034,19 +7119,19 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key,
{
// We must provide approx table rows
Uint64 table_rows=0;
- Ndb_local_table_statistics *info= m_table_info;
- if (info->records != ~(ha_rows)0 && info->records != 0)
+ Ndb_local_table_statistics *ndb_info= m_table_info;
+ if (ndb_info->records != ~(ha_rows)0 && ndb_info->records != 0)
{
- table_rows = info->records;
- DBUG_PRINT("info", ("use info->records: %llu", table_rows));
+ table_rows = ndb_info->records;
+ DBUG_PRINT("info", ("use info->records: %lu", (ulong) table_rows));
}
else
{
Ndb_statistics stat;
- if ((res=ndb_get_table_statistics(this, true, ndb, m_table, &stat)) != 0)
+ if ((res=ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat)))
break;
table_rows=stat.row_count;
- DBUG_PRINT("info", ("use db row_count: %llu", table_rows));
+ DBUG_PRINT("info", ("use db row_count: %lu", (ulong) table_rows));
if (table_rows == 0) {
// Problem if autocommit=0
#ifdef ndb_get_table_statistics_uses_active_trans
@@ -7069,7 +7154,7 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key,
if ((op->readTuples(NdbOperation::LM_CommittedRead)) == -1)
ERR_BREAK(op->getNdbError(), res);
const key_range *keys[2]={ min_key, max_key };
- if ((res=set_bounds(op, inx, true, keys)) != 0)
+ if ((res=set_bounds(op, inx, TRUE, keys)) != 0)
break;
// Decide if db should be contacted
@@ -7175,7 +7260,10 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
DBUG_PRINT("info", ("Table %s not found in ndbcluster_open_tables", name));
DBUG_RETURN(1);
}
+ /* ndb_share reference temporary, free below */
share->use_count++;
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
pthread_mutex_unlock(&ndbcluster_mutex);
pthread_mutex_lock(&share->mutex);
@@ -7184,10 +7272,15 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
if (share->commit_count != 0)
{
*commit_count= share->commit_count;
+#ifndef DBUG_OFF
char buff[22];
+#endif
DBUG_PRINT("info", ("Getting commit_count: %s from share",
llstr(share->commit_count, buff)));
pthread_mutex_unlock(&share->mutex);
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
DBUG_RETURN(0);
}
@@ -7204,8 +7297,11 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
{
Ndb_table_guard ndbtab_g(ndb->getDictionary(), tabname);
if (ndbtab_g.get_table() == 0
- || ndb_get_table_statistics(NULL, false, ndb, ndbtab_g.get_table(), &stat))
+ || ndb_get_table_statistics(NULL, FALSE, ndb, ndbtab_g.get_table(), &stat))
{
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
DBUG_RETURN(1);
}
@@ -7214,7 +7310,9 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
pthread_mutex_lock(&share->mutex);
if (share->commit_count_lock == lock)
{
+#ifndef DBUG_OFF
char buff[22];
+#endif
DBUG_PRINT("info", ("Setting commit_count to %s",
llstr(stat.commit_count, buff)));
share->commit_count= stat.commit_count;
@@ -7226,6 +7324,9 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
*commit_count= 0;
}
pthread_mutex_unlock(&share->mutex);
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
DBUG_RETURN(0);
}
@@ -7270,7 +7371,9 @@ ndbcluster_cache_retrieval_allowed(THD *thd,
bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
char *dbname= full_name;
char *tabname= dbname+strlen(dbname)+1;
+#ifndef DBUG_OFF
char buff[22], buff2[22];
+#endif
DBUG_ENTER("ndbcluster_cache_retrieval_allowed");
DBUG_PRINT("enter", ("dbname: %s, tabname: %s, is_autocommit: %d",
dbname, tabname, is_autocommit));
@@ -7337,7 +7440,9 @@ ha_ndbcluster::register_query_cache_table(THD *thd,
ulonglong *engine_data)
{
Uint64 commit_count;
+#ifndef DBUG_OFF
char buff[22];
+#endif
bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
DBUG_ENTER("ha_ndbcluster::register_query_cache_table");
DBUG_PRINT("enter",("dbname: %s, tabname: %s, is_autocommit: %d",
@@ -7383,9 +7488,9 @@ static byte *ndbcluster_get_key(NDB_SHARE *share,uint *length,
static void print_share(const char* where, NDB_SHARE* share)
{
fprintf(DBUG_FILE,
- "%s %s.%s: use_count: %u, commit_count: %llu\n",
+ "%s %s.%s: use_count: %u, commit_count: %lu\n",
where, share->db, share->table_name, share->use_count,
- (long long unsigned int) share->commit_count);
+ (ulong) share->commit_count);
fprintf(DBUG_FILE,
" - key: %s, key_length: %d\n",
share->key, share->key_length);
@@ -7442,21 +7547,34 @@ int handle_trailing_share(NDB_SHARE *share)
static ulong trailing_share_id= 0;
DBUG_ENTER("handle_trailing_share");
+ /* ndb_share reference temporary, free below */
++share->use_count;
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
pthread_mutex_unlock(&ndbcluster_mutex);
TABLE_LIST table_list;
bzero((char*) &table_list,sizeof(table_list));
table_list.db= share->db;
table_list.alias= table_list.table_name= share->table_name;
+ safe_mutex_assert_owner(&LOCK_open);
close_cached_tables(thd, 0, &table_list, TRUE);
pthread_mutex_lock(&ndbcluster_mutex);
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
if (!--share->use_count)
{
- DBUG_PRINT("info", ("NDB_SHARE: close_cashed_tables %s freed share.",
- share->key));
- real_free_share(&share);
+ if (ndb_extra_logging)
+ sql_print_information("NDB_SHARE: trailing share "
+ "%s(connect_count: %u) "
+ "released by close_cached_tables at "
+ "connect_count: %u",
+ share->key,
+ share->connect_count,
+ g_ndb_cluster_connection->get_connect_count());
+ ndbcluster_real_free_share(&share);
DBUG_RETURN(0);
}
@@ -7464,16 +7582,28 @@ int handle_trailing_share(NDB_SHARE *share)
share still exists, if share has not been dropped by server
release that share
*/
- if (share->state != NSS_DROPPED && !--share->use_count)
+ if (share->state != NSS_DROPPED)
{
- DBUG_PRINT("info", ("NDB_SHARE: %s already exists, "
- "use_count=%d state != NSS_DROPPED.",
- share->key, share->use_count));
- real_free_share(&share);
- DBUG_RETURN(0);
+ share->state= NSS_DROPPED;
+ /* ndb_share reference create free */
+ DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
+ share->key, share->use_count));
+ --share->use_count;
+
+ if (share->use_count == 0)
+ {
+ if (ndb_extra_logging)
+ sql_print_information("NDB_SHARE: trailing share "
+ "%s(connect_count: %u) "
+ "released after NSS_DROPPED check "
+ "at connect_count: %u",
+ share->key,
+ share->connect_count,
+ g_ndb_cluster_connection->get_connect_count());
+ ndbcluster_real_free_share(&share);
+ DBUG_RETURN(0);
+ }
}
- DBUG_PRINT("error", ("NDB_SHARE: %s already exists use_count=%d.",
- share->key, share->use_count));
sql_print_error("NDB_SHARE: %s already exists use_count=%d."
" Moving away for safety, but possible memleak.",
@@ -7622,7 +7752,6 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
bool create_if_not_exists,
bool have_lock)
{
- THD *thd= current_thd;
NDB_SHARE *share;
uint length= (uint) strlen(key);
DBUG_ENTER("ndbcluster_get_share");
@@ -7736,7 +7865,7 @@ void ndbcluster_free_share(NDB_SHARE **share, bool have_lock)
(*share)->util_lock= 0;
if (!--(*share)->use_count)
{
- real_free_share(share);
+ ndbcluster_real_free_share(share);
}
else
{
@@ -7758,7 +7887,9 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const
int retries= 10;
int reterr= 0;
int retry_sleep= 30 * 1000; /* 30 milliseconds */
+#ifndef DBUG_OFF
char buff[22], buff2[22], buff3[22], buff4[22];
+#endif
DBUG_ENTER("ndb_get_table_statistics");
DBUG_PRINT("enter", ("table: %s", ndbtab->getName()));
@@ -7774,7 +7905,6 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const
Uint64 sum_row_size= 0;
Uint64 sum_mem= 0;
NdbScanOperation*pOp;
- NdbResultSet *rs;
int check;
if ((pTrans= ndb->startTransaction()) == NULL)
@@ -7810,7 +7940,7 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const
(char*)&var_mem);
if (pTrans->execute(NdbTransaction::NoCommit,
- NdbTransaction::AbortOnError,
+ NdbOperation::AbortOnError,
TRUE) == -1)
{
error= pTrans->getNdbError();
@@ -7953,10 +8083,10 @@ ha_ndbcluster::null_value_index_search(KEY_MULTI_RANGE *ranges,
const byte *key= range->start_key.key;
uint key_len= range->start_key.length;
if (check_null_in_key(key_info, key, key_len))
- DBUG_RETURN(true);
+ DBUG_RETURN(TRUE);
curr += reclength;
}
- DBUG_RETURN(false);
+ DBUG_RETURN(FALSE);
}
int
@@ -7966,21 +8096,20 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
bool sorted,
HANDLER_BUFFER *buffer)
{
- DBUG_ENTER("ha_ndbcluster::read_multi_range_first");
m_write_op= FALSE;
-
int res;
KEY* key_info= table->key_info + active_index;
- NDB_INDEX_TYPE index_type= get_index_type(active_index);
+ NDB_INDEX_TYPE cur_index_type= get_index_type(active_index);
ulong reclength= table_share->reclength;
NdbOperation* op;
Thd_ndb *thd_ndb= get_thd_ndb(current_thd);
+ DBUG_ENTER("ha_ndbcluster::read_multi_range_first");
/**
* blobs and unique hash index with NULL can't be batched currently
*/
if (uses_blob_value() ||
- (index_type == UNIQUE_INDEX &&
+ (cur_index_type == UNIQUE_INDEX &&
has_null_in_unique_index(active_index) &&
null_value_index_search(ranges, ranges+range_count, buffer)))
{
@@ -8055,7 +8184,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
continue;
}
}
- switch(index_type){
+ switch (cur_index_type) {
case PRIMARY_KEY_ORDERED_INDEX:
if (!(multi_range_curr->start_key.length == key_info->key_length &&
multi_range_curr->start_key.flag == HA_READ_KEY_EXACT))
@@ -8068,9 +8197,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
!op->readTuple(lm) &&
!set_primary_key(op, multi_range_curr->start_key.key) &&
!define_read_attrs(curr, op) &&
- (op->setAbortOption(AO_IgnoreError), TRUE) &&
(!m_use_partition_function ||
- (op->setPartitionId(part_spec.start_part), true)))
+ (op->setPartitionId(part_spec.start_part), TRUE)))
curr += reclength;
else
ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError());
@@ -8090,8 +8218,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
if ((op= m_active_trans->getNdbIndexOperation(unique_idx, tab)) &&
!op->readTuple(lm) &&
!set_index_key(op, key_info, multi_range_curr->start_key.key) &&
- !define_read_attrs(curr, op) &&
- (op->setAbortOption(AO_IgnoreError), TRUE))
+ !define_read_attrs(curr, op))
curr += reclength;
else
ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError());
@@ -8115,7 +8242,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
}
else if ((scanOp= m_active_trans->getNdbIndexScanOperation(idx, tab))
&&!scanOp->readTuples(lm, 0, parallelism, sorted,
- FALSE, TRUE, need_pk)
+ FALSE, TRUE, need_pk, TRUE)
&&!generate_scan_filter(m_cond_stack, scanOp)
&&!define_read_attrs(end_of_buffer-reclength, scanOp))
{
@@ -8131,7 +8258,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
const key_range *keys[2]= { &multi_range_curr->start_key,
&multi_range_curr->end_key };
- if ((res= set_bounds(scanOp, active_index, false, keys,
+ if ((res= set_bounds(scanOp, active_index, FALSE, keys,
multi_range_curr-ranges)))
DBUG_RETURN(res);
break;
@@ -8253,7 +8380,7 @@ ha_ndbcluster::read_multi_range_next(KEY_MULTI_RANGE ** multi_range_found_p)
DBUG_MULTI_RANGE(6);
// First fetch from cursor
DBUG_ASSERT(range_no == -1);
- if ((res= m_multi_cursor->nextResult(true)))
+ if ((res= m_multi_cursor->nextResult(TRUE)))
{
DBUG_MULTI_RANGE(15);
goto close_scan;
@@ -8291,6 +8418,8 @@ close_scan:
if (multi_range_curr == multi_range_end)
{
DBUG_MULTI_RANGE(16);
+ Thd_ndb *thd_ndb= get_thd_ndb(current_thd);
+ thd_ndb->query_state&= NDB_QUERY_NORMAL;
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
@@ -8375,7 +8504,6 @@ ha_ndbcluster::update_table_comment(
}
ndb->setDatabaseName(m_dbname);
- NDBDICT* dict= ndb->getDictionary();
const NDBTAB* tab= m_table;
DBUG_ASSERT(tab != NULL);
@@ -8419,7 +8547,6 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
goto ndb_util_thread_fail;
thd->init_for_queries();
thd->version=refresh_version;
- thd->set_time();
thd->main_security_ctx.host_or_ip= "";
thd->client_capabilities = 0;
my_net_init(&thd->net, 0);
@@ -8530,7 +8657,10 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
continue; // injector thread is the only user, skip statistics
share->util_lock= current_thd; // Mark that util thread has lock
#endif /* HAVE_NDB_BINLOG */
+ /* ndb_share reference temporary, free below */
share->use_count++; /* Make sure the table can't be closed */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
DBUG_PRINT("ndb_util_thread",
("Found open table[%d]: %s, use_count: %d",
i, share->table_name, share->use_count));
@@ -8551,6 +8681,9 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
/*
Util thread and injector thread is the only user, skip statistics
*/
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
continue;
}
@@ -8570,10 +8703,12 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
ndb->setDatabaseName(share->db);
Ndb_table_guard ndbtab_g(ndb->getDictionary(), share->table_name);
if (ndbtab_g.get_table() &&
- ndb_get_table_statistics(NULL, false, ndb,
+ ndb_get_table_statistics(NULL, FALSE, ndb,
ndbtab_g.get_table(), &stat) == 0)
{
+#ifndef DBUG_OFF
char buff[22], buff2[22];
+#endif
DBUG_PRINT("info",
("Table: %s commit_count: %s rows: %s",
share->key,
@@ -8594,7 +8729,9 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
share->commit_count= stat.commit_count;
pthread_mutex_unlock(&share->mutex);
- /* Decrease the use count and possibly free share */
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
}
@@ -8751,14 +8888,14 @@ void ndb_serialize_cond(const Item *item, void *arg)
if (context->supported)
{
- Ndb_rewrite_context *rewrite_context= context->rewrite_stack;
- const Item_func *func_item;
+ Ndb_rewrite_context *rewrite_context2= context->rewrite_stack;
+ const Item_func *rewrite_func_item;
// Check if we are rewriting some unsupported function call
- if (rewrite_context &&
- (func_item= rewrite_context->func_item) &&
- rewrite_context->count++ == 0)
+ if (rewrite_context2 &&
+ (rewrite_func_item= rewrite_context2->func_item) &&
+ rewrite_context2->count++ == 0)
{
- switch (func_item->functype()) {
+ switch (rewrite_func_item->functype()) {
case Item_func::BETWEEN:
/*
Rewrite
@@ -8785,7 +8922,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
if (context->expecting(item->type()))
{
// This is the <field>|<const> item, save it in the rewrite context
- rewrite_context->left_hand_item= item;
+ rewrite_context2->left_hand_item= item;
if (item->type() == Item::FUNC_ITEM)
{
Item_func *func_item= (Item_func *) item;
@@ -8929,7 +9066,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
Check that the field is part of the table of the handler
instance and that we expect a field with of this result type.
*/
- if (context->table == field->table)
+ if (context->table->s == field->table->s)
{
const NDBTAB *tab= (const NDBTAB *) context->ndb_table;
DBUG_PRINT("info", ("FIELD_ITEM"));
@@ -8950,7 +9087,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
type == MYSQL_TYPE_DATETIME)
? (context->expecting_field_result(STRING_RESULT) ||
context->expecting_field_result(INT_RESULT))
- : true)) &&
+ : TRUE)) &&
// Bit fields no yet supported in scan filter
type != MYSQL_TYPE_BIT &&
// No BLOB support in scan filter
@@ -9423,8 +9560,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
DBUG_PRINT("info", ("INT_ITEM"));
if (context->expecting(Item::INT_ITEM))
{
- Item_int *int_item= (Item_int *) item;
- DBUG_PRINT("info", ("value %ld", (long) int_item->value));
+ DBUG_PRINT("info", ("value %ld",
+ (long) ((Item_int*) item)->value));
NDB_ITEM_QUALIFICATION q;
q.value_type= Item::INT_ITEM;
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
@@ -9450,8 +9587,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
DBUG_PRINT("info", ("REAL_ITEM"));
if (context->expecting(Item::REAL_ITEM))
{
- Item_float *float_item= (Item_float *) item;
- DBUG_PRINT("info", ("value %f", float_item->value));
+ DBUG_PRINT("info", ("value %f", ((Item_float*) item)->value));
NDB_ITEM_QUALIFICATION q;
q.value_type= Item::REAL_ITEM;
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
@@ -9498,8 +9634,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
DBUG_PRINT("info", ("DECIMAL_ITEM"));
if (context->expecting(Item::DECIMAL_ITEM))
{
- Item_decimal *decimal_item= (Item_decimal *) item;
- DBUG_PRINT("info", ("value %f", decimal_item->val_real()));
+ DBUG_PRINT("info", ("value %f",
+ ((Item_decimal*) item)->val_real()));
NDB_ITEM_QUALIFICATION q;
q.value_type= Item::DECIMAL_ITEM;
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
@@ -9610,25 +9746,24 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
break;
Ndb_item *a= cond->next->ndb_item;
Ndb_item *b, *field, *value= NULL;
- LINT_INIT(field);
switch (cond->ndb_item->argument_count()) {
case 1:
- field=
- (a->type == NDB_FIELD)? a : NULL;
+ field= (a->type == NDB_FIELD)? a : NULL;
break;
case 2:
if (!cond->next->next)
+ {
+ field= NULL;
break;
+ }
b= cond->next->next->ndb_item;
- value=
- (a->type == NDB_VALUE)? a
- : (b->type == NDB_VALUE)? b
- : NULL;
- field=
- (a->type == NDB_FIELD)? a
- : (b->type == NDB_FIELD)? b
- : NULL;
+ value= ((a->type == NDB_VALUE) ? a :
+ (b->type == NDB_VALUE) ? b :
+ NULL);
+ field= ((a->type == NDB_FIELD) ? a :
+ (b->type == NDB_FIELD) ? b :
+ NULL);
break;
default:
field= NULL; //Keep compiler happy
@@ -9838,6 +9973,7 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
DBUG_RETURN(1);
}
+
int
ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter)
{
@@ -9911,6 +10047,7 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter)
DBUG_RETURN(0);
}
+
int
ha_ndbcluster::build_scan_filter(Ndb_cond * &cond, NdbScanFilter *filter)
{
@@ -9961,14 +10098,14 @@ ha_ndbcluster::generate_scan_filter(Ndb_cond_stack *ndb_cond_stack,
DBUG_RETURN(0);
}
+
int
ha_ndbcluster::generate_scan_filter_from_cond(Ndb_cond_stack *ndb_cond_stack,
NdbScanFilter& filter)
{
- DBUG_ENTER("generate_scan_filter_from_cond");
bool multiple_cond= FALSE;
-
- DBUG_PRINT("info", ("Generating scan filter"));
+ DBUG_ENTER("generate_scan_filter_from_cond");
+
// Wrap an AND group around multiple conditions
if (ndb_cond_stack->next)
{
@@ -9994,6 +10131,7 @@ ha_ndbcluster::generate_scan_filter_from_cond(Ndb_cond_stack *ndb_cond_stack,
DBUG_RETURN(0);
}
+
int ha_ndbcluster::generate_scan_filter_from_key(NdbScanOperation *op,
const KEY* key_info,
const byte *key,
@@ -10004,15 +10142,14 @@ int ha_ndbcluster::generate_scan_filter_from_key(NdbScanOperation *op,
KEY_PART_INFO* end= key_part+key_info->key_parts;
NdbScanFilter filter(op);
int res;
-
DBUG_ENTER("generate_scan_filter_from_key");
+
filter.begin(NdbScanFilter::AND);
for (; key_part != end; key_part++)
{
Field* field= key_part->field;
uint32 pack_len= field->pack_length();
const byte* ptr= key;
- char buf[256];
DBUG_PRINT("info", ("Filtering value for %s", field->field_name));
DBUG_DUMP("key", (char*)ptr, pack_len);
if (key_part->null_bit)
@@ -10190,13 +10327,13 @@ static bool adjusted_frag_count(uint no_fragments, uint no_nodes,
return (reported_frags < no_fragments);
}
-int ha_ndbcluster::get_default_no_partitions(HA_CREATE_INFO *info)
+int ha_ndbcluster::get_default_no_partitions(HA_CREATE_INFO *create_info)
{
ha_rows max_rows, min_rows;
- if (info)
+ if (create_info)
{
- max_rows= info->max_rows;
- min_rows= info->min_rows;
+ max_rows= create_info->max_rows;
+ min_rows= create_info->min_rows;
}
else
{
@@ -10347,15 +10484,14 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info,
{
uint16 frag_data[MAX_PARTITIONS];
char *ts_names[MAX_PARTITIONS];
- ulong ts_index= 0, fd_index= 0, i, j;
+ ulong fd_index= 0, i, j;
NDBTAB *tab= (NDBTAB*)tab_par;
NDBTAB::FragmentType ftype= NDBTAB::UserDefined;
partition_element *part_elem;
bool first= TRUE;
- uint ts_id, ts_version, part_count= 0, tot_ts_name_len;
+ uint tot_ts_name_len;
List_iterator<partition_element> part_it(part_info->partitions);
int error;
- char *name_ptr;
DBUG_ENTER("ha_ndbcluster::set_up_partition_info");
if (part_info->part_type == HASH_PARTITION &&
@@ -10469,7 +10605,7 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info,
}
-bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *info,
+bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *create_info,
uint table_changes)
{
DBUG_ENTER("ha_ndbcluster::check_if_incompatible_data");
@@ -10527,76 +10663,78 @@ bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *info,
}
/* Check that auto_increment value was not changed */
- if ((info->used_fields & HA_CREATE_USED_AUTO) &&
- info->auto_increment_value != 0)
+ if ((create_info->used_fields & HA_CREATE_USED_AUTO) &&
+ create_info->auto_increment_value != 0)
DBUG_RETURN(COMPATIBLE_DATA_NO);
/* Check that row format didn't change */
- if ((info->used_fields & HA_CREATE_USED_AUTO) &&
- get_row_type() != info->row_type)
+ if ((create_info->used_fields & HA_CREATE_USED_AUTO) &&
+ get_row_type() != create_info->row_type)
DBUG_RETURN(COMPATIBLE_DATA_NO);
DBUG_RETURN(COMPATIBLE_DATA_YES);
}
-bool set_up_tablespace(st_alter_tablespace *info,
+bool set_up_tablespace(st_alter_tablespace *alter_info,
NdbDictionary::Tablespace *ndb_ts)
{
- ndb_ts->setName(info->tablespace_name);
- ndb_ts->setExtentSize(info->extent_size);
- ndb_ts->setDefaultLogfileGroup(info->logfile_group_name);
- return false;
+ ndb_ts->setName(alter_info->tablespace_name);
+ ndb_ts->setExtentSize(alter_info->extent_size);
+ ndb_ts->setDefaultLogfileGroup(alter_info->logfile_group_name);
+ return FALSE;
}
-bool set_up_datafile(st_alter_tablespace *info,
+bool set_up_datafile(st_alter_tablespace *alter_info,
NdbDictionary::Datafile *ndb_df)
{
- if (info->max_size > 0)
+ if (alter_info->max_size > 0)
{
my_error(ER_TABLESPACE_AUTO_EXTEND_ERROR, MYF(0));
- return true;
+ return TRUE;
}
- ndb_df->setPath(info->data_file_name);
- ndb_df->setSize(info->initial_size);
- ndb_df->setTablespace(info->tablespace_name);
- return false;
+ ndb_df->setPath(alter_info->data_file_name);
+ ndb_df->setSize(alter_info->initial_size);
+ ndb_df->setTablespace(alter_info->tablespace_name);
+ return FALSE;
}
-bool set_up_logfile_group(st_alter_tablespace *info,
+bool set_up_logfile_group(st_alter_tablespace *alter_info,
NdbDictionary::LogfileGroup *ndb_lg)
{
- ndb_lg->setName(info->logfile_group_name);
- ndb_lg->setUndoBufferSize(info->undo_buffer_size);
- return false;
+ ndb_lg->setName(alter_info->logfile_group_name);
+ ndb_lg->setUndoBufferSize(alter_info->undo_buffer_size);
+ return FALSE;
}
-bool set_up_undofile(st_alter_tablespace *info,
+bool set_up_undofile(st_alter_tablespace *alter_info,
NdbDictionary::Undofile *ndb_uf)
{
- ndb_uf->setPath(info->undo_file_name);
- ndb_uf->setSize(info->initial_size);
- ndb_uf->setLogfileGroup(info->logfile_group_name);
- return false;
+ ndb_uf->setPath(alter_info->undo_file_name);
+ ndb_uf->setSize(alter_info->initial_size);
+ ndb_uf->setLogfileGroup(alter_info->logfile_group_name);
+ return FALSE;
}
-int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace *info)
+int ndbcluster_alter_tablespace(handlerton *hton,
+ THD* thd, st_alter_tablespace *alter_info)
{
+ int is_tablespace= 0;
+ NdbError err;
+ NDBDICT *dict;
+ int error;
+ const char *errmsg;
+ Ndb *ndb;
DBUG_ENTER("ha_ndbcluster::alter_tablespace");
+ LINT_INIT(errmsg);
- int is_tablespace= 0;
- Ndb *ndb= check_ndb_in_thd(thd);
+ ndb= check_ndb_in_thd(thd);
if (ndb == NULL)
{
DBUG_RETURN(HA_ERR_NO_CONNECTION);
}
+ dict= ndb->getDictionary();
- NdbError err;
- NDBDICT *dict= ndb->getDictionary();
- int error;
- const char * errmsg;
- LINT_INIT(errmsg);
-
- switch (info->ts_cmd_type){
+ switch (alter_info->ts_cmd_type){
case (CREATE_TABLESPACE):
{
error= ER_CREATE_FILEGROUP_FAILED;
@@ -10604,11 +10742,11 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
NdbDictionary::Tablespace ndb_ts;
NdbDictionary::Datafile ndb_df;
NdbDictionary::ObjectId objid;
- if (set_up_tablespace(info, &ndb_ts))
+ if (set_up_tablespace(alter_info, &ndb_ts))
{
DBUG_RETURN(1);
}
- if (set_up_datafile(info, &ndb_df))
+ if (set_up_datafile(alter_info, &ndb_df))
{
DBUG_RETURN(1);
}
@@ -10618,7 +10756,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
DBUG_PRINT("error", ("createTablespace returned %d", error));
goto ndberror;
}
- DBUG_PRINT("info", ("Successfully created Tablespace"));
+ DBUG_PRINT("alter_info", ("Successfully created Tablespace"));
errmsg= "DATAFILE";
if (dict->createDatafile(ndb_df))
{
@@ -10640,10 +10778,10 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
case (ALTER_TABLESPACE):
{
error= ER_ALTER_FILEGROUP_FAILED;
- if (info->ts_alter_tablespace_type == ALTER_TABLESPACE_ADD_FILE)
+ if (alter_info->ts_alter_tablespace_type == ALTER_TABLESPACE_ADD_FILE)
{
NdbDictionary::Datafile ndb_df;
- if (set_up_datafile(info, &ndb_df))
+ if (set_up_datafile(alter_info, &ndb_df))
{
DBUG_RETURN(1);
}
@@ -10653,14 +10791,14 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
goto ndberror;
}
}
- else if(info->ts_alter_tablespace_type == ALTER_TABLESPACE_DROP_FILE)
+ else if(alter_info->ts_alter_tablespace_type == ALTER_TABLESPACE_DROP_FILE)
{
- NdbDictionary::Tablespace ts= dict->getTablespace(info->tablespace_name);
- NdbDictionary::Datafile df= dict->getDatafile(0, info->data_file_name);
+ NdbDictionary::Tablespace ts= dict->getTablespace(alter_info->tablespace_name);
+ NdbDictionary::Datafile df= dict->getDatafile(0, alter_info->data_file_name);
NdbDictionary::ObjectId objid;
df.getTablespaceId(&objid);
if (ts.getObjectId() == objid.getObjectId() &&
- strcmp(df.getPath(), info->data_file_name) == 0)
+ strcmp(df.getPath(), alter_info->data_file_name) == 0)
{
errmsg= " DROP DATAFILE";
if (dict->dropDatafile(df))
@@ -10678,7 +10816,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
else
{
DBUG_PRINT("error", ("Unsupported alter tablespace: %d",
- info->ts_alter_tablespace_type));
+ alter_info->ts_alter_tablespace_type));
DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
}
is_tablespace= 1;
@@ -10690,14 +10828,14 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
NdbDictionary::LogfileGroup ndb_lg;
NdbDictionary::Undofile ndb_uf;
NdbDictionary::ObjectId objid;
- if (info->undo_file_name == NULL)
+ if (alter_info->undo_file_name == NULL)
{
/*
REDO files in LOGFILE GROUP not supported yet
*/
DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
}
- if (set_up_logfile_group(info, &ndb_lg))
+ if (set_up_logfile_group(alter_info, &ndb_lg))
{
DBUG_RETURN(1);
}
@@ -10706,8 +10844,8 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
{
goto ndberror;
}
- DBUG_PRINT("info", ("Successfully created Logfile Group"));
- if (set_up_undofile(info, &ndb_uf))
+ DBUG_PRINT("alter_info", ("Successfully created Logfile Group"));
+ if (set_up_undofile(alter_info, &ndb_uf))
{
DBUG_RETURN(1);
}
@@ -10729,7 +10867,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
case (ALTER_LOGFILE_GROUP):
{
error= ER_ALTER_FILEGROUP_FAILED;
- if (info->undo_file_name == NULL)
+ if (alter_info->undo_file_name == NULL)
{
/*
REDO files in LOGFILE GROUP not supported yet
@@ -10737,7 +10875,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
}
NdbDictionary::Undofile ndb_uf;
- if (set_up_undofile(info, &ndb_uf))
+ if (set_up_undofile(alter_info, &ndb_uf))
{
DBUG_RETURN(1);
}
@@ -10752,7 +10890,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
{
error= ER_DROP_FILEGROUP_FAILED;
errmsg= "TABLESPACE";
- if (dict->dropTablespace(dict->getTablespace(info->tablespace_name)))
+ if (dict->dropTablespace(dict->getTablespace(alter_info->tablespace_name)))
{
goto ndberror;
}
@@ -10763,7 +10901,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
{
error= ER_DROP_FILEGROUP_FAILED;
errmsg= "LOGFILE GROUP";
- if (dict->dropLogfileGroup(dict->getLogfileGroup(info->logfile_group_name)))
+ if (dict->dropLogfileGroup(dict->getLogfileGroup(alter_info->logfile_group_name)))
{
goto ndberror;
}
@@ -10786,13 +10924,13 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
if (is_tablespace)
ndbcluster_log_schema_op(thd, 0,
thd->query, thd->query_length,
- "", info->tablespace_name,
+ "", alter_info->tablespace_name,
0, 0,
SOT_TABLESPACE, 0, 0, 0);
else
ndbcluster_log_schema_op(thd, 0,
thd->query, thd->query_length,
- "", info->logfile_group_name,
+ "", alter_info->logfile_group_name,
0, 0,
SOT_LOGFILE_GROUP, 0, 0, 0);
#endif
@@ -10813,7 +10951,6 @@ bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts)
{
Ndb *ndb;
NDBDICT *dict;
- const NDBTAB *tab;
int err;
DBUG_ENTER("ha_ndbcluster::get_no_parts");
LINT_INIT(err);
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index 5b6900766b6..63665fde0f8 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -108,6 +108,7 @@ typedef struct st_ndbcluster_share {
char *table_name;
Ndb::TupleIdRange tuple_id_range;
#ifdef HAVE_NDB_BINLOG
+ uint32 connect_count;
uint32 flags;
NdbEventOperation *op;
NdbEventOperation *op_old; // for rename table
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index 38b640d5f55..2615732e7ee 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -81,6 +81,7 @@ static Ndb *injector_ndb= 0;
static Ndb *schema_ndb= 0;
static int ndbcluster_binlog_inited= 0;
+static int ndbcluster_binlog_terminating= 0;
/*
Mutex and condition used for interacting between client sql thread
@@ -97,6 +98,7 @@ static ulonglong ndb_latest_received_binlog_epoch= 0;
NDB_SHARE *ndb_apply_status_share= 0;
NDB_SHARE *ndb_schema_share= 0;
+pthread_mutex_t ndb_schema_share_mutex;
/* Schema object distribution handling */
HASH ndb_schema_objects;
@@ -361,6 +363,8 @@ void ndbcluster_binlog_init_share(NDB_SHARE *share, TABLE *_table)
int do_event_op= ndb_binlog_running;
DBUG_ENTER("ndbcluster_binlog_init_share");
+ share->connect_count= g_ndb_cluster_connection->get_connect_count();
+
share->op= 0;
share->table= 0;
@@ -368,6 +372,10 @@ void ndbcluster_binlog_init_share(NDB_SHARE *share, TABLE *_table)
strcmp(share->db, NDB_REP_DB) == 0 &&
strcmp(share->table_name, NDB_SCHEMA_TABLE) == 0)
do_event_op= 1;
+ else if (!ndb_apply_status_share &&
+ strcmp(share->db, NDB_REP_DB) == 0 &&
+ strcmp(share->table_name, NDB_APPLY_TABLE) == 0)
+ do_event_op= 1;
{
int i, no_nodes= g_ndb_cluster_connection->no_db_nodes();
@@ -575,53 +583,18 @@ static int ndbcluster_binlog_end(THD *thd)
#ifdef HAVE_NDB_BINLOG
/* wait for injector thread to finish */
+ ndbcluster_binlog_terminating= 1;
+ pthread_cond_signal(&injector_cond);
pthread_mutex_lock(&injector_mutex);
- if (ndb_binlog_thread_running > 0)
- {
- pthread_cond_signal(&injector_cond);
- pthread_mutex_unlock(&injector_mutex);
-
- pthread_mutex_lock(&injector_mutex);
- while (ndb_binlog_thread_running > 0)
- {
- struct timespec abstime;
- set_timespec(abstime, 1);
- pthread_cond_timedwait(&injector_cond, &injector_mutex, &abstime);
- }
- }
+ while (ndb_binlog_thread_running > 0)
+ pthread_cond_wait(&injector_cond, &injector_mutex);
pthread_mutex_unlock(&injector_mutex);
-
- /* remove all shares */
- {
- pthread_mutex_lock(&ndbcluster_mutex);
- for (uint i= 0; i < ndbcluster_open_tables.records; i++)
- {
- NDB_SHARE *share=
- (NDB_SHARE*) hash_element(&ndbcluster_open_tables, i);
- if (share->table)
- DBUG_PRINT("share",
- ("table->s->db.table_name: %s.%s",
- share->table->s->db.str, share->table->s->table_name.str));
- if (share->state != NSS_DROPPED && !--share->use_count)
- real_free_share(&share);
- else
- {
- DBUG_PRINT("share",
- ("[%d] 0x%lx key: %s key_length: %d",
- i, (long) share, share->key, share->key_length));
- DBUG_PRINT("share",
- ("db.tablename: %s.%s use_count: %d commit_count: %lu",
- share->db, share->table_name,
- share->use_count, (long) share->commit_count));
- }
- }
- pthread_mutex_unlock(&ndbcluster_mutex);
- }
-
pthread_mutex_destroy(&injector_mutex);
pthread_cond_destroy(&injector_cond);
+ pthread_mutex_destroy(&ndb_schema_share_mutex);
#endif
+
DBUG_RETURN(0);
}
@@ -1131,7 +1104,7 @@ ndbcluster_update_slock(THD *thd,
ndb_error= this_error;
break;
}
-end:
+
if (ndb_error)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
@@ -1271,6 +1244,16 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
int no_storage_nodes= g_ndb_cluster_connection->no_db_nodes();
bitmap_init(&schema_subscribers, bitbuf, sizeof(bitbuf)*8, FALSE);
bitmap_set_all(&schema_subscribers);
+
+ /* begin protect ndb_schema_share */
+ pthread_mutex_lock(&ndb_schema_share_mutex);
+ if (ndb_schema_share == 0)
+ {
+ pthread_mutex_unlock(&ndb_schema_share_mutex);
+ if (ndb_schema_object)
+ ndb_free_schema_object(&ndb_schema_object, FALSE);
+ DBUG_RETURN(0);
+ }
(void) pthread_mutex_lock(&ndb_schema_share->mutex);
for (i= 0; i < no_storage_nodes; i++)
{
@@ -1283,6 +1266,9 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
}
}
(void) pthread_mutex_unlock(&ndb_schema_share->mutex);
+ pthread_mutex_unlock(&ndb_schema_share_mutex);
+ /* end protect ndb_schema_share */
+
if (updated)
{
bitmap_clear_bit(&schema_subscribers, node_id);
@@ -1478,6 +1464,14 @@ end:
&abstime);
if (thd->killed)
break;
+
+ /* begin protect ndb_schema_share */
+ pthread_mutex_lock(&ndb_schema_share_mutex);
+ if (ndb_schema_share == 0)
+ {
+ pthread_mutex_unlock(&ndb_schema_share_mutex);
+ break;
+ }
(void) pthread_mutex_lock(&ndb_schema_share->mutex);
for (i= 0; i < no_storage_nodes; i++)
{
@@ -1487,6 +1481,8 @@ end:
bitmap_intersect(&schema_subscribers, tmp);
}
(void) pthread_mutex_unlock(&ndb_schema_share->mutex);
+ pthread_mutex_unlock(&ndb_schema_share_mutex);
+ /* end protect ndb_schema_share */
/* remove any unsubscribed from ndb_schema_object->slock */
bitmap_intersect(&ndb_schema_object->slock_bitmap, &schema_subscribers);
@@ -1689,15 +1685,25 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
(void) pthread_cond_signal(&injector_cond);
pthread_mutex_lock(&ndbcluster_mutex);
+ /* ndb_share reference binlog free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog free use_count: %u",
+ share->key, share->use_count));
free_share(&share, TRUE);
if (is_remote_change && share && share->state != NSS_DROPPED)
{
DBUG_PRINT("info", ("remote change"));
share->state= NSS_DROPPED;
if (share->use_count != 1)
+ {
+ /* open handler holding reference */
+ /* wait with freeing create ndb_share to below */
do_close_cached_tables= TRUE;
+ }
else
{
+ /* ndb_share reference create free */
+ DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
+ share->key, share->use_count));
free_share(&share, TRUE);
share= 0;
}
@@ -1720,6 +1726,9 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
table_list.db= (char *)dbname;
table_list.alias= table_list.table_name= (char *)tabname;
close_cached_tables(thd, 0, &table_list);
+ /* ndb_share reference create free */
+ DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
}
DBUG_RETURN(0);
@@ -1787,7 +1796,13 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
char key[FN_REFLEN];
build_table_filename(key, sizeof(key),
schema->db, schema->name, "", 0);
+ /* ndb_share reference temporary, free below */
NDB_SHARE *share= get_share(key, 0, FALSE, FALSE);
+ if (share)
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
+ }
// invalidation already handled by binlog thread
if (!share || !share->op)
{
@@ -1803,21 +1818,26 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
table_list.alias= table_list.table_name= schema->name;
close_cached_tables(thd, 0, &table_list, FALSE);
}
+ /* ndb_share reference temporary free */
if (share)
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
+ }
}
// fall through
case SOT_CREATE_TABLE:
pthread_mutex_lock(&LOCK_open);
- if (ndbcluster_check_if_local_table(schema->db, schema->name))
- {
- DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'",
- schema->db, schema->name));
+ if (ndbcluster_check_if_local_table(schema->db, schema->name))
+ {
+ DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'",
+ schema->db, schema->name));
sql_print_error("NDB binlog: Skipping locally defined table '%s.%s' from "
"binlog schema event '%s' from node %d. ",
schema->db, schema->name, schema->query,
schema->node_id);
- }
+ }
else if (ndb_create_table_from_engine(thd, schema->db, schema->name))
{
sql_print_error("NDB binlog: Could not discover table '%s.%s' from "
@@ -1834,27 +1854,27 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
log_query= 1;
break;
case SOT_DROP_DB:
- /* Drop the database locally if it only contains ndb tables */
- if (! ndbcluster_check_if_local_tables_in_db(thd, schema->db))
- {
- run_query(thd, schema->query,
- schema->query + schema->query_length,
- TRUE, /* print error */
- TRUE); /* don't binlog the query */
- /* binlog dropping database after any table operations */
- post_epoch_log_list->push_back(schema, mem_root);
- /* acknowledge this query _after_ epoch completion */
- post_epoch_unlock= 1;
- }
- else
- {
- /* Database contained local tables, leave it */
- sql_print_error("NDB binlog: Skipping drop database '%s' since it contained local tables "
+ /* Drop the database locally if it only contains ndb tables */
+ if (! ndbcluster_check_if_local_tables_in_db(thd, schema->db))
+ {
+ run_query(thd, schema->query,
+ schema->query + schema->query_length,
+ TRUE, /* print error */
+ TRUE); /* don't binlog the query */
+ /* binlog dropping database after any table operations */
+ post_epoch_log_list->push_back(schema, mem_root);
+ /* acknowledge this query _after_ epoch completion */
+ post_epoch_unlock= 1;
+ }
+ else
+ {
+ /* Database contained local tables, leave it */
+ sql_print_error("NDB binlog: Skipping drop database '%s' since it contained local tables "
"binlog schema event '%s' from node %d. ",
schema->db, schema->query,
schema->node_id);
- log_query= 1;
- }
+ log_query= 1;
+ }
break;
case SOT_CREATE_DB:
/* fall through */
@@ -1910,8 +1930,18 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
ndb_binlog_tables_inited && ndb_binlog_running)
sql_print_information("NDB Binlog: ndb tables initially "
"read only on reconnect.");
+
+ /* begin protect ndb_schema_share */
+ pthread_mutex_lock(&ndb_schema_share_mutex);
+ /* ndb_share reference binlog extra free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u",
+ ndb_schema_share->key,
+ ndb_schema_share->use_count));
free_share(&ndb_schema_share);
ndb_schema_share= 0;
+ pthread_mutex_unlock(&ndb_schema_share_mutex);
+ /* end protect ndb_schema_share */
+
close_cached_tables((THD*) 0, 0, (TABLE_LIST*) 0, FALSE);
// fall through
case NDBEVENT::TE_ALTER:
@@ -2033,7 +2063,13 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
pthread_mutex_unlock(&ndbcluster_mutex);
continue;
}
+ /* ndb_share reference temporary, free below */
NDB_SHARE *share= get_share(key, 0, FALSE, FALSE);
+ if (share)
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
+ }
switch (schema_type)
{
case SOT_DROP_DB:
@@ -2078,22 +2114,25 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
*/
if (share)
{
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
share= 0;
}
pthread_mutex_lock(&LOCK_open);
- if (ndbcluster_check_if_local_table(schema->db, schema->name))
- {
- DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'",
- schema->db, schema->name));
+ if (ndbcluster_check_if_local_table(schema->db, schema->name))
+ {
+ DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'",
+ schema->db, schema->name));
sql_print_error("NDB binlog: Skipping locally defined table '%s.%s' from "
"binlog schema event '%s' from node %d. ",
schema->db, schema->name, schema->query,
schema->node_id);
- }
+ }
else if (ndb_create_table_from_engine(thd, schema->db, schema->name))
- {
- sql_print_error("NDB binlog: Could not discover table '%s.%s' from "
+ {
+ sql_print_error("NDB binlog: Could not discover table '%s.%s' from "
"binlog schema event '%s' from node %d. my_errno: %d",
schema->db, schema->name, schema->query,
schema->node_id, my_errno);
@@ -2110,6 +2149,9 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
}
if (share)
{
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
share= 0;
}
@@ -2218,7 +2260,7 @@ int ndb_add_ndb_binlog_index(THD *thd, void *_row)
{
TABLE_LIST *p_binlog_tables= &binlog_tables;
close_tables_for_reopen(thd, &p_binlog_tables);
- ndb_binlog_index= 0;
+ ndb_binlog_index= 0;
continue;
}
sql_print_error("NDB Binlog: Unable to lock table ndb_binlog_index");
@@ -2278,6 +2320,7 @@ int ndbcluster_binlog_start()
pthread_mutex_init(&injector_mutex, MY_MUTEX_INIT_FAST);
pthread_cond_init(&injector_cond, NULL);
+ pthread_mutex_init(&ndb_schema_share_mutex, MY_MUTEX_INIT_FAST);
/* Create injector thread */
if (pthread_create(&ndb_binlog_thread, &connection_attrib,
@@ -2300,7 +2343,6 @@ int ndbcluster_binlog_start()
if (ndb_binlog_thread_running < 0)
DBUG_RETURN(-1);
-
DBUG_RETURN(0);
}
@@ -2411,20 +2453,42 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key,
pthread_mutex_unlock(&ndbcluster_mutex);
DBUG_RETURN(1);
}
- handle_trailing_share(share);
+ if (!share_may_exist || share->connect_count !=
+ g_ndb_cluster_connection->get_connect_count())
+ {
+ handle_trailing_share(share);
+ share= NULL;
+ }
}
/* Create share which is needed to hold replication information */
- if (!(share= get_share(key, 0, TRUE, TRUE)))
+ if (share)
+ {
+ /* ndb_share reference create */
+ ++share->use_count;
+ DBUG_PRINT("NDB_SHARE", ("%s create use_count: %u",
+ share->key, share->use_count));
+ }
+ /* ndb_share reference create */
+ else if (!(share= get_share(key, 0, TRUE, TRUE)))
{
sql_print_error("NDB Binlog: "
"allocating table share for %s failed", key);
}
+ else
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s create use_count: %u",
+ share->key, share->use_count));
+ }
if (!ndb_schema_share &&
strcmp(share->db, NDB_REP_DB) == 0 &&
strcmp(share->table_name, NDB_SCHEMA_TABLE) == 0)
do_event_op= 1;
+ else if (!ndb_apply_status_share &&
+ strcmp(share->db, NDB_REP_DB) == 0 &&
+ strcmp(share->table_name, NDB_APPLY_TABLE) == 0)
+ do_event_op= 1;
if (!do_event_op)
{
@@ -2696,7 +2760,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
else if (!ndb_apply_status_share && strcmp(share->db, NDB_REP_DB) == 0 &&
strcmp(share->table_name, NDB_APPLY_TABLE) == 0)
do_ndb_apply_status_share= 1;
- else if (!binlog_filter->db_ok(share->db))
+ else if (!binlog_filter->db_ok(share->db) || !ndb_binlog_running)
{
share->flags|= NSF_NO_BINLOG;
DBUG_RETURN(0);
@@ -2708,6 +2772,9 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
DBUG_ASSERT(share->use_count > 1);
sql_print_error("NDB Binlog: discover reusing old ev op");
+ /* ndb_share reference ToDo free */
+ DBUG_PRINT("NDB_SHARE", ("%s ToDo free use_count: %u",
+ share->key, share->use_count));
free_share(&share); // old event op already has reference
DBUG_RETURN(0);
}
@@ -2850,15 +2917,24 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
break;
}
+ /* ndb_share reference binlog */
get_share(share);
+ DBUG_PRINT("NDB_SHARE", ("%s binlog use_count: %u",
+ share->key, share->use_count));
if (do_ndb_apply_status_share)
{
+ /* ndb_share reference binlog extra */
ndb_apply_status_share= get_share(share);
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra use_count: %u",
+ share->key, share->use_count));
(void) pthread_cond_signal(&injector_cond);
}
else if (do_ndb_schema_share)
{
+ /* ndb_share reference binlog extra */
ndb_schema_share= get_share(share);
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra use_count: %u",
+ share->key, share->use_count));
(void) pthread_cond_signal(&injector_cond);
}
@@ -3045,6 +3121,9 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb,
ndb_binlog_tables_inited && ndb_binlog_running)
sql_print_information("NDB Binlog: ndb tables initially "
"read only on reconnect.");
+ /* ndb_share reference binlog extra free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u",
+ share->key, share->use_count));
free_share(&ndb_apply_status_share);
ndb_apply_status_share= 0;
}
@@ -3061,6 +3140,9 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb,
ndb_binlog_tables_inited && ndb_binlog_running)
sql_print_information("NDB Binlog: ndb tables initially "
"read only on reconnect.");
+ /* ndb_share reference binlog extra free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u",
+ share->key, share->use_count));
free_share(&ndb_apply_status_share);
ndb_apply_status_share= 0;
}
@@ -3143,15 +3225,17 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= 0;
- int ret= get_ndb_blobs_value(table, share->ndb_value[0],
- blobs_buffer[0], blobs_buffer_size[0],
- ptrdiff);
+ IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[0],
+ blobs_buffer[0],
+ blobs_buffer_size[0],
+ ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[0], &b, table->record[0]);
- int ret= trans.write_row(::server_id,
- injector::transaction::table(table, TRUE),
- &b, n_fields, table->record[0]);
+ IF_DBUG(int ret=) trans.write_row(::server_id,
+ injector::transaction::table(table,
+ TRUE),
+ &b, n_fields, table->record[0]);
DBUG_ASSERT(ret == 0);
}
break;
@@ -3169,27 +3253,29 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
n= 0; /*
use the primary key only as it save time and space and
it is the only thing needed to log the delete
- */
+ */
else
n= 1; /*
we use the before values since we don't have a primary key
since the mysql server does not handle the hidden primary
key
- */
+ */
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= table->record[n] - table->record[0];
- int ret= get_ndb_blobs_value(table, share->ndb_value[n],
- blobs_buffer[n], blobs_buffer_size[n],
- ptrdiff);
+ IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[n],
+ blobs_buffer[n],
+ blobs_buffer_size[n],
+ ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[n], &b, table->record[n]);
DBUG_EXECUTE("info", print_records(table, table->record[n]););
- int ret= trans.delete_row(::server_id,
- injector::transaction::table(table, TRUE),
- &b, n_fields, table->record[n]);
+ IF_DBUG(int ret =) trans.delete_row(::server_id,
+ injector::transaction::table(table,
+ TRUE),
+ &b, n_fields, table->record[n]);
DBUG_ASSERT(ret == 0);
}
break;
@@ -3201,9 +3287,10 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= 0;
- int ret= get_ndb_blobs_value(table, share->ndb_value[0],
- blobs_buffer[0], blobs_buffer_size[0],
- ptrdiff);
+ IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[0],
+ blobs_buffer[0],
+ blobs_buffer_size[0],
+ ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[0],
@@ -3214,7 +3301,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
/*
since table has a primary key, we can do a write
using only after values
- */
+ */
trans.write_row(::server_id, injector::transaction::table(table, TRUE),
&b, n_fields, table->record[0]);// after values
}
@@ -3223,22 +3310,24 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
/*
mysql server cannot handle the ndb hidden key and
therefore needs the before image as well
- */
+ */
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= table->record[1] - table->record[0];
- int ret= get_ndb_blobs_value(table, share->ndb_value[1],
- blobs_buffer[1], blobs_buffer_size[1],
- ptrdiff);
+ IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[1],
+ blobs_buffer[1],
+ blobs_buffer_size[1],
+ ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[1], &b, table->record[1]);
DBUG_EXECUTE("info", print_records(table, table->record[1]););
- int ret= trans.update_row(::server_id,
- injector::transaction::table(table, TRUE),
- &b, n_fields,
- table->record[1], // before values
- table->record[0]);// after values
+ IF_DBUG(int ret =) trans.update_row(::server_id,
+ injector::transaction::table(table,
+ TRUE),
+ &b, n_fields,
+ table->record[1], // before values
+ table->record[0]);// after values
DBUG_ASSERT(ret == 0);
}
}
@@ -3414,7 +3503,6 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
thd->command= COM_DAEMON;
thd->system_thread= SYSTEM_THREAD_NDBCLUSTER_BINLOG;
thd->version= refresh_version;
- thd->set_time();
thd->main_security_ctx.host_or_ip= "";
thd->client_capabilities= 0;
my_net_init(&thd->net, 0);
@@ -3437,6 +3525,9 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
s_ndb->init())
{
sql_print_error("NDB Binlog: Getting Schema Ndb object failed");
+ ndb_binlog_thread_running= -1;
+ pthread_mutex_unlock(&injector_mutex);
+ pthread_cond_signal(&injector_cond);
goto err;
}
@@ -3467,7 +3558,7 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
p_latest_trans_gci=
injector_ndb->get_ndb_cluster_connection().get_latest_trans_gci();
schema_ndb= s_ndb;
- ndb_binlog_thread_running= 1;
+
if (opt_bin_log)
{
if (global_system_variables.binlog_format == BINLOG_FORMAT_ROW ||
@@ -3480,10 +3571,9 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
sql_print_error("NDB: only row based binary logging is supported");
}
}
- /*
- We signal the thread that started us that we've finished
- starting up.
- */
+
+ /* Thread start up completed */
+ ndb_binlog_thread_running= 1;
pthread_mutex_unlock(&injector_mutex);
pthread_cond_signal(&injector_cond);
@@ -3502,7 +3592,7 @@ restart:
struct timespec abstime;
set_timespec(abstime, 1);
pthread_cond_timedwait(&injector_cond, &injector_mutex, &abstime);
- if (abort_loop)
+ if (ndbcluster_binlog_terminating)
{
pthread_mutex_unlock(&injector_mutex);
goto err;
@@ -3527,13 +3617,15 @@ restart:
{
// wait for the first event
thd->proc_info= "Waiting for first event from ndbcluster";
- DBUG_PRINT("info", ("Waiting for the first event"));
int schema_res, res;
Uint64 schema_gci;
do
{
- if (abort_loop)
+ DBUG_PRINT("info", ("Waiting for the first event"));
+
+ if (ndbcluster_binlog_terminating)
goto err;
+
schema_res= s_ndb->pollEvents(100, &schema_gci);
} while (schema_gci == 0 || ndb_latest_received_binlog_epoch == schema_gci);
if (ndb_binlog_running)
@@ -3541,7 +3633,7 @@ restart:
Uint64 gci= i_ndb->getLatestGCI();
while (gci < schema_gci || gci == ndb_latest_received_binlog_epoch)
{
- if (abort_loop)
+ if (ndbcluster_binlog_terminating)
goto err;
res= i_ndb->pollEvents(10, &gci);
}
@@ -3588,7 +3680,8 @@ restart:
thd->db= db;
}
do_ndbcluster_binlog_close_connection= BCCC_running;
- for ( ; !((abort_loop || do_ndbcluster_binlog_close_connection) &&
+ for ( ; !((ndbcluster_binlog_terminating ||
+ do_ndbcluster_binlog_close_connection) &&
ndb_latest_handled_binlog_epoch >= *p_latest_trans_gci) &&
do_ndbcluster_binlog_close_connection != BCCC_restart; )
{
@@ -3635,7 +3728,8 @@ restart:
schema_res= s_ndb->pollEvents(10, &schema_gci);
}
- if ((abort_loop || do_ndbcluster_binlog_close_connection) &&
+ if ((ndbcluster_binlog_terminating ||
+ do_ndbcluster_binlog_close_connection) &&
(ndb_latest_handled_binlog_epoch >= *p_latest_trans_gci ||
!ndb_binlog_running))
break; /* Shutting down server */
@@ -3762,7 +3856,9 @@ restart:
continue;
}
TABLE *table= share->table;
+#ifndef DBUG_OFF
const LEX_STRING &name= table->s->table_name;
+#endif
if ((event_types & (NdbDictionary::Event::TE_INSERT |
NdbDictionary::Event::TE_UPDATE |
NdbDictionary::Event::TE_DELETE)) == 0)
@@ -3779,7 +3875,7 @@ restart:
}
DBUG_PRINT("info", ("use_table: %.*s", name.length, name.str));
injector::transaction::table tbl(table, TRUE);
- int ret= trans.use_table(::server_id, tbl);
+ IF_DBUG(int ret=) trans.use_table(::server_id, tbl);
DBUG_ASSERT(ret == 0);
}
}
@@ -3789,10 +3885,12 @@ restart:
{
TABLE *table= ndb_apply_status_share->table;
- const LEX_STRING& name=table->s->table_name;
+#ifndef DBUG_OFF
+ const LEX_STRING& name= table->s->table_name;
DBUG_PRINT("info", ("use_table: %.*s", name.length, name.str));
+#endif
injector::transaction::table tbl(table, TRUE);
- int ret= trans.use_table(::server_id, tbl);
+ IF_DBUG(int ret=) trans.use_table(::server_id, tbl);
DBUG_ASSERT(ret == 0);
// Set all fields non-null.
@@ -3857,7 +3955,7 @@ restart:
else
{
// set injector_ndb database/schema from table internal name
- int ret=
+ IF_DBUG(int ret=)
i_ndb->setDatabaseAndSchemaName(pOp->getEvent()->getTable());
DBUG_ASSERT(ret == 0);
ndb_binlog_thread_handle_non_data_event(thd, i_ndb, pOp, row);
@@ -3891,7 +3989,7 @@ restart:
/*
note! pOp is not referring to an event in the next epoch
or is == 0
- */
+ */
#ifdef RUN_NDB_BINLOG_TIMER
write_timer.stop();
#endif
@@ -3924,9 +4022,9 @@ restart:
"%ld(%d e/s), total time %ld(%d e/s)",
(ulong)gci, event_count,
write_timer.elapsed_ms(),
- event_count / write_timer.elapsed_ms(),
+ (1000*event_count) / write_timer.elapsed_ms(),
gci_timer.elapsed_ms(),
- event_count / gci_timer.elapsed_ms());
+ (1000*event_count) / gci_timer.elapsed_ms());
#endif
}
}
@@ -3961,13 +4059,25 @@ err:
if (ndb_apply_status_share)
{
+ /* ndb_share reference binlog extra free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u",
+ ndb_apply_status_share->key,
+ ndb_apply_status_share->use_count));
free_share(&ndb_apply_status_share);
ndb_apply_status_share= 0;
}
if (ndb_schema_share)
{
+ /* begin protect ndb_schema_share */
+ pthread_mutex_lock(&ndb_schema_share_mutex);
+ /* ndb_share reference binlog extra free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u",
+ ndb_schema_share->key,
+ ndb_schema_share->use_count));
free_share(&ndb_schema_share);
ndb_schema_share= 0;
+ pthread_mutex_unlock(&ndb_schema_share_mutex);
+ /* end protect ndb_schema_share */
}
/* remove all event operations */
@@ -3985,6 +4095,9 @@ err:
DBUG_ASSERT(share->op == op ||
share->op_old == op);
share->op= share->op_old= 0;
+ /* ndb_share reference binlog free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
s_ndb->dropEventOperation(op);
}
@@ -4005,6 +4118,9 @@ err:
DBUG_ASSERT(share->op == op ||
share->op_old == op);
share->op= share->op_old= 0;
+ /* ndb_share reference binlog free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
i_ndb->dropEventOperation(op);
}
diff --git a/sql/ha_ndbcluster_binlog.h b/sql/ha_ndbcluster_binlog.h
index 44183c6de9d..00fc689f061 100644
--- a/sql/ha_ndbcluster_binlog.h
+++ b/sql/ha_ndbcluster_binlog.h
@@ -208,11 +208,6 @@ inline void free_share(NDB_SHARE **share, bool have_lock= FALSE)
ndbcluster_free_share(share, have_lock);
}
-inline void real_free_share(NDB_SHARE **share)
-{
- ndbcluster_real_free_share(share);
-}
-
inline
Thd_ndb *
get_thd_ndb(THD *thd) { return (Thd_ndb *) thd->ha_data[ndbcluster_hton->slot]; }
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index feb08f474b7..db0d118c2e0 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -158,7 +158,7 @@ static uint alter_table_flags(uint flags __attribute__((unused)))
ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share)
:handler(hton, share), m_part_info(NULL), m_create_handler(FALSE),
- m_is_sub_partitioned(0)
+ m_is_sub_partitioned(0), is_clone(FALSE)
{
DBUG_ENTER("ha_partition::ha_partition(table)");
init_handler_variables();
@@ -180,8 +180,7 @@ ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share)
ha_partition::ha_partition(handlerton *hton, partition_info *part_info)
:handler(hton, NULL), m_part_info(part_info),
m_create_handler(TRUE),
- m_is_sub_partitioned(m_part_info->is_sub_partitioned())
-
+ m_is_sub_partitioned(m_part_info->is_sub_partitioned()), is_clone(FALSE)
{
DBUG_ENTER("ha_partition::ha_partition(part_info)");
init_handler_variables();
@@ -584,7 +583,6 @@ int ha_partition::drop_partitions(const char *path)
List_iterator<partition_element> part_it(m_part_info->partitions);
char part_name_buff[FN_REFLEN];
uint no_parts= m_part_info->partitions.elements;
- uint part_count= 0;
uint no_subparts= m_part_info->no_subparts;
uint i= 0;
uint name_variant;
@@ -1075,7 +1073,6 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
uint no_parts= m_part_info->no_parts;
uint no_subparts= m_part_info->no_subparts;
uint i= 0;
- LEX *lex= thd->lex;
int error;
DBUG_ENTER("ha_partition::handle_opt_partitions");
DBUG_PRINT("enter", ("all_parts %u, flag= %u", all_parts, flag));
@@ -1087,11 +1084,9 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
{
if (m_is_sub_partitioned)
{
- List_iterator<partition_element> sub_it(part_elem->subpartitions);
uint j= 0, part;
do
{
- partition_element *sub_elem= sub_it++;
part= i * no_subparts + j;
DBUG_PRINT("info", ("Optimize subpartition %u",
part));
@@ -1136,7 +1131,6 @@ int ha_partition::prepare_new_partition(TABLE *table,
{
int error;
bool create_flag= FALSE;
- bool open_flag= FALSE;
DBUG_ENTER("prepare_new_partition");
if ((error= set_up_table_before_create(table, part_name, create_info,
@@ -1245,7 +1239,6 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
handler **new_file_array;
int error= 1;
bool first;
- bool copy_parts= FALSE;
uint temp_partitions= m_part_info->temp_partitions.elements;
THD *thd= current_thd;
DBUG_ENTER("ha_partition::change_partitions");
@@ -2061,7 +2054,6 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root)
partition_element *part_elem;
uint alloc_len= (m_tot_parts + 1) * sizeof(handler*);
List_iterator_fast <partition_element> part_it(m_part_info->partitions);
- THD *thd= current_thd;
DBUG_ENTER("ha_partition::new_handlers_from_part_info");
if (!(m_file= (handler **) alloc_root(mem_root, alloc_len)))
@@ -2269,9 +2261,12 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
}
/* Initialise the bitmap we use to determine what partitions are used */
- if (bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE))
- DBUG_RETURN(1);
- bitmap_set_all(&(m_part_info->used_partitions));
+ if (!is_clone)
+ {
+ if (bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE))
+ DBUG_RETURN(1);
+ bitmap_set_all(&(m_part_info->used_partitions));
+ }
/* Recalculate table flags as they may change after open */
m_table_flags= m_file[0]->table_flags();
@@ -2327,6 +2322,19 @@ err_handler:
DBUG_RETURN(error);
}
+handler *ha_partition::clone(MEM_ROOT *mem_root)
+{
+ handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type);
+ ((ha_partition*)new_handler)->m_part_info= m_part_info;
+ ((ha_partition*)new_handler)->is_clone= TRUE;
+ if (new_handler && !new_handler->ha_open(table,
+ table->s->normalized_path.str,
+ table->db_stat,
+ HA_OPEN_IGNORE_IF_LOCKED))
+ return new_handler;
+ return NULL;
+}
+
/*
Close handler object
@@ -2353,7 +2361,8 @@ int ha_partition::close(void)
DBUG_ENTER("ha_partition::close");
delete_queue(&m_queue);
- bitmap_free(&(m_part_info->used_partitions));
+ if (!is_clone)
+ bitmap_free(&(m_part_info->used_partitions));
file= m_file;
repeat:
@@ -4015,6 +4024,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order)
m_queue.elements= j;
queue_fix(&m_queue);
return_top_record(buf);
+ table->status= 0;
DBUG_PRINT("info", ("Record returned from partition %d", m_top_entry));
DBUG_RETURN(0);
}
@@ -4083,6 +4093,7 @@ int ha_partition::handle_ordered_next(byte *buf, bool is_next_same)
DBUG_PRINT("info", ("Record returned from partition %u (2)",
m_top_entry));
return_top_record(buf);
+ table->status= 0;
error= 0;
}
}
@@ -4126,6 +4137,7 @@ int ha_partition::handle_ordered_prev(byte *buf)
DBUG_PRINT("info", ("Record returned from partition %d (2)",
m_top_entry));
error= 0;
+ table->status= 0;
}
}
DBUG_RETURN(error);
@@ -4470,7 +4482,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
2) It is called from close_thread_table which in turn is called from
close_thread_tables except in the case where the tables are locked
in which case ha_commit_stmt is called instead.
- It is only called from here if flush_version hasn't changed and the
+ It is only called from here if refresh_version hasn't changed and the
table is not an old table when calling close_thread_table.
close_thread_tables is called from many places as a general clean up
function after completing a query.
@@ -4491,8 +4503,9 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
The handler will set HA_KEYREAD_ONLY in its table flags to indicate this
feature is supported.
HA_EXTRA_FLUSH:
- Indication to flush tables to disk, called at close_thread_table to
+ Indication to flush tables to disk, is supposed to be used to
ensure disk based tables are flushed at end of query execution.
+ Currently is never used.
2) Parameters used by some non-MyISAM handlers
----------------------------------------------
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 4fdf325fa06..1069dd058d5 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -132,7 +132,13 @@ private:
THR_LOCK_DATA lock; /* MySQL lock */
PARTITION_SHARE *share; /* Shared lock info */
+ /*
+ TRUE <=> this object was created with ha_partition::clone and doesn't
+ "own" the m_part_info structure.
+ */
+ bool is_clone;
public:
+ handler *clone(MEM_ROOT *mem_root);
virtual void set_part_info(partition_info *part_info)
{
m_part_info= part_info;
diff --git a/sql/handler.cc b/sql/handler.cc
index c596556fc98..23c3103493e 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -13,8 +13,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/** @file handler.cc
-/* Handler-calling-functions */
+ @brief
+ Handler-calling-functions
+*/
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
@@ -44,12 +47,6 @@ static handlerton *installed_htons[128];
KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NullS,0} };
-/* static functions defined in this file */
-
-static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root);
-
-static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
-
/* number of entries in handlertons[] */
ulong total_ha= 0;
/* number of storage engines (from handlertons[]) that support 2pc */
@@ -80,17 +77,16 @@ static TYPELIB known_extensions= {0,"known_exts", NULL, NULL};
uint known_extensions_id= 0;
-/*
+/** @brief
Return the default storage engine handlerton for thread
-
+
SYNOPSIS
ha_default_handlerton(thd)
thd current thread
-
+
RETURN
pointer to handlerton
*/
-
handlerton *ha_default_handlerton(THD *thd)
{
return (thd->variables.table_type != NULL) ?
@@ -100,7 +96,7 @@ handlerton *ha_default_handlerton(THD *thd)
}
-/*
+/** @brief
Return the storage engine handlerton for the supplied name
SYNOPSIS
@@ -111,7 +107,6 @@ handlerton *ha_default_handlerton(THD *thd)
RETURN
pointer to handlerton
*/
-
handlerton *ha_resolve_by_name(THD *thd, const LEX_STRING *name)
{
const LEX_STRING *table_alias;
@@ -166,11 +161,13 @@ const char *ha_get_storage_engine(enum legacy_db_type db_type)
}
+#ifdef NOT_USED
static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
handlerton *hton= ha_default_handlerton(current_thd);
return (hton && hton->create) ? hton->create(hton, table, mem_root) : NULL;
}
+#endif
handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type)
@@ -188,8 +185,9 @@ handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type)
}
-/* Use other database handler if databasehandler is not compiled in */
-
+/** @brief
+ Use other database handler if databasehandler is not compiled in
+*/
handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
bool no_substitute, bool report_error)
{
@@ -269,7 +267,7 @@ handler *get_ha_partition(partition_info *part_info)
#endif
-/*
+/** @brief
Register handler error messages for use with my_error().
SYNOPSIS
@@ -279,7 +277,6 @@ handler *get_ha_partition(partition_info *part_info)
0 OK
!= 0 Error
*/
-
static int ha_init_errors(void)
{
#define SETMSG(nr, msg) errmsgs[(nr) - HA_ERR_FIRST]= (msg)
@@ -339,7 +336,7 @@ static int ha_init_errors(void)
}
-/*
+/** @brief
Unregister handler error messages.
SYNOPSIS
@@ -349,7 +346,6 @@ static int ha_init_errors(void)
0 OK
!= 0 Error
*/
-
static int ha_finish_errors(void)
{
const char **errmsgs;
@@ -557,7 +553,9 @@ static my_bool closecon_handlerton(THD *thd, st_plugin_int *plugin,
}
-/* don't bother to rollback here, it's done already */
+/** @brief
+ don't bother to rollback here, it's done already
+*/
void ha_close_connection(THD* thd)
{
plugin_foreach(thd, closecon_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, 0);
@@ -566,7 +564,7 @@ void ha_close_connection(THD* thd)
/* ========================================================================
======================= TRANSACTIONS ===================================*/
-/*
+/** @brief
Register a storage engine for a transaction
DESCRIPTION
@@ -608,7 +606,7 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
DBUG_VOID_RETURN;
}
-/*
+/** @brief
RETURN
0 - ok
1 - error, transaction was rolled back
@@ -648,7 +646,7 @@ int ha_prepare(THD *thd)
DBUG_RETURN(error);
}
-/*
+/** @brief
RETURN
0 - ok
1 - transaction was rolled back
@@ -724,7 +722,7 @@ int ha_commit_trans(THD *thd, bool all)
}
DBUG_EXECUTE_IF("crash_commit_after_prepare", abort(););
if (error || (is_real_trans && xid &&
- (error= !(cookie= tc_log->log(thd, xid)))))
+ (error= !(cookie= tc_log->log_xid(thd, xid)))))
{
ha_rollback_trans(thd, all);
error= 1;
@@ -732,7 +730,7 @@ int ha_commit_trans(THD *thd, bool all)
}
DBUG_EXECUTE_IF("crash_commit_after_log", abort(););
}
- error=ha_commit_one_phase(thd, all) ? cookie ? 2 : 1 : 0;
+ error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0;
DBUG_EXECUTE_IF("crash_commit_before_unlog", abort(););
if (cookie)
tc_log->unlog(cookie, xid);
@@ -745,7 +743,7 @@ end:
DBUG_RETURN(error);
}
-/*
+/** @brief
NOTE - this function does not care about global read lock.
A caller should.
*/
@@ -847,14 +845,14 @@ int ha_rollback_trans(THD *thd, bool all)
message in the error log, so we don't send it.
*/
if (is_real_trans && (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
- !thd->slave_thread)
+ !thd->slave_thread && thd->killed != THD::KILL_CONNECTION)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
DBUG_RETURN(error);
}
-/*
+/** @brief
This is used to commit or rollback a single statement depending on the value
of error. Note that if the autocommit is on, then the following call inside
InnoDB will commit or rollback the whole transaction (= the statement). The
@@ -862,7 +860,6 @@ int ha_rollback_trans(THD *thd, bool all)
the user has used LOCK TABLES then that mechanism does not know to do the
commit.
*/
-
int ha_autocommit_or_rollback(THD *thd, int error)
{
DBUG_ENTER("ha_autocommit_or_rollback");
@@ -980,7 +977,7 @@ static char* xid_to_str(char *buf, XID *xid)
}
#endif
-/*
+/** @brief
recover() step of xa
NOTE
@@ -999,7 +996,6 @@ static char* xid_to_str(char *buf, XID *xid)
in this case commit_list==0, tc_heuristic_recover == 0
there should be no prepared transactions in this case.
*/
-
struct xarecover_st
{
int len, found_foreign_xids, found_my_xids;
@@ -1131,7 +1127,7 @@ int ha_recover(HASH *commit_list)
DBUG_RETURN(0);
}
-/*
+/** @brief
return the list of XID's to a client, the same way SHOW commands do
NOTE
@@ -1180,7 +1176,7 @@ bool mysql_xa_recover(THD *thd)
DBUG_RETURN(0);
}
-/*
+/** @brief
This function should be called when MySQL sends rows of a SELECT result set
or the EOF mark to the client. It releases a possible adaptive hash index
S-latch held by thd in InnoDB and also releases a possible InnoDB query
@@ -1196,7 +1192,6 @@ bool mysql_xa_recover(THD *thd)
thd: the thread handle of the current connection
return value: always 0
*/
-
static my_bool release_temporary_latches(THD *thd, st_plugin_int *plugin,
void *unused)
{
@@ -1263,12 +1258,11 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
DBUG_RETURN(error);
}
-/*
+/** @brief
note, that according to the sql standard (ISO/IEC 9075-2:2003)
section "4.33.4 SQL-statements and transaction states",
SAVEPOINT is *not* transaction-initiating SQL-statement
*/
-
int ha_savepoint(THD *thd, SAVEPOINT *sv)
{
int error=0;
@@ -1383,11 +1377,10 @@ bool ha_flush_logs(handlerton *db_type)
return FALSE;
}
-/*
+/** @brief
This should return ENOENT if the file doesn't exists.
The .frm file will be deleted only if we return 0 or ENOENT
*/
-
int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
const char *db, const char *alias, bool generate_warning)
{
@@ -1510,14 +1503,13 @@ bool handler::check_if_log_table_locking_is_allowed(uint sql_command,
return TRUE;
}
-/*
+/** @brief
Open database-handler.
IMPLEMENTATION
Try O_RDONLY if cannot open as O_RDWR
Don't wait for locks if not HA_OPEN_WAIT_IF_LOCKED is set
*/
-
int handler::ha_open(TABLE *table_arg, const char *name, int mode,
int test_if_locked)
{
@@ -1565,12 +1557,11 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
}
-/*
+/** @brief
Read first row (only) from a table
This is never called for InnoDB tables, as these table types
has the HA_STATS_RECORDS_IS_EXACT set.
*/
-
int handler::read_first_row(byte * buf, uint primary_key)
{
register int error;
@@ -1601,7 +1592,7 @@ int handler::read_first_row(byte * buf, uint primary_key)
DBUG_RETURN(error);
}
-/*
+/** @brief
Generate the next auto-increment number based on increment and offset:
computes the lowest number
- strictly greater than "nr"
@@ -1612,7 +1603,6 @@ int handler::read_first_row(byte * buf, uint primary_key)
If increment=10 and offset=5 and previous number is 1, we get:
1,5,15,25,35,...
*/
-
inline ulonglong
compute_next_insert_id(ulonglong nr,struct system_variables *variables)
{
@@ -1638,7 +1628,7 @@ void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr)
}
-/*
+/** @brief
Computes the largest number X:
- smaller than or equal to "nr"
- of the form: auto_increment_offset + N * auto_increment_increment
@@ -1653,7 +1643,6 @@ void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr)
RETURN
The number X if it exists, "nr" otherwise.
*/
-
inline ulonglong
prev_insert_id(ulonglong nr, struct system_variables *variables)
{
@@ -1922,7 +1911,7 @@ int handler::update_auto_increment()
}
-/*
+/** @brief
MySQL signal that it changed the column bitmap
USAGE
@@ -1935,7 +1924,6 @@ int handler::update_auto_increment()
rnd_init() call is made as after this, MySQL will not use the bitmap
for any program logic checking.
*/
-
void handler::column_bitmaps_signal()
{
DBUG_ENTER("column_bitmaps_signal");
@@ -1945,7 +1933,7 @@ void handler::column_bitmaps_signal()
}
-/*
+/** @brief
Reserves an interval of auto_increment values from the handler.
SYNOPSIS
@@ -1962,7 +1950,6 @@ void handler::column_bitmaps_signal()
If the function sets *nb_reserved_values to ULONGLONG_MAX it means it has
reserved to "positive infinite".
*/
-
void handler::get_auto_increment(ulonglong offset, ulonglong increment,
ulonglong nb_desired_values,
ulonglong *first_value,
@@ -2060,7 +2047,7 @@ void handler::print_keydup_error(uint key_nr, const char *msg)
}
-/*
+/** @brief
Print error that we got from handler function
NOTE
@@ -2069,7 +2056,6 @@ void handler::print_keydup_error(uint key_nr, const char *msg)
table->s->path
table->alias
*/
-
void handler::print_error(int error, myf errflag)
{
DBUG_ENTER("handler::print_error");
@@ -2255,7 +2241,7 @@ void handler::print_error(int error, myf errflag)
}
-/*
+/** @brief
Return an error message specific to this handler
SYNOPSIS
@@ -2263,8 +2249,7 @@ void handler::print_error(int error, myf errflag)
buf Pointer to String where to add error message
Returns true if this is a temporary error
- */
-
+*/
bool handler::get_error_message(int error, String* buf)
{
return FALSE;
@@ -2326,7 +2311,7 @@ int handler::check_old_types()
}
-static bool update_frm_version(TABLE *table, bool needs_lock)
+static bool update_frm_version(TABLE *table)
{
char path[FN_REFLEN];
File file;
@@ -2338,9 +2323,6 @@ static bool update_frm_version(TABLE *table, bool needs_lock)
strxmov(path, table->s->normalized_path.str, reg_ext, NullS);
- if (needs_lock)
- pthread_mutex_lock(&LOCK_open);
-
if ((file= my_open(path, O_RDWR|O_BINARY, MYF(MY_WME))) >= 0)
{
uchar version[4];
@@ -2362,15 +2344,13 @@ static bool update_frm_version(TABLE *table, bool needs_lock)
err:
if (file >= 0)
VOID(my_close(file,MYF(MY_WME)));
- if (needs_lock)
- pthread_mutex_unlock(&LOCK_open);
DBUG_RETURN(result);
}
-/* Return key if error because of duplicated keys */
-
+/** @brief
+ Return key if error because of duplicated keys */
uint handler::get_dup_key(int error)
{
DBUG_ENTER("handler::get_dup_key");
@@ -2383,7 +2363,7 @@ uint handler::get_dup_key(int error)
}
-/*
+/** @brief
Delete all files with extension from bas_ext()
SYNOPSIS
@@ -2399,7 +2379,6 @@ uint handler::get_dup_key(int error)
didn't get any other errors than ENOENT
# Error
*/
-
int handler::delete_table(const char *name)
{
int error= 0;
@@ -2445,7 +2424,7 @@ void handler::drop_table(const char *name)
}
-/*
+/** @brief
Performs checks upon the table.
SYNOPSIS
@@ -2461,7 +2440,6 @@ void handler::drop_table(const char *name)
HA_ADMIN_NEEDS_ALTER Table has structures requiring ALTER TABLE
HA_ADMIN_NOT_IMPLEMENTED
*/
-
int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt)
{
int error;
@@ -2482,7 +2460,7 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt)
}
if ((error= check(thd, check_opt)))
return error;
- return update_frm_version(table, 0);
+ return update_frm_version(table);
}
@@ -2491,11 +2469,11 @@ int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt)
int result;
if ((result= repair(thd, check_opt)))
return result;
- return update_frm_version(table, 0);
+ return update_frm_version(table);
}
-/*
+/** @brief
Tell the storage engine that it is allowed to "disable transaction" in the
handler. It is a hint that ACID is not required - it is used in NDB for
ALTER TABLE, for example, when data are copied to temporary table.
@@ -2503,7 +2481,6 @@ int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt)
starts to commit every now and then automatically.
This hint can be safely ignored.
*/
-
int ha_enable_transaction(THD *thd, bool on)
{
int error=0;
@@ -2564,7 +2541,7 @@ void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info,
** Some general functions that isn't in the handler class
****************************************************************************/
-/*
+/** @brief
Initiates table-file and calls appropriate database-creator
NOTES
@@ -2575,7 +2552,6 @@ void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info,
0 ok
1 error
*/
-
int ha_create_table(THD *thd, const char *path,
const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
@@ -2619,7 +2595,7 @@ err:
DBUG_RETURN(error != 0);
}
-/*
+/** @brief
Try to discover table from engine
NOTES
@@ -2631,7 +2607,6 @@ err:
> 0 Error, table existed but could not be created
*/
-
int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
{
int error;
@@ -2706,9 +2681,9 @@ void st_ha_check_opt::init()
call to ha_init_key_cache() (probably out of memory)
*****************************************************************************/
-/* Init a key cache if it has not been initied before */
-
-
+/** @brief
+ Init a key cache if it has not been initied before
+*/
int ha_init_key_cache(const char *name, KEY_CACHE *key_cache)
{
DBUG_ENTER("ha_init_key_cache");
@@ -2730,8 +2705,9 @@ int ha_init_key_cache(const char *name, KEY_CACHE *key_cache)
}
-/* Resize key cache */
-
+/** @brief
+ Resize key cache
+*/
int ha_resize_key_cache(KEY_CACHE *key_cache)
{
DBUG_ENTER("ha_resize_key_cache");
@@ -2752,8 +2728,9 @@ int ha_resize_key_cache(KEY_CACHE *key_cache)
}
-/* Change parameters for key cache (like size) */
-
+/** @brief
+ Change parameters for key cache (like size)
+*/
int ha_change_key_cache_param(KEY_CACHE *key_cache)
{
if (key_cache->key_cache_inited)
@@ -2767,16 +2744,18 @@ int ha_change_key_cache_param(KEY_CACHE *key_cache)
return 0;
}
-/* Free memory allocated by a key cache */
-
+/** @brief
+ Free memory allocated by a key cache
+*/
int ha_end_key_cache(KEY_CACHE *key_cache)
{
end_key_cache(key_cache, 1); // Can never fail
return 0;
}
-/* Move all tables from one key cache to another one */
-
+/** @brief
+ Move all tables from one key cache to another one
+*/
int ha_change_key_cache(KEY_CACHE *old_key_cache,
KEY_CACHE *new_key_cache)
{
@@ -2785,7 +2764,7 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache,
}
-/*
+/** @brief
Try to discover one table from handler(s)
RETURN
@@ -2793,7 +2772,6 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache,
0 : OK. In this case *frmblob and *frmlen are set
>0 : error. frmblob and frmlen may not be set
*/
-
struct st_discover_args
{
const char *db;
@@ -2837,7 +2815,7 @@ int ha_discover(THD *thd, const char *db, const char *name,
}
-/*
+/** @brief
Call this function in order to give the handler the possibility
to ask engine if there are any new tables that should be written to disk
or any dropped tables that need to be removed from disk
@@ -2872,8 +2850,8 @@ ha_find_files(THD *thd,const char *db,const char *path,
{
int error= 0;
DBUG_ENTER("ha_find_files");
- DBUG_PRINT("enter", ("db: %s, path: %s, wild: %s, dir: %d",
- db, path, wild, dir));
+ DBUG_PRINT("enter", ("db: '%s' path: '%s' wild: '%s' dir: %d",
+ db, path, wild ? wild : "NULL", dir));
st_find_files_args args= {db, path, wild, dir, files};
plugin_foreach(thd, find_files_handlerton,
@@ -2883,7 +2861,7 @@ ha_find_files(THD *thd,const char *db,const char *path,
}
-/*
+/** @brief
Ask handler if the table exists in engine
RETURN
@@ -2891,8 +2869,7 @@ ha_find_files(THD *thd,const char *db,const char *path,
1 Table exists
# Error code
- */
-
+*/
struct st_table_exists_in_engine_args
{
const char *db;
@@ -2944,7 +2921,7 @@ struct binlog_func_st
void *arg;
};
-/*
+/** @brief
Listing handlertons first to avoid recursive calls and deadlock
*/
static my_bool binlog_func_list(THD *thd, st_plugin_int *plugin, void *arg)
@@ -3062,7 +3039,7 @@ void ha_binlog_log_query(THD *thd, handlerton *hton,
}
#endif
-/*
+/** @brief
Read the first row of a multi-range set.
SYNOPSIS
@@ -3086,7 +3063,6 @@ void ha_binlog_log_query(THD *thd, handlerton *hton,
HA_ERR_END_OF_FILE No rows in range
# Error code
*/
-
int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
KEY_MULTI_RANGE *ranges, uint range_count,
bool sorted, HANDLER_BUFFER *buffer)
@@ -3119,7 +3095,7 @@ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
}
-/*
+/** @brief
Read the next row of a multi-range set.
SYNOPSIS
@@ -3137,7 +3113,6 @@ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
HA_ERR_END_OF_FILE No (more) rows in range
# Error code
*/
-
int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
{
int result;
@@ -3190,7 +3165,7 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
}
-/*
+/** @brief
Read first row between two ranges.
Store ranges for future calls to read_range_next
@@ -3209,7 +3184,6 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
HA_ERR_END_OF_FILE No rows in range
# Error code
*/
-
int handler::read_range_first(const key_range *start_key,
const key_range *end_key,
bool eq_range_arg, bool sorted)
@@ -3244,7 +3218,7 @@ int handler::read_range_first(const key_range *start_key,
}
-/*
+/** @brief
Read next row between two ranges.
SYNOPSIS
@@ -3258,7 +3232,6 @@ int handler::read_range_first(const key_range *start_key,
HA_ERR_END_OF_FILE No rows in range
# Error code
*/
-
int handler::read_range_next()
{
int result;
@@ -3278,7 +3251,7 @@ int handler::read_range_next()
}
-/*
+/** @brief
Compare if found key (in row) is over max-value
SYNOPSIS
@@ -3295,7 +3268,6 @@ int handler::read_range_next()
-1 Key is less than range
1 Key is larger than range
*/
-
int handler::compare_key(key_range *range)
{
int cmp;
@@ -3319,7 +3291,7 @@ int handler::index_read_idx(byte * buf, uint index, const byte * key,
}
-/*
+/** @brief
Returns a list of all known extensions.
SYNOPSIS
@@ -3333,7 +3305,6 @@ int handler::index_read_idx(byte * buf, uint index, const byte * key,
RETURN VALUE
pointer pointer to TYPELIB structure
*/
-
static my_bool exts_handlerton(THD *unused, st_plugin_int *plugin,
void *arg)
{
@@ -3365,7 +3336,6 @@ static my_bool exts_handlerton(THD *unused, st_plugin_int *plugin,
TYPELIB *ha_known_exts(void)
{
- MEM_ROOT *mem_root= current_thd->mem_root;
if (!known_extensions.type_names || mysys_usage_id != known_extensions_id)
{
List<char> found_exts;
@@ -3481,7 +3451,7 @@ namespace {
{
int const check(table->s->tmp_table == NO_TMP_TABLE &&
binlog_filter->db_ok(table->s->db.str) &&
- strcmp("mysql", table->s->db.str) != 0);
+ !table->no_replicate);
table->s->cached_row_logging_check= check;
}
@@ -3495,7 +3465,7 @@ namespace {
}
}
-/*
+/** @brief
Write table maps for all (manually or automatically) locked tables
to the binary log.
@@ -3516,7 +3486,7 @@ namespace {
SEE ALSO
THD::lock
THD::locked_tables
- */
+*/
namespace
{
int write_locked_table_maps(THD *thd)
@@ -3639,10 +3609,9 @@ int handler::ha_external_lock(THD *thd, int lock_type)
}
-/*
+/** @brief
Check handler usage and reset state of file to after 'open'
*/
-
int handler::ha_reset()
{
DBUG_ENTER("ha_reset");
@@ -3699,12 +3668,11 @@ int handler::ha_delete_row(const byte *buf)
-/*
+/** @brief
use_hidden_primary_key() is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key
*/
-
void handler::use_hidden_primary_key()
{
/* fallback to use all columns in the table to identify row */
@@ -3712,11 +3680,10 @@ void handler::use_hidden_primary_key()
}
-/*
+/** @brief
Dummy function which accept information about log files which is not need
by handlers
*/
-
void signal_log_not_needed(struct handlerton, char *log_file)
{
DBUG_ENTER("signal_log_not_needed");
@@ -3772,12 +3739,11 @@ err:
#define fl_dir FN_ROOTDIR
-/*
+/** @brief
Dummy function to return log status should be replaced by function which
really detect the log status and check that the file is a log of this
handler.
*/
-
enum log_status fl_get_log_status(char *log)
{
MY_STAT stat_buff;
@@ -3817,7 +3783,7 @@ void fl_log_iterator_destroy(struct handler_iterator *iterator)
}
-/*
+/** @brief
returns buffer, to be assigned in handler_iterator struct
*/
enum handler_create_iterator_result
diff --git a/sql/init.cc b/sql/init.cc
index e129f98547e..ff236c03204 100644
--- a/sql/init.cc
+++ b/sql/init.cc
@@ -45,5 +45,11 @@ void unireg_init(ulong options)
{ /* It's used by filesort... */
log_10[i]= nr ; nr*= 10.0;
}
+ /* Make a tab of powers of 0.1 */
+ for (i= 0, nr= 0.1; i < array_elements(log_01); i++)
+ {
+ log_01[i]= nr;
+ nr*= 0.1;
+ }
DBUG_VOID_RETURN;
}
diff --git a/sql/item.cc b/sql/item.cc
index 7ba5ab3e09d..a01a68de783 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -25,10 +25,6 @@
#include "sql_trigger.h"
#include "sql_select.h"
-static void mark_as_dependent(THD *thd,
- SELECT_LEX *last, SELECT_LEX *current,
- Item_ident *item);
-
const String my_null_string("NULL", 4, default_charset_info);
/****************************************************************************/
@@ -1270,7 +1266,10 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
if (type() == SUM_FUNC_ITEM && skip_registered &&
((Item_sum *) this)->ref_by)
return;
- if (type() != SUM_FUNC_ITEM && with_sum_func)
+ if ((type() != SUM_FUNC_ITEM && with_sum_func) ||
+ (type() == FUNC_ITEM &&
+ (((Item_func *) this)->functype() == Item_func::ISNOTNULLTEST_FUNC ||
+ ((Item_func *) this)->functype() == Item_func::TRIG_COND_FUNC)))
{
/* Will split complicated items and ignore simple ones */
split_sum_func(thd, ref_pointer_array, fields);
@@ -1554,6 +1553,8 @@ bool agg_item_charsets(DTCollation &coll, const char *fname,
doesn't display each argument's characteristics.
- if nargs is 1, then this error cannot happen.
*/
+ LINT_INIT(safe_args[0]);
+ LINT_INIT(safe_args[1]);
if (nargs >=2 && nargs <= 3)
{
safe_args[0]= args[0];
@@ -1638,7 +1639,7 @@ void Item_ident_for_show::make_field(Send_field *tmp_field)
Item_field::Item_field(Field *f)
:Item_ident(0, NullS, *f->table_name, f->field_name),
item_equal(0), no_const_subst(0),
- have_privileges(0), any_privileges(0)
+ have_privileges(0), any_privileges(0), fixed_as_field(0)
{
set_field(f);
/*
@@ -1653,7 +1654,7 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
Field *f)
:Item_ident(context_arg, f->table->s->db.str, *f->table_name, f->field_name),
item_equal(0), no_const_subst(0),
- have_privileges(0), any_privileges(0)
+ have_privileges(0), any_privileges(0), fixed_as_field(0)
{
/*
We always need to provide Item_field with a fully qualified field
@@ -1692,9 +1693,12 @@ Item_field::Item_field(Name_resolution_context *context_arg,
const char *field_name_arg)
:Item_ident(context_arg, db_arg,table_name_arg,field_name_arg),
field(0), result_field(0), item_equal(0), no_const_subst(0),
- have_privileges(0), any_privileges(0)
+ have_privileges(0), any_privileges(0), fixed_as_field(0)
{
+ SELECT_LEX *select= current_thd->lex->current_select;
collation.set(DERIVATION_IMPLICIT);
+ if (select && select->parsing_place != IN_HAVING)
+ select->select_n_where_fields++;
}
// Constructor need to process subselect with temporary tables (see Item)
@@ -1705,7 +1709,8 @@ Item_field::Item_field(THD *thd, Item_field *item)
item_equal(item->item_equal),
no_const_subst(item->no_const_subst),
have_privileges(item->have_privileges),
- any_privileges(item->any_privileges)
+ any_privileges(item->any_privileges),
+ fixed_as_field(item->fixed_as_field)
{
collation.set(DERIVATION_IMPLICIT);
}
@@ -1715,7 +1720,7 @@ void Item_field::set_field(Field *field_par)
field=result_field=field_par; // for easy coding with fields
maybe_null=field->maybe_null();
decimals= field->decimals();
- max_length= field_par->max_length();
+ max_length= field_par->max_display_length();
table_name= *field_par->table_name;
field_name= field_par->field_name;
db_name= field_par->table->s->db.str;
@@ -2424,21 +2429,22 @@ void Item_param::set_decimal(const char *str, ulong length)
the fact that even wrong value sent over binary protocol fits into
MAX_DATE_STRING_REP_LENGTH buffer.
*/
-void Item_param::set_time(TIME *tm, timestamp_type type, uint32 max_length_arg)
+void Item_param::set_time(TIME *tm, timestamp_type time_type,
+ uint32 max_length_arg)
{
DBUG_ENTER("Item_param::set_time");
value.time= *tm;
- value.time.time_type= type;
+ value.time.time_type= time_type;
if (value.time.year > 9999 || value.time.month > 12 ||
value.time.day > 31 ||
- type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23 ||
+ time_type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23 ||
value.time.minute > 59 || value.time.second > 59)
{
char buff[MAX_DATE_STRING_REP_LENGTH];
uint length= my_TIME_to_str(&value.time, buff);
- make_truncated_value_warning(current_thd, buff, length, type, 0);
+ make_truncated_value_warning(current_thd, buff, length, time_type, 0);
set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR);
}
@@ -2904,7 +2910,7 @@ bool Item_param::basic_const_item() const
Item *
-Item_param::new_item()
+Item_param::clone_item()
{
/* see comments in the header file */
switch (state) {
@@ -3503,36 +3509,85 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
{
if (*from_field)
{
+ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
+ select->cur_pos_in_select_list != UNDEF_POS)
+ {
+ /*
+ As this is an outer field it should be added to the list of
+ non aggregated fields of the outer select.
+ */
+ marker= select->cur_pos_in_select_list;
+ select->non_agg_fields.push_back(this);
+ }
if (*from_field != view_ref_found)
{
+
prev_subselect_item->used_tables_cache|= (*from_field)->table->map;
prev_subselect_item->const_item_cache= 0;
+ if (!last_checked_context->select_lex->having_fix_field &&
+ !fixed_as_field)
+ {
+ Item_outer_ref *rf;
+ Query_arena *arena= 0, backup;
+ /*
+ Each outer field is replaced for an Item_outer_ref object.
+ This is done in order to get correct results when the outer
+ select employs a temporary table.
+ The original fields are saved in the inner_fields_list of the
+ outer select. This list is created by the following reasons:
+ 1. We can't add field items to the outer select list directly
+ because the outer select hasn't been fully fixed yet.
+ 2. We need a location to refer to in the Item_ref object
+ so the inner_fields_list is used as such temporary
+ reference storage.
+ The new Item_outer_ref object replaces the original field and is
+ also saved in the inner_refs_list of the outer select. Here
+ it is only created. It can be fixed only after the original
+ field has been fixed and this is done in the fix_inner_refs()
+ function.
+ */
+ set_field(*from_field);
+ arena= thd->activate_stmt_arena_if_needed(&backup);
+ rf= new Item_outer_ref(context, this);
+ if (!rf)
+ {
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+ return -1;
+ }
+ *reference= rf;
+ select->inner_refs_list.push_back(rf);
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+ fixed_as_field= 1;
+ }
if (thd->lex->in_sum_func &&
thd->lex->in_sum_func->nest_level ==
thd->lex->current_select->nest_level)
{
- Item::Type type= (*reference)->type();
+ Item::Type ref_type= (*reference)->type();
set_if_bigger(thd->lex->in_sum_func->max_arg_level,
select->nest_level);
set_field(*from_field);
fixed= 1;
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
- ((type == REF_ITEM || type == FIELD_ITEM) ?
+ ((ref_type == REF_ITEM ||
+ ref_type == FIELD_ITEM) ?
(Item_ident*) (*reference) : 0));
return 0;
}
}
else
{
- Item::Type type= (*reference)->type();
+ Item::Type ref_type= (*reference)->type();
prev_subselect_item->used_tables_cache|=
(*reference)->used_tables();
prev_subselect_item->const_item_cache&=
(*reference)->const_item();
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
- ((type == REF_ITEM || type == FIELD_ITEM) ?
+ ((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
0));
/*
@@ -3633,7 +3688,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
{
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex,
- this, this);
+ this, (Item_ident*)*reference);
if (last_checked_context->select_lex->having_fix_field)
{
Item_ref *rf;
@@ -3705,10 +3760,11 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
bool Item_field::fix_fields(THD *thd, Item **reference)
{
DBUG_ASSERT(fixed == 0);
+ Field *from_field= (Field *)not_found_field;
+ bool outer_fixed= false;
+
if (!field) // If field is not checked
{
- Field *from_field= (Field *)not_found_field;
- bool outer_fixed= false;
/*
In case of view, find_field_in_tables() write pointer to view field
expression to 'reference', i.e. it substitute that expression instead
@@ -3800,6 +3856,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
goto error;
if (!ret)
return FALSE;
+ outer_fixed= 1;
}
set_field(from_field);
@@ -3859,6 +3916,13 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
}
#endif
fixed= 1;
+ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
+ !outer_fixed && !thd->lex->in_sum_func &&
+ thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS)
+ {
+ thd->lex->current_select->non_agg_fields.push_back(this);
+ marker= thd->lex->current_select->cur_pos_in_select_list;
+ }
return FALSE;
error:
@@ -4066,7 +4130,7 @@ Item *Item_field::replace_equal_field(byte *arg)
void Item::init_make_field(Send_field *tmp_field,
- enum enum_field_types field_type)
+ enum enum_field_types field_type_arg)
{
char *empty_name= (char*) "";
tmp_field->db_name= empty_name;
@@ -4078,7 +4142,7 @@ void Item::init_make_field(Send_field *tmp_field,
tmp_field->flags= (maybe_null ? 0 : NOT_NULL_FLAG) |
(my_binary_compare(collation.collation) ?
BINARY_FLAG : 0);
- tmp_field->type=field_type;
+ tmp_field->type= field_type_arg;
tmp_field->length=max_length;
tmp_field->decimals=decimals;
if (unsigned_flag)
@@ -4093,12 +4157,12 @@ void Item::make_field(Send_field *tmp_field)
enum_field_types Item::string_field_type() const
{
- enum_field_types type= MYSQL_TYPE_VAR_STRING;
+ enum_field_types f_type= MYSQL_TYPE_VAR_STRING;
if (max_length >= 16777216)
- type= MYSQL_TYPE_LONG_BLOB;
+ f_type= MYSQL_TYPE_LONG_BLOB;
else if (max_length >= 65536)
- type= MYSQL_TYPE_MEDIUM_BLOB;
- return type;
+ f_type= MYSQL_TYPE_MEDIUM_BLOB;
+ return f_type;
}
@@ -4309,18 +4373,19 @@ void Item_field::save_org_in_field(Field *to)
int Item_field::save_in_field(Field *to, bool no_conversions)
{
+ int res;
if (result_field->is_null())
{
null_value=1;
- return set_field_to_null_with_conversions(to, no_conversions);
+ res= set_field_to_null_with_conversions(to, no_conversions);
}
else
{
to->set_notnull();
- field_conv(to,result_field);
+ res= field_conv(to,result_field);
null_value=0;
}
- return 0;
+ return res;
}
@@ -4468,7 +4533,7 @@ bool Item_int::eq(const Item *arg, bool binary_cmp) const
}
-Item *Item_int_with_ref::new_item()
+Item *Item_int_with_ref::clone_item()
{
DBUG_ASSERT(ref->const_item());
/*
@@ -4746,10 +4811,10 @@ bool Item_null::send(Protocol *protocol, String *packet)
bool Item::send(Protocol *protocol, String *buffer)
{
bool result;
- enum_field_types type;
+ enum_field_types f_type;
LINT_INIT(result); // Will be set if null_value == 0
- switch ((type=field_type())) {
+ switch ((f_type=field_type())) {
default:
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_DECIMAL:
@@ -4828,7 +4893,7 @@ bool Item::send(Protocol *protocol, String *buffer)
get_date(&tm, TIME_FUZZY_DATE);
if (!null_value)
{
- if (type == MYSQL_TYPE_DATE)
+ if (f_type == MYSQL_TYPE_DATE)
return protocol->store_date(&tm);
else
result= protocol->store(&tm);
@@ -4872,6 +4937,51 @@ void Item_field::update_null_value()
}
+/*
+ Add the field to the select list and substitute it for the reference to
+ the field.
+
+ SYNOPSIS
+ Item_field::update_value_transformer()
+ select_arg current select
+
+ DESCRIPTION
+ If the field doesn't belong to the table being inserted into then it is
+ added to the select list, pointer to it is stored in the ref_pointer_array
+ of the select and the field itself is substituted for the Item_ref object.
+ This is done in order to get correct values from update fields that
+ belongs to the SELECT part in the INSERT .. SELECT .. ON DUPLICATE KEY
+ UPDATE statement.
+
+ RETURN
+ 0 if error occured
+ ref if all conditions are met
+ this field otherwise
+*/
+
+Item *Item_field::update_value_transformer(byte *select_arg)
+{
+ SELECT_LEX *select= (SELECT_LEX*)select_arg;
+ DBUG_ASSERT(fixed);
+
+ if (field->table != select->context.table_list->table &&
+ type() != Item::TRIGGER_FIELD_ITEM)
+ {
+ List<Item> *all_fields= &select->join->all_fields;
+ Item **ref_pointer_array= select->ref_pointer_array;
+ int el= all_fields->elements;
+ Item_ref *ref;
+
+ ref_pointer_array[el]= (Item*)this;
+ all_fields->push_front((Item*)this);
+ ref= new Item_ref(&select->context, ref_pointer_array + el,
+ table_name, field_name);
+ return ref;
+ }
+ return this;
+}
+
+
Item_ref::Item_ref(Name_resolution_context *context_arg,
Item **item, const char *table_name_arg,
const char *field_name_arg)
@@ -4881,8 +4991,7 @@ Item_ref::Item_ref(Name_resolution_context *context_arg,
/*
This constructor used to create some internals references over fixed items
*/
- DBUG_ASSERT(ref != 0);
- if (*ref && (*ref)->fixed)
+ if (ref && *ref && (*ref)->fixed)
set_properties();
}
@@ -5041,7 +5150,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
goto error;
if (from_field == view_ref_found)
{
- Item::Type type= (*reference)->type();
+ Item::Type refer_type= (*reference)->type();
prev_subselect_item->used_tables_cache|=
(*reference)->used_tables();
prev_subselect_item->const_item_cache&=
@@ -5049,7 +5158,8 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
DBUG_ASSERT((*reference)->type() == REF_ITEM);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
- ((type == REF_ITEM || type == FIELD_ITEM) ?
+ ((refer_type == REF_ITEM ||
+ refer_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
0));
/*
@@ -5182,7 +5292,7 @@ void Item_ref::print(String *str)
if (ref)
{
if ((*ref)->type() != Item::CACHE_ITEM && ref_type() != VIEW_REF &&
- name && alias_name_used)
+ ref_type() != OUTER_REF && name && alias_name_used)
{
THD *thd= current_thd;
append_identifier(thd, str, name, (uint) strlen(name));
@@ -5340,18 +5450,7 @@ my_decimal *Item_ref::val_decimal(my_decimal *decimal_value)
int Item_ref::save_in_field(Field *to, bool no_conversions)
{
int res;
- if (result_field)
- {
- if (result_field->is_null())
- {
- null_value= 1;
- return set_field_to_null_with_conversions(to, no_conversions);
- }
- to->set_notnull();
- field_conv(to, result_field);
- null_value= 0;
- return 0;
- }
+ DBUG_ASSERT(!result_field);
res= (*ref)->save_in_field(to, no_conversions);
null_value= (*ref)->null_value;
return res;
@@ -5441,7 +5540,7 @@ bool Item_direct_ref::get_date(TIME *ltime,uint fuzzydate)
/*
- Prepare referenced view viewld then call usual Item_direct_ref::fix_fields
+ Prepare referenced field then call usual Item_direct_ref::fix_fields
SYNOPSIS
Item_direct_view_ref::fix_fields()
@@ -5465,6 +5564,31 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference)
}
/*
+ Prepare referenced outer field then call usual Item_direct_ref::fix_fields
+
+ SYNOPSIS
+ Item_outer_ref::fix_fields()
+ thd thread handler
+ reference reference on reference where this item stored
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
+
+bool Item_outer_ref::fix_fields(THD *thd, Item **reference)
+{
+ DBUG_ASSERT(*ref);
+ /* outer_field->check_cols() will be made in Item_direct_ref::fix_fields */
+ outer_field->fixed_as_field= 1;
+ if (!outer_field->fixed &&
+ (outer_field->fix_fields(thd, reference)))
+ return TRUE;
+ table_name= outer_field->table_name;
+ return Item_direct_ref::fix_fields(thd, reference);
+}
+
+/*
Compare two view column references for equality.
SYNOPSIS
@@ -5570,6 +5694,13 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
{
if (field_arg->flags & NO_DEFAULT_VALUE_FLAG)
{
+ if (field_arg->reset())
+ {
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+ return -1;
+ }
+
if (context->error_processor == &view_error_processor)
{
TABLE_LIST *view= cached_table->top_table();
@@ -5588,7 +5719,6 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
ER(ER_NO_DEFAULT_FOR_FIELD),
field_arg->field_name);
}
- field_arg->set_default();
return 1;
}
field_arg->set_default();
@@ -5795,8 +5925,8 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items)
{
table_grants->want_privilege= want_privilege;
- if (check_grant_column(thd, table_grants, triggers->table->s->db.str,
- triggers->table->s->table_name.str, field_name,
+ if (check_grant_column(thd, table_grants, triggers->trigger_table->s->db.str,
+ triggers->trigger_table->s->table_name.str, field_name,
strlen(field_name), thd->security_ctx))
return TRUE;
}
@@ -5909,7 +6039,8 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
DBUG_ASSERT(item_row->cols() == comp_item_row->cols());
col= item_row->cols();
while (col-- > 0)
- resolve_const_item(thd, item_row->addr(col), comp_item_row->el(col));
+ resolve_const_item(thd, item_row->addr(col),
+ comp_item_row->element_index(col));
break;
}
/* Fallthrough */
@@ -6177,7 +6308,7 @@ bool Item_cache_row::setup(Item * item)
return 1;
for (uint i= 0; i < item_count; i++)
{
- Item *el= item->el(i);
+ Item *el= item->element_index(i);
Item_cache *tmp;
if (!(tmp= values[i]= Item_cache::get_cache(el->result_type())))
return 1;
@@ -6193,7 +6324,7 @@ void Item_cache_row::store(Item * item)
item->bring_value();
for (uint i= 0; i < item_count; i++)
{
- values[i]->store(item->el(i));
+ values[i]->store(item->element_index(i));
null_value|= values[i]->null_value;
}
}
diff --git a/sql/item.h b/sql/item.h
index b2e363dce52..be4636db91e 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -325,10 +325,10 @@ private:
TABLE_LIST *save_first_name_resolution_table;
TABLE_LIST *save_next_name_resolution_table;
bool save_resolve_in_select_list;
+ TABLE_LIST *save_next_local;
public:
Name_resolution_context_state() {} /* Remove gcc warning */
- TABLE_LIST *save_next_local;
public:
/* Save the state of a name resolution context. */
@@ -350,6 +350,11 @@ public:
context->first_name_resolution_table= save_first_name_resolution_table;
context->resolve_in_select_list= save_resolve_in_select_list;
}
+
+ TABLE_LIST *get_first_name_resolution_table()
+ {
+ return save_first_name_resolution_table;
+ }
};
@@ -477,7 +482,8 @@ public:
Item *next;
uint32 max_length;
uint name_length; /* Length of name */
- uint8 marker, decimals;
+ int8 marker;
+ uint8 decimals;
my_bool maybe_null; /* If item may be null */
my_bool null_value; /* if item is null */
my_bool unsigned_flag;
@@ -686,7 +692,7 @@ public:
*/
virtual bool basic_const_item() const { return 0; }
/* cloning of constant items (0 if it is not const) */
- virtual Item *new_item() { return 0; }
+ virtual Item *clone_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;}
@@ -817,6 +823,7 @@ public:
virtual bool collect_item_field_processor(byte * arg) { return 0; }
virtual bool find_item_in_field_list_processor(byte *arg) { return 0; }
virtual bool change_context_processor(byte *context) { return 0; }
+ virtual bool reset_query_id_processor(byte *query_id_arg) { return 0; }
virtual bool is_expensive_processor(byte *arg) { return 0; }
virtual bool register_field_in_read_map(byte *arg) { return 0; }
/*
@@ -894,11 +901,11 @@ public:
For SP local variable returns address of pointer to Item representing its
current value and pointer passed via parameter otherwise.
*/
- virtual Item **this_item_addr(THD *thd, Item **addr) { return addr; }
+ virtual Item **this_item_addr(THD *thd, Item **addr_arg) { return addr_arg; }
// Row emulation
virtual uint cols() { return 1; }
- virtual Item* el(uint i) { return this; }
+ virtual Item* element_index(uint i) { return this; }
virtual Item** addr(uint i) { return 0; }
virtual bool check_cols(uint c);
// It is not row => null inside is impossible
@@ -910,6 +917,7 @@ public:
virtual Item_field *filed_for_view_update() { return 0; }
virtual Item *neg_transformer(THD *thd) { return NULL; }
+ virtual Item *update_value_transformer(byte *select_arg) { return this; }
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
void delete_self()
{
@@ -1164,7 +1172,8 @@ class Item_name_const : public Item
Item *value_item;
Item *name_item;
public:
- Item_name_const(Item *name, Item *val): value_item(val), name_item(name)
+ Item_name_const(Item *name_arg, Item *val):
+ value_item(val), name_item(name_arg)
{
Item::maybe_null= TRUE;
}
@@ -1308,7 +1317,7 @@ public:
uint have_privileges;
/* field need any privileges (for VIEW creation) */
bool any_privileges;
-
+ bool fixed_as_field;
Item_field(Name_resolution_context *context_arg,
const char *db_arg,const char *table_name_arg,
const char *field_name_arg);
@@ -1384,10 +1393,11 @@ public:
Item *equal_fields_propagator(byte *arg);
bool set_no_const_sub(byte *arg);
Item *replace_equal_field(byte *arg);
- inline uint32 max_disp_length() { return field->max_length(); }
+ inline uint32 max_disp_length() { return field->max_display_length(); }
Item_field *filed_for_view_update() { return this; }
Item *safe_charset_converter(CHARSET_INFO *tocs);
int fix_outer_field(THD *thd, Field **field, Item **reference);
+ virtual Item *update_value_transformer(byte *select_arg);
friend class Item_default_value;
friend class Item_insert_value;
friend class st_select_lex_unit;
@@ -1418,7 +1428,7 @@ public:
/* to prevent drop fixed flag (no need parent cleanup call) */
void cleanup() {}
bool basic_const_item() const { return 1; }
- Item *new_item() { return new Item_null(name); }
+ Item *clone_item() { return new Item_null(name); }
bool is_null() { return 1; }
void print(String *str) { str->append(STRING_WITH_LEN("NULL")); }
Item *safe_charset_converter(CHARSET_INFO *tocs);
@@ -1567,7 +1577,7 @@ public:
basic_const_item returned TRUE.
*/
Item *safe_charset_converter(CHARSET_INFO *tocs);
- Item *new_item();
+ Item *clone_item();
/*
Implement by-value equality evaluation if parameter value
is set and is a basic constant (integer, real or string).
@@ -1599,7 +1609,7 @@ public:
String *val_str(String*);
int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
- Item *new_item() { return new Item_int(name,value,max_length); }
+ Item *clone_item() { return new Item_int(name,value,max_length); }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
void print(String *str);
@@ -1619,7 +1629,7 @@ public:
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); }
+ Item *clone_item() { return new Item_uint(name,max_length); }
int save_in_field(Field *field, bool no_conversions);
void print(String *str);
Item_num *neg ();
@@ -1650,7 +1660,7 @@ public:
my_decimal *val_decimal(my_decimal *val) { return &decimal_value; }
int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
- Item *new_item()
+ Item *clone_item()
{
return new Item_decimal(name, &decimal_value, decimals, max_length);
}
@@ -1708,7 +1718,7 @@ public:
bool basic_const_item() const { return 1; }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
- Item *new_item()
+ Item *clone_item()
{ return new Item_float(name, value, decimals, max_length); }
Item_num *neg() { value= -value; return this; }
void print(String *str);
@@ -1794,7 +1804,7 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
bool basic_const_item() const { return 1; }
bool eq(const Item *item, bool binary_cmp) const;
- Item *new_item()
+ Item *clone_item()
{
return new Item_string(name, str_value.ptr(),
str_value.length(), collation.collation);
@@ -1848,9 +1858,9 @@ class Item_return_int :public Item_int
{
enum_field_types int_field_type;
public:
- Item_return_int(const char *name, uint length,
+ Item_return_int(const char *name_arg, uint length,
enum_field_types field_type_arg)
- :Item_int(name, 0, length), int_field_type(field_type_arg)
+ :Item_int(name_arg, 0, length), int_field_type(field_type_arg)
{
unsigned_flag=1;
}
@@ -1918,7 +1928,7 @@ class Item_ref :public Item_ident
protected:
void set_properties();
public:
- enum Ref_Type { REF, DIRECT_REF, VIEW_REF };
+ enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF };
Field *result_field; /* Save result here */
Item **ref;
Item_ref(Name_resolution_context *context_arg,
@@ -1979,7 +1989,7 @@ public:
(*ref)->get_tmp_table_item(thd));
}
table_map used_tables() const
- {
+ {
return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables();
}
table_map not_null_tables() const { return (*ref)->not_null_tables(); }
@@ -2052,6 +2062,40 @@ public:
};
+class Item_outer_ref :public Item_direct_ref
+{
+public:
+ Item_field *outer_field;
+ Item_outer_ref(Name_resolution_context *context_arg,
+ Item_field *outer_field_arg)
+ :Item_direct_ref(context_arg, 0, outer_field_arg->table_name,
+ outer_field_arg->field_name),
+ outer_field(outer_field_arg)
+ {
+ ref= (Item**)&outer_field;
+ set_properties();
+ fixed= 0;
+ }
+ void cleanup()
+ {
+ ref= (Item**)&outer_field;
+ fixed= 0;
+ Item_direct_ref::cleanup();
+ outer_field->cleanup();
+ }
+ void save_in_result_field(bool no_conversions)
+ {
+ outer_field->save_org_in_field(result_field);
+ }
+ bool fix_fields(THD *, Item **);
+ table_map used_tables() const
+ {
+ return (*ref)->const_item() ? 0 : OUTER_REF_TABLE_BIT;
+ }
+ virtual Ref_Type ref_type() { return OUTER_REF; }
+};
+
+
class Item_in_subselect;
@@ -2114,7 +2158,7 @@ public:
{
return ref->save_in_field(field, no_conversions);
}
- Item *new_item();
+ Item *clone_item();
virtual Item *real_item() { return ref; }
bool check_partition_func_processor(byte *int_arg) {return TRUE;}
};
@@ -2367,6 +2411,9 @@ public:
bool fix_fields(THD *, Item **);
void print(String *str);
table_map used_tables() const { return (table_map)0L; }
+ Field *get_tmp_table_field() { return 0; }
+ Item *copy_or_same(THD *thd) { return this; }
+ Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); }
void cleanup();
private:
@@ -2549,8 +2596,8 @@ public:
enum Item_result result_type() const { return ROW_RESULT; }
uint cols() { return item_count; }
- Item* el(uint i) { return values[i]; }
- Item** addr(uint i) { return (Item **) (values + i); }
+ Item *element_index(uint i) { return values[i]; }
+ Item **addr(uint i) { return (Item **) (values + i); }
bool check_cols(uint c);
bool null_inside();
void bring_value();
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 3a615d4c10a..e78550598f5 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -26,13 +26,17 @@
static bool convert_constant_item(THD *thd, Field *field, Item **item);
-static Item_result item_store_type(Item_result a,Item_result b)
+static Item_result item_store_type(Item_result a, Item *item,
+ my_bool unsigned_flag)
{
+ Item_result b= item->result_type();
+
if (a == STRING_RESULT || b == STRING_RESULT)
return STRING_RESULT;
else if (a == REAL_RESULT || b == REAL_RESULT)
return REAL_RESULT;
- else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT)
+ else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT ||
+ unsigned_flag != item->unsigned_flag)
return DECIMAL_RESULT;
else
return INT_RESULT;
@@ -41,6 +45,7 @@ static Item_result item_store_type(Item_result a,Item_result b)
static void agg_result_type(Item_result *type, Item **items, uint nitems)
{
Item **item, **item_end;
+ my_bool unsigned_flag= 0;
*type= STRING_RESULT;
/* Skip beginning NULL items */
@@ -49,6 +54,7 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
if ((*item)->type() != Item::NULL_ITEM)
{
*type= (*item)->result_type();
+ unsigned_flag= (*item)->unsigned_flag;
item++;
break;
}
@@ -57,7 +63,7 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
for (; item < item_end; item++)
{
if ((*item)->type() != Item::NULL_ITEM)
- *type= item_store_type(type[0], (*item)->result_type());
+ *type= item_store_type(*type, *item, unsigned_flag);
}
}
@@ -176,6 +182,22 @@ longlong Item_func_not::val_int()
}
/*
+ We put any NOT expression into parenthesis to avoid
+ possible problems with internal view representations where
+ any '!' is converted to NOT. It may cause a problem if
+ '!' is used in an expression together with other operators
+ whose precedence is lower than the precedence of '!' yet
+ higher than the precedence of NOT.
+*/
+
+void Item_func_not::print(String *str)
+{
+ str->append('(');
+ Item_func::print(str);
+ str->append(')');
+}
+
+/*
special NOT for ALL subquery
*/
@@ -306,7 +328,7 @@ static bool convert_constant_item(THD *thd, Field *field, Item **item)
void Item_bool_func2::fix_length_and_dec()
{
max_length= 1; // Function returns 0 or 1
- THD *thd= current_thd;
+ THD *thd;
/*
As some compare functions are generated after sql_yacc,
@@ -344,12 +366,13 @@ void Item_bool_func2::fix_length_and_dec()
return;
}
+ thd= current_thd;
if (!thd->is_context_analysis_only())
{
- Item *real_item= args[0]->real_item();
- if (real_item->type() == FIELD_ITEM)
+ Item *arg_real_item= args[0]->real_item();
+ if (arg_real_item->type() == FIELD_ITEM)
{
- Field *field=((Item_field*) real_item)->field;
+ Field *field=((Item_field*) arg_real_item)->field;
if (field->can_be_compared_as_longlong())
{
if (convert_constant_item(thd, field,&args[1]))
@@ -361,10 +384,10 @@ void Item_bool_func2::fix_length_and_dec()
}
}
}
- real_item= args[1]->real_item();
- if (real_item->type() == FIELD_ITEM /* && !real_item->const_item() */)
+ arg_real_item= args[1]->real_item();
+ if (arg_real_item->type() == FIELD_ITEM)
{
- Field *field=((Item_field*) real_item)->field;
+ Field *field=((Item_field*) arg_real_item)->field;
if (field->can_be_compared_as_longlong())
{
if (convert_constant_item(thd, field,&args[0]))
@@ -400,9 +423,9 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
return 1;
for (uint i=0; i < n; i++)
{
- if ((*a)->el(i)->cols() != (*b)->el(i)->cols())
+ if ((*a)->element_index(i)->cols() != (*b)->element_index(i)->cols())
{
- my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->el(i)->cols());
+ my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols());
return 1;
}
comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i));
@@ -464,8 +487,19 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
break;
}
case DECIMAL_RESULT:
+ break;
case REAL_RESULT:
+ {
+ if ((*a)->decimals < NOT_FIXED_DEC && (*b)->decimals < NOT_FIXED_DEC)
+ {
+ precision= 5 * log_01[max((*a)->decimals, (*b)->decimals)];
+ if (func == &Arg_comparator::compare_real)
+ func= &Arg_comparator::compare_real_fixed;
+ else if (func == &Arg_comparator::compare_e_real)
+ func= &Arg_comparator::compare_e_real_fixed;
+ }
break;
+ }
default:
DBUG_ASSERT(0);
}
@@ -604,6 +638,44 @@ int Arg_comparator::compare_e_decimal()
return test(my_decimal_cmp(val1, val2) == 0);
}
+
+int Arg_comparator::compare_real_fixed()
+{
+ /*
+ Fix yet another manifestation of Bug#2338. 'Volatile' will instruct
+ gcc to flush double values out of 80-bit Intel FPU registers before
+ performing the comparison.
+ */
+ volatile double val1, val2;
+ val1= (*a)->val_real();
+ if (!(*a)->null_value)
+ {
+ val2= (*b)->val_real();
+ if (!(*b)->null_value)
+ {
+ owner->null_value= 0;
+ if (val1 == val2 || fabs(val1 - val2) < precision)
+ return 0;
+ if (val1 < val2)
+ return -1;
+ return 1;
+ }
+ }
+ owner->null_value= 1;
+ return -1;
+}
+
+
+int Arg_comparator::compare_e_real_fixed()
+{
+ double val1= (*a)->val_real();
+ double val2= (*b)->val_real();
+ if ((*a)->null_value || (*b)->null_value)
+ return test((*a)->null_value && (*b)->null_value);
+ return test(val1 == val2 || fabs(val1 - val2) < precision);
+}
+
+
int Arg_comparator::compare_int_signed()
{
longlong val1= (*a)->val_int();
@@ -768,6 +840,59 @@ int Arg_comparator::compare_e_row()
}
+void Item_func_truth::fix_length_and_dec()
+{
+ maybe_null= 0;
+ null_value= 0;
+ decimals= 0;
+ max_length= 1;
+}
+
+
+void Item_func_truth::print(String *str)
+{
+ str->append('(');
+ args[0]->print(str);
+ str->append(STRING_WITH_LEN(" is "));
+ if (! affirmative)
+ str->append(STRING_WITH_LEN("not "));
+ if (value)
+ str->append(STRING_WITH_LEN("true"));
+ else
+ str->append(STRING_WITH_LEN("false"));
+ str->append(')');
+}
+
+
+bool Item_func_truth::val_bool()
+{
+ bool val= args[0]->val_bool();
+ if (args[0]->null_value)
+ {
+ /*
+ NULL val IS {TRUE, FALSE} --> FALSE
+ NULL val IS NOT {TRUE, FALSE} --> TRUE
+ */
+ return (! affirmative);
+ }
+
+ if (affirmative)
+ {
+ /* {TRUE, FALSE} val IS {TRUE, FALSE} value */
+ return (val == value);
+ }
+
+ /* {TRUE, FALSE} val IS NOT {TRUE, FALSE} value */
+ return (val != value);
+}
+
+
+longlong Item_func_truth::val_int()
+{
+ return (val_bool() ? 1 : 0);
+}
+
+
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
{
if (!args[0]->fixed && args[0]->fix_fields(thd, args) ||
@@ -787,10 +912,10 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
uint n= cache->cols();
for (uint i= 0; i < n; i++)
{
- if (args[0]->el(i)->used_tables())
- ((Item_cache *)cache->el(i))->set_used_tables(OUTER_REF_TABLE_BIT);
+ if (args[0]->element_index(i)->used_tables())
+ ((Item_cache *)cache->element_index(i))->set_used_tables(OUTER_REF_TABLE_BIT);
else
- ((Item_cache *)cache->el(i))->set_used_tables(0);
+ ((Item_cache *)cache->element_index(i))->set_used_tables(0);
}
used_tables_cache= args[0]->used_tables();
}
@@ -831,6 +956,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
longlong Item_in_optimizer::val_int()
{
+ bool tmp;
DBUG_ASSERT(fixed == 1);
cache->store(args[0]);
@@ -861,16 +987,40 @@ longlong Item_in_optimizer::val_int()
We disable the predicates we've pushed down into subselect, run the
subselect and see if it has produced any rows.
*/
- ((Item_in_subselect*)args[1])->enable_pushed_conds= FALSE;
- longlong tmp= args[1]->val_bool_result();
- result_for_null_param= null_value=
- !((Item_in_subselect*)args[1])->engine->no_rows();
- ((Item_in_subselect*)args[1])->enable_pushed_conds= TRUE;
+ Item_in_subselect *item_subs=(Item_in_subselect*)args[1];
+ if (cache->cols() == 1)
+ {
+ item_subs->set_cond_guard_var(0, FALSE);
+ (void) args[1]->val_bool_result();
+ result_for_null_param= null_value= !item_subs->engine->no_rows();
+ item_subs->set_cond_guard_var(0, TRUE);
+ }
+ else
+ {
+ uint i;
+ uint ncols= cache->cols();
+ /*
+ Turn off the predicates that are based on column compares for
+ which the left part is currently NULL
+ */
+ for (i= 0; i < ncols; i++)
+ {
+ if (cache->element_index(i)->null_value)
+ item_subs->set_cond_guard_var(i, FALSE);
+ }
+
+ (void) args[1]->val_bool_result();
+ result_for_null_param= null_value= !item_subs->engine->no_rows();
+
+ /* Turn all predicates back on */
+ for (i= 0; i < ncols; i++)
+ item_subs->set_cond_guard_var(i, TRUE);
+ }
}
}
return 0;
}
- bool tmp= args[1]->val_bool_result();
+ tmp= args[1]->val_bool_result();
null_value= args[1]->null_value;
return tmp;
}
@@ -979,15 +1129,17 @@ longlong Item_func_strcmp::val_int()
void Item_func_interval::fix_length_and_dec()
{
- use_decimal_comparison= (row->el(0)->result_type() == DECIMAL_RESULT) ||
- (row->el(0)->result_type() == INT_RESULT);
+ use_decimal_comparison= ((row->element_index(0)->result_type() ==
+ DECIMAL_RESULT) ||
+ (row->element_index(0)->result_type() ==
+ INT_RESULT));
if (row->cols() > 8)
{
bool consts=1;
for (uint i=1 ; consts && i < row->cols() ; i++)
{
- consts&= row->el(i)->const_item();
+ consts&= row->element_index(i)->const_item();
}
if (consts &&
@@ -998,7 +1150,7 @@ void Item_func_interval::fix_length_and_dec()
{
for (uint i=1 ; i < row->cols(); i++)
{
- Item *el= row->el(i);
+ Item *el= row->element_index(i);
interval_range *range= intervals + (i-1);
if ((el->result_type() == DECIMAL_RESULT) ||
(el->result_type() == INT_RESULT))
@@ -1023,7 +1175,7 @@ void Item_func_interval::fix_length_and_dec()
{
for (uint i=1 ; i < row->cols(); i++)
{
- intervals[i-1].dbl= row->el(i)->val_real();
+ intervals[i-1].dbl= row->element_index(i)->val_real();
}
}
}
@@ -1063,15 +1215,15 @@ longlong Item_func_interval::val_int()
if (use_decimal_comparison)
{
- dec= row->el(0)->val_decimal(&dec_buf);
- if (row->el(0)->null_value)
+ dec= row->element_index(0)->val_decimal(&dec_buf);
+ if (row->element_index(0)->null_value)
return -1;
my_decimal2double(E_DEC_FATAL_ERROR, dec, &value);
}
else
{
- value= row->el(0)->val_real();
- if (row->el(0)->null_value)
+ value= row->element_index(0)->val_real();
+ if (row->element_index(0)->null_value)
return -1;
}
@@ -1107,16 +1259,16 @@ longlong Item_func_interval::val_int()
for (i=1 ; i < row->cols() ; i++)
{
- Item *el= row->el(i);
+ Item *el= row->element_index(i);
if (use_decimal_comparison &&
((el->result_type() == DECIMAL_RESULT) ||
(el->result_type() == INT_RESULT)))
{
- my_decimal e_dec_buf, *e_dec= row->el(i)->val_decimal(&e_dec_buf);
+ my_decimal e_dec_buf, *e_dec= row->element_index(i)->val_decimal(&e_dec_buf);
if (my_decimal_cmp(e_dec, dec) > 0)
return i-1;
}
- else if (row->el(i)->val_real() > value)
+ else if (row->element_index(i)->val_real() > value)
return i-1;
}
return i-1;
@@ -1193,11 +1345,11 @@ void Item_func_between::fix_length_and_dec()
They are compared as integers, so for const item this time-consuming
conversion can be done only once, not for every single comparison
*/
- if (args[0]->type() == FIELD_ITEM &&
+ if (args[0]->real_item()->type() == FIELD_ITEM &&
thd->lex->sql_command != SQLCOM_CREATE_VIEW &&
thd->lex->sql_command != SQLCOM_SHOW_CREATE)
{
- Field *field=((Item_field*) args[0])->field;
+ Field *field=((Item_field*) (args[0]->real_item()))->field;
if (field->can_be_compared_as_longlong())
{
/*
@@ -1480,6 +1632,7 @@ Item_func_if::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
decimals= max(args[1]->decimals, args[2]->decimals);
+ unsigned_flag=args[1]->unsigned_flag && args[2]->unsigned_flag;
enum Item_result arg1_type=args[1]->result_type();
enum Item_result arg2_type=args[2]->result_type();
@@ -1509,12 +1662,20 @@ Item_func_if::fix_length_and_dec()
collation.set(&my_charset_bin); // Number
}
}
- max_length=
- (cached_result_type == DECIMAL_RESULT || cached_result_type == INT_RESULT) ?
- (max(args[1]->max_length - args[1]->decimals,
- args[2]->max_length - args[2]->decimals) + decimals +
- (unsigned_flag ? 0 : 1) ) :
- max(args[1]->max_length, args[2]->max_length);
+
+ if ((cached_result_type == DECIMAL_RESULT )
+ || (cached_result_type == INT_RESULT))
+ {
+ int len1= args[1]->max_length - args[1]->decimals
+ - (args[1]->unsigned_flag ? 0 : 1);
+
+ int len2= args[2]->max_length - args[2]->decimals
+ - (args[2]->unsigned_flag ? 0 : 1);
+
+ max_length=max(len1, len2) + decimals + (unsigned_flag ? 0 : 1);
+ }
+ else
+ max_length= max(args[1]->max_length, args[2]->max_length);
}
@@ -1810,7 +1971,9 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref)
buff should match stack usage from
Item_func_case::val_int() -> Item_func_case::find_item()
*/
+#ifndef EMBEDDED_LIBRARY
char buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2];
+#endif
bool res= Item_func::fix_fields(thd, ref);
/*
Call check_stack_overrun after fix_fields to be sure that stack variable
@@ -1827,7 +1990,6 @@ void Item_func_case::fix_length_and_dec()
{
Item **agg;
uint nagg;
- THD *thd= current_thd;
uint found_types= 0;
if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1))))
return;
@@ -2288,11 +2450,11 @@ void cmp_item_row::store_value(Item *item)
{
if (!comparators[i])
if (!(comparators[i]=
- cmp_item::get_comparator(item->el(i)->result_type(),
- item->el(i)->collation.collation)))
+ cmp_item::get_comparator(item->element_index(i)->result_type(),
+ item->element_index(i)->collation.collation)))
break; // new failed
- comparators[i]->store_value(item->el(i));
- item->null_value|= item->el(i)->null_value;
+ comparators[i]->store_value(item->element_index(i));
+ item->null_value|= item->element_index(i)->null_value;
}
}
DBUG_VOID_RETURN;
@@ -2317,8 +2479,8 @@ void cmp_item_row::store_value_by_template(cmp_item *t, Item *item)
if (!(comparators[i]= tmpl->comparators[i]->make_same()))
break; // new failed
comparators[i]->store_value_by_template(tmpl->comparators[i],
- item->el(i));
- item->null_value|= item->el(i)->null_value;
+ item->element_index(i));
+ item->null_value|= item->element_index(i)->null_value;
}
}
}
@@ -2336,9 +2498,9 @@ int cmp_item_row::cmp(Item *arg)
arg->bring_value();
for (uint i=0; i < n; i++)
{
- if (comparators[i]->cmp(arg->el(i)))
+ if (comparators[i]->cmp(arg->element_index(i)))
{
- if (!arg->el(i)->null_value)
+ if (!arg->element_index(i)->null_value)
return 1;
was_null= 1;
}
@@ -2349,11 +2511,11 @@ int cmp_item_row::cmp(Item *arg)
int cmp_item_row::compare(cmp_item *c)
{
- cmp_item_row *cmp= (cmp_item_row *) c;
+ cmp_item_row *l_cmp= (cmp_item_row *) c;
for (uint i=0; i < n; i++)
{
int res;
- if ((res= comparators[i]->compare(cmp->comparators[i])))
+ if ((res= comparators[i]->compare(l_cmp->comparators[i])))
return res;
}
return 0;
@@ -2380,8 +2542,8 @@ int cmp_item_decimal::cmp(Item *arg)
int cmp_item_decimal::compare(cmp_item *arg)
{
- cmp_item_decimal *cmp= (cmp_item_decimal*) arg;
- return my_decimal_cmp(&value, &cmp->value);
+ cmp_item_decimal *l_cmp= (cmp_item_decimal*) arg;
+ return my_decimal_cmp(&value, &l_cmp->value);
}
@@ -2468,6 +2630,7 @@ void Item_func_in::fix_length_and_dec()
THD *thd= current_thd;
uint found_types= 0;
uint type_cnt= 0, i;
+ Item_result cmp_type= STRING_RESULT;
left_result_type= args[0]->result_type();
found_types= collect_cmp_types(args, arg_count);
@@ -2482,25 +2645,28 @@ void Item_func_in::fix_length_and_dec()
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
if (found_types & 1 << i)
+ {
(type_cnt)++;
+ cmp_type= (Item_result) i;
+ }
}
+
+ if (type_cnt == 1)
+ {
+ if (cmp_type == STRING_RESULT &&
+ agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
+ return;
+ arg_types_compatible= TRUE;
+ }
+
/*
Row item with NULLs inside can return NULL or FALSE =>
they can't be processed as static
*/
if (type_cnt == 1 && const_itm && !nulls_in_row())
{
- uint tmp_type;
- Item_result cmp_type;
- /* Only one cmp type was found. Extract it here */
- for (tmp_type= 0; found_types - 1; found_types>>= 1)
- tmp_type++;
- cmp_type= (Item_result)tmp_type;
-
switch (cmp_type) {
case STRING_RESULT:
- if (agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
- return;
array=new in_string(arg_count - 1,(qsort2_cmp) srtcmp_in,
cmp_collation.collation);
break;
@@ -4085,11 +4251,9 @@ longlong Item_equal::val_int()
void Item_equal::fix_length_and_dec()
{
- Item *item= const_item ? const_item : get_first();
+ Item *item= get_first();
eval_item= cmp_item::get_comparator(item->result_type(),
item->collation.collation);
- if (item->result_type() == STRING_RESULT)
- eval_item->cmp_charset= cmp_collation.collation;
}
bool Item_equal::walk(Item_processor processor, bool walk_subquery, byte *arg)
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index a51cc0d4b30..3b08036368c 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -34,6 +34,7 @@ class Arg_comparator: public Sql_alloc
arg_cmp_func func;
Item_bool_func2 *owner;
Arg_comparator *comparators; // used only for compare_row()
+ double precision;
public:
DTCollation cmp_collation;
@@ -80,6 +81,8 @@ public:
int compare_e_int(); // compare args[0] & args[1]
int compare_e_int_diff_signedness();
int compare_e_row(); // compare args[0] & args[1]
+ int compare_real_fixed();
+ int compare_e_real_fixed();
static arg_cmp_func comparator_matrix [5][2];
@@ -98,6 +101,92 @@ public:
uint decimal_precision() const { return 1; }
};
+
+/**
+ Abstract Item class, to represent <code>X IS [NOT] (TRUE | FALSE)</code>
+ boolean predicates.
+*/
+
+class Item_func_truth : public Item_bool_func
+{
+public:
+ virtual bool val_bool();
+ virtual longlong val_int();
+ virtual void fix_length_and_dec();
+ virtual void print(String *str);
+
+protected:
+ Item_func_truth(Item *a, bool a_value, bool a_affirmative)
+ : Item_bool_func(a), value(a_value), affirmative(a_affirmative)
+ {}
+
+ ~Item_func_truth()
+ {}
+private:
+ /**
+ True for <code>X IS [NOT] TRUE</code>,
+ false for <code>X IS [NOT] FALSE</code> predicates.
+ */
+ const bool value;
+ /**
+ True for <code>X IS Y</code>, false for <code>X IS NOT Y</code> predicates.
+ */
+ const bool affirmative;
+};
+
+
+/**
+ This Item represents a <code>X IS TRUE</code> boolean predicate.
+*/
+
+class Item_func_istrue : public Item_func_truth
+{
+public:
+ Item_func_istrue(Item *a) : Item_func_truth(a, true, true) {}
+ ~Item_func_istrue() {}
+ virtual const char* func_name() const { return "istrue"; }
+};
+
+
+/**
+ This Item represents a <code>X IS NOT TRUE</code> boolean predicate.
+*/
+
+class Item_func_isnottrue : public Item_func_truth
+{
+public:
+ Item_func_isnottrue(Item *a) : Item_func_truth(a, true, false) {}
+ ~Item_func_isnottrue() {}
+ virtual const char* func_name() const { return "isnottrue"; }
+};
+
+
+/**
+ This Item represents a <code>X IS FALSE</code> boolean predicate.
+*/
+
+class Item_func_isfalse : public Item_func_truth
+{
+public:
+ Item_func_isfalse(Item *a) : Item_func_truth(a, false, true) {}
+ ~Item_func_isfalse() {}
+ virtual const char* func_name() const { return "isfalse"; }
+};
+
+
+/**
+ This Item represents a <code>X IS NOT FALSE</code> boolean predicate.
+*/
+
+class Item_func_isnotfalse : public Item_func_truth
+{
+public:
+ Item_func_isnotfalse(Item *a) : Item_func_truth(a, false, false) {}
+ ~Item_func_isnotfalse() {}
+ virtual const char* func_name() const { return "isnotfalse"; }
+};
+
+
class Item_cache;
#define UNKNOWN ((my_bool)-1)
@@ -271,6 +360,7 @@ public:
const char *func_name() const { return "not"; }
Item *neg_transformer(THD *thd);
bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ void print(String *str);
};
class Item_maxmin_subselect;
@@ -313,6 +403,7 @@ public:
enum Functype functype() const { return TRIG_COND_FUNC; };
const char *func_name() const { return "trigcond"; };
bool const_item() const { return FALSE; }
+ bool *get_trig_var() { return trig_var; }
};
class Item_func_not_all :public Item_func_not
@@ -813,10 +904,10 @@ public:
return (value_res ? (res ? sortcmp(value_res, res, cmp_charset) : 1) :
(res ? -1 : 0));
}
- int compare(cmp_item *c)
+ int compare(cmp_item *ci)
{
- cmp_item_string *cmp= (cmp_item_string *)c;
- return sortcmp(value_res, cmp->value_res, cmp_charset);
+ cmp_item_string *l_cmp= (cmp_item_string *) ci;
+ return sortcmp(value_res, l_cmp->value_res, cmp_charset);
}
cmp_item *make_same();
void set_charset(CHARSET_INFO *cs)
@@ -839,10 +930,10 @@ public:
{
return value != arg->val_int();
}
- int compare(cmp_item *c)
+ int compare(cmp_item *ci)
{
- cmp_item_int *cmp= (cmp_item_int *)c;
- return (value < cmp->value) ? -1 : ((value == cmp->value) ? 0 : 1);
+ cmp_item_int *l_cmp= (cmp_item_int *)ci;
+ return (value < l_cmp->value) ? -1 : ((value == l_cmp->value) ? 0 : 1);
}
cmp_item *make_same();
};
@@ -860,10 +951,10 @@ public:
{
return value != arg->val_real();
}
- int compare(cmp_item *c)
+ int compare(cmp_item *ci)
{
- cmp_item_real *cmp= (cmp_item_real *)c;
- return (value < cmp->value)? -1 : ((value == cmp->value) ? 0 : 1);
+ cmp_item_real *l_cmp= (cmp_item_real *) ci;
+ return (value < l_cmp->value)? -1 : ((value == l_cmp->value) ? 0 : 1);
}
cmp_item *make_same();
};
@@ -929,10 +1020,10 @@ public:
DBUG_ASSERT(0);
return 1;
}
- int compare(cmp_item *c)
+ int compare(cmp_item *ci)
{
- cmp_item_string *cmp= (cmp_item_string *)c;
- return sortcmp(value_res, cmp->value_res, cmp_charset);
+ cmp_item_string *l_cmp= (cmp_item_string *) ci;
+ return sortcmp(value_res, l_cmp->value_res, cmp_charset);
}
cmp_item *make_same()
{
@@ -1033,14 +1124,25 @@ public:
class Item_func_in :public Item_func_opt_neg
{
public:
+ Item_result cmp_type;
+ /*
+ an array of values when the right hand arguments of IN
+ are all SQL constant and there are no nulls
+ */
in_vector *array;
bool have_null;
+ /*
+ true when all arguments of the IN clause are of compatible types
+ and can be used safely as comparisons for key conditions
+ */
+ bool arg_types_compatible;
Item_result left_result_type;
cmp_item *cmp_items[5]; /* One cmp_item for each result type */
DTCollation cmp_collation;
Item_func_in(List<Item> &list)
- :Item_func_opt_neg(list), array(0), have_null(0)
+ :Item_func_opt_neg(list), array(0), have_null(0),
+ arg_types_compatible(FALSE)
{
bzero(&cmp_items, sizeof(cmp_items));
allowed_arg_cols= 0; // Fetch this value from first argument
@@ -1064,7 +1166,7 @@ public:
DBUG_VOID_RETURN;
}
optimize_type select_optimize() const
- { return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; }
+ { return OPTIMIZE_KEY; }
void print(String *str);
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
@@ -1371,7 +1473,6 @@ class Item_equal: public Item_bool_func
Item *const_item; /* optional constant item equal to fields items */
cmp_item *eval_item;
bool cond_false;
- DTCollation cmp_collation;
public:
inline Item_equal()
: Item_bool_func(), const_item(0), eval_item(0), cond_false(0)
@@ -1445,7 +1546,7 @@ public:
Item_cond_and() :Item_cond() {}
Item_cond_and(Item *i1,Item *i2) :Item_cond(i1,i2) {}
Item_cond_and(THD *thd, Item_cond_and *item) :Item_cond(thd, item) {}
- Item_cond_and(List<Item> &list): Item_cond(list) {}
+ Item_cond_and(List<Item> &list_arg): Item_cond(list_arg) {}
enum Functype functype() const { return COND_AND_FUNC; }
longlong val_int();
const char *func_name() const { return "and"; }
@@ -1467,7 +1568,7 @@ public:
Item_cond_or() :Item_cond() {}
Item_cond_or(Item *i1,Item *i2) :Item_cond(i1,i2) {}
Item_cond_or(THD *thd, Item_cond_or *item) :Item_cond(thd, item) {}
- Item_cond_or(List<Item> &list): Item_cond(list) {}
+ Item_cond_or(List<Item> &list_arg): Item_cond(list_arg) {}
enum Functype functype() const { return COND_OR_FUNC; }
longlong val_int();
const char *func_name() const { return "or"; }
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 1e89a579420..55888f6b16a 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -232,6 +232,8 @@ void Item_func::traverse_cond(Cond_traverser traverser,
(*traverser)(this, argument);
}
}
+ else
+ (*traverser)(this, argument);
}
@@ -997,7 +999,7 @@ String *Item_decimal_typecast::val_str(String *str)
my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
if (null_value)
return NULL;
- my_decimal2string(E_DEC_FATAL_ERROR, &tmp_buf, 0, 0, 0, str);
+ my_decimal2string(E_DEC_FATAL_ERROR, tmp, 0, 0, 0, str);
return str;
}
@@ -2042,6 +2044,18 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
}
+void Item_func_rand::seed_random(Item *arg)
+{
+ /*
+ TODO: do not do reinit 'rand' for every execute of PS/SP if
+ args[0] is a constant.
+ */
+ uint32 tmp= (uint32) arg->val_int();
+ randominit(rand, (uint32) (tmp*0x10001L+55555555L),
+ (uint32) (tmp*0x10000001L));
+}
+
+
bool Item_func_rand::fix_fields(THD *thd,Item **ref)
{
if (Item_real_func::fix_fields(thd, ref))
@@ -2049,11 +2063,6 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref)
used_tables_cache|= RAND_TABLE_BIT;
if (arg_count)
{ // Only use argument once in query
- if (!args[0]->const_during_execution())
- {
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "RAND");
- return TRUE;
- }
/*
Allocate rand structure once: we must use thd->stmt_arena
to create rand in proper mem_root if it's a prepared statement or
@@ -2065,20 +2074,9 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref)
if (!rand && !(rand= (struct rand_struct*)
thd->stmt_arena->alloc(sizeof(*rand))))
return TRUE;
- /*
- PARAM_ITEM is returned if we're in statement prepare and consequently
- no placeholder value is set yet.
- */
- if (args[0]->type() != PARAM_ITEM)
- {
- /*
- TODO: do not do reinit 'rand' for every execute of PS/SP if
- args[0] is a constant.
- */
- uint32 tmp= (uint32) args[0]->val_int();
- randominit(rand, (uint32) (tmp*0x10001L+55555555L),
- (uint32) (tmp*0x10000001L));
- }
+
+ if (args[0]->const_item())
+ seed_random (args[0]);
}
else
{
@@ -2108,6 +2106,8 @@ void Item_func_rand::update_used_tables()
double Item_func_rand::val_real()
{
DBUG_ASSERT(fixed == 1);
+ if (arg_count && !args[0]->const_item())
+ seed_random (args[0]);
return my_rnd(rand);
}
@@ -2377,7 +2377,7 @@ longlong Item_func_locate::val_int()
b->ptr(), b->length(),
&match, 1))
return 0;
- return (longlong) match.mblen + start0 + 1;
+ return (longlong) match.mb_len + start0 + 1;
}
@@ -2746,25 +2746,28 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
if (arguments[i]->const_item())
{
- if (arguments[i]->null_value)
- continue;
-
switch (arguments[i]->result_type())
{
case STRING_RESULT:
case DECIMAL_RESULT:
{
String *res= arguments[i]->val_str(&buffers[i]);
+ if (arguments[i]->null_value)
+ continue;
f_args.args[i]= (char*) res->ptr();
break;
}
case INT_RESULT:
*((longlong*) to)= arguments[i]->val_int();
+ if (arguments[i]->null_value)
+ continue;
f_args.args[i]= to;
to+= ALIGN_SIZE(sizeof(longlong));
break;
case REAL_RESULT:
*((double*) to)= arguments[i]->val_real();
+ if (arguments[i]->null_value)
+ continue;
f_args.args[i]= to;
to+= ALIGN_SIZE(sizeof(double));
break;
@@ -3084,8 +3087,8 @@ public:
int count;
bool locked;
pthread_cond_t cond;
- pthread_t thread;
- ulong thread_id;
+ my_thread_id thread_id;
+ void set_thread(THD *thd) { thread_id= thd->thread_id; }
User_level_lock(const char *key_arg,uint length, ulong id)
:key_length(length),count(1),locked(1), thread_id(id)
@@ -3172,9 +3175,9 @@ longlong Item_master_pos_wait::val_int()
null_value = 1;
return 0;
}
+#ifdef HAVE_REPLICATION
longlong pos = (ulong)args[1]->val_int();
longlong timeout = (arg_count==3) ? args[2]->val_int() : 0 ;
-#ifdef HAVE_REPLICATION
if ((event_count = active_mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2)
{
null_value = 1;
@@ -3238,7 +3241,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
else
{
ull->locked=1;
- ull->thread=thd->real_id;
+ ull->set_thread(thd);
thd->ull=ull;
}
pthread_mutex_unlock(&LOCK_user_locks);
@@ -3313,7 +3316,7 @@ longlong Item_func_get_lock::val_int()
null_value=1; // Probably out of memory
return 0;
}
- ull->thread=thd->real_id;
+ ull->set_thread(thd);
thd->ull=ull;
pthread_mutex_unlock(&LOCK_user_locks);
return 1; // Got new lock
@@ -3354,7 +3357,7 @@ longlong Item_func_get_lock::val_int()
else // We got the lock
{
ull->locked=1;
- ull->thread=thd->real_id;
+ ull->set_thread(thd);
ull->thread_id= thd->thread_id;
thd->ull=ull;
error=0;
@@ -3402,11 +3405,7 @@ longlong Item_func_release_lock::val_int()
}
else
{
-#ifdef EMBEDDED_LIBRARY
- if (ull->locked && pthread_equal(current_thd->real_id,ull->thread))
-#else
- if (ull->locked && pthread_equal(pthread_self(),ull->thread))
-#endif
+ if (ull->locked && current_thd->thread_id == ull->thread_id)
{
result=1; // Release is ok
item_user_lock_release(ull);
@@ -3448,10 +3447,11 @@ longlong Item_func_benchmark::val_int()
DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff), &my_charset_bin);
+ my_decimal tmp_decimal;
THD *thd=current_thd;
ulong loop_count;
- loop_count= args[0]->val_int();
+ loop_count= (ulong) args[0]->val_int();
if (args[0]->null_value)
{
@@ -3472,6 +3472,9 @@ longlong Item_func_benchmark::val_int()
case STRING_RESULT:
(void) args[1]->val_str(&tmp);
break;
+ case DECIMAL_RESULT:
+ (void) args[1]->val_decimal(&tmp_decimal);
+ break;
case ROW_RESULT:
default:
// This case should never be chosen
@@ -3710,7 +3713,8 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
bool
-Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type,
+Item_func_set_user_var::update_hash(void *ptr, uint length,
+ Item_result res_type,
CHARSET_INFO *cs, Derivation dv,
bool unsigned_arg)
{
@@ -3719,9 +3723,9 @@ Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type,
result type of the variable
*/
if ((null_value= args[0]->null_value) && null_item)
- type= entry->type; // Don't change type of item
+ res_type= entry->type; // Don't change type of item
if (::update_hash(entry, (null_value= args[0]->null_value),
- ptr, length, type, cs, dv, unsigned_arg))
+ ptr, length, res_type, cs, dv, unsigned_arg))
{
current_thd->fatal_error(); // Probably end of memory
null_value= 1;
@@ -4220,7 +4224,14 @@ int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
user_var_entry *var_entry;
var_entry= get_variable(&thd->user_vars, name, 0);
- if (!(opt_bin_log && is_update_query(sql_command)))
+ /*
+ Any reference to user-defined variable which is done from stored
+ function or trigger affects their execution and the execution of the
+ calling statement. We must log all such variables even if they are
+ not involved in table-updating statements.
+ */
+ if (!(opt_bin_log &&
+ (is_update_query(sql_command) || thd->in_sub_stmt)))
{
*out_entry= var_entry;
return 0;
@@ -4859,7 +4870,7 @@ longlong Item_func_bit_xor::val_int()
thd Thread handler
var_type global / session
name Name of base or system variable
- component Component.
+ component Component
NOTES
If component.str = 0 then the variable name is in 'name'
@@ -4971,8 +4982,9 @@ longlong Item_func_row_count::val_int()
}
-Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name)
- :Item_func(), context(context_arg), m_name(name), m_sp(NULL),
+Item_func_sp::Item_func_sp(Name_resolution_context *context_arg,
+ sp_name *name_arg)
+ :Item_func(), context(context_arg), m_name(name_arg), m_sp(NULL),
result_field(NULL)
{
maybe_null= 1;
@@ -4983,8 +4995,8 @@ Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name)
Item_func_sp::Item_func_sp(Name_resolution_context *context_arg,
- sp_name *name, List<Item> &list)
- :Item_func(list), context(context_arg), m_name(name), m_sp(NULL),
+ sp_name *name_arg, List<Item> &list)
+ :Item_func(list), context(context_arg), m_name(name_arg), m_sp(NULL),
result_field(NULL)
{
maybe_null= 1;
diff --git a/sql/item_func.h b/sql/item_func.h
index 7810c0ce9a9..3306b059097 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -679,6 +679,8 @@ public:
bool const_item() const { return 0; }
void update_used_tables();
bool fix_fields(THD *thd, Item **ref);
+private:
+ void seed_random (Item * val);
};
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 1b8c8d6a161..35a9f026b1d 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -701,8 +701,9 @@ double Item_func_glength::val_real()
null_value= (!swkb ||
!(geom= Geometry::construct(&buffer,
- swkb->ptr(), swkb->length())) ||
- geom->length(&res));
+ swkb->ptr(),
+ swkb->length())) ||
+ geom->geom_length(&res));
return res;
}
diff --git a/sql/item_row.h b/sql/item_row.h
index 503e48ca16b..d55d3ae223f 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -71,7 +71,7 @@ public:
Item *transform(Item_transformer transformer, byte *arg);
uint cols() { return arg_count; }
- Item* el(uint i) { return items[i]; }
+ Item* element_index(uint i) { return items[i]; }
Item** addr(uint i) { return items + i; }
bool check_cols(uint c);
bool null_inside() { return with_null; };
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 89a85a19f56..acc522b1b46 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -25,9 +25,6 @@
#include "mysql_priv.h"
#include <m_ctype.h>
-#ifdef HAVE_OPENSSL
-#include <openssl/des.h>
-#endif /* HAVE_OPENSSL */
#include "md5.h"
#include "sha1.h"
#include "my_aes.h"
@@ -37,15 +34,6 @@ C_MODE_END
String my_empty_string("",default_charset_info);
-static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
- const char *fname)
-{
- my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0),
- c1.collation->name, c1.derivation_name(),
- c2.collation->name, c2.derivation_name(),
- fname);
-}
-
String *Item_str_func::check_well_formed_result(String *str)
{
@@ -1935,7 +1923,7 @@ String *Item_func_format::val_str(String *str)
int diff;
DBUG_ASSERT(fixed == 1);
- dec= args[1]->val_int();
+ dec= (int) args[1]->val_int();
if (args[1]->null_value)
{
null_value=1;
@@ -3273,15 +3261,17 @@ String *Item_func_uuid::val_str(String *str)
int i;
if (my_gethwaddr(mac))
{
+ /* purecov: begin inspected */
/*
generating random "hardware addr"
and because specs explicitly specify that it should NOT correlate
with a clock_seq value (initialized random below), we use a separate
randominit() here
*/
- randominit(&uuid_rand, tmp + (ulong) thd, tmp + (ulong)query_id);
+ randominit(&uuid_rand, tmp + (ulong) thd, tmp + (ulong)global_query_id);
for (i=0; i < (int)sizeof(mac); i++)
mac[i]=(uchar)(my_rnd(&uuid_rand)*255);
+ /* purecov: end */
}
s=clock_seq_and_node_str+sizeof(clock_seq_and_node_str)-1;
for (i=sizeof(mac)-1 ; i>=0 ; i--)
@@ -3289,7 +3279,7 @@ String *Item_func_uuid::val_str(String *str)
*--s=_dig_vec_lower[mac[i] & 15];
*--s=_dig_vec_lower[mac[i] >> 4];
}
- randominit(&uuid_rand, tmp + (ulong)start_time,
+ randominit(&uuid_rand, tmp + (ulong) server_start_time,
tmp + thd->status_var.bytes_sent);
set_clock_seq_str();
}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index f3f840bdaa9..135ed33feec 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -51,6 +51,10 @@ Item_subselect::Item_subselect():
void Item_subselect::init(st_select_lex *select_lex,
select_subselect *result)
{
+ /*
+ Please see Item_singlerow_subselect::invalidate_and_restore_select_lex(),
+ which depends on alterations to the parse tree implemented here.
+ */
DBUG_ENTER("Item_subselect::init");
DBUG_PRINT("enter", ("select_lex: 0x%lx", (long) select_lex));
@@ -91,6 +95,12 @@ void Item_subselect::init(st_select_lex *select_lex,
DBUG_VOID_RETURN;
}
+st_select_lex *
+Item_subselect::get_select_lex()
+{
+ return unit->first_select();
+}
+
void Item_subselect::cleanup()
{
DBUG_ENTER("Item_subselect::cleanup");
@@ -234,16 +244,20 @@ bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
}
-bool Item_subselect::exec(bool full_scan)
+bool Item_subselect::exec()
{
int res;
- res= engine->exec(full_scan);
+ if (thd->net.report_error)
+ /* Do not execute subselect in case of a fatal error */
+ return 1;
+
+ res= engine->exec();
if (engine_changed)
{
engine_changed= 0;
- return exec(full_scan);
+ return exec();
}
return (res);
}
@@ -271,11 +285,11 @@ bool Item_subselect::const_item() const
return const_item_cache;
}
-Item *Item_subselect::get_tmp_table_item(THD *thd)
+Item *Item_subselect::get_tmp_table_item(THD *thd_arg)
{
if (!with_sum_func && !const_item())
return new Item_field(result_field);
- return copy_or_same(thd);
+ return copy_or_same(thd_arg);
}
void Item_subselect::update_used_tables()
@@ -307,6 +321,26 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex)
DBUG_VOID_RETURN;
}
+st_select_lex *
+Item_singlerow_subselect::invalidate_and_restore_select_lex()
+{
+ DBUG_ENTER("Item_singlerow_subselect::invalidate_and_restore_select_lex");
+ st_select_lex *result= get_select_lex();
+
+ DBUG_ASSERT(result);
+
+ /*
+ This code restore the parse tree in it's state before the execution of
+ Item_singlerow_subselect::Item_singlerow_subselect(),
+ and in particular decouples this object from the SELECT_LEX,
+ so that the SELECT_LEX can be used with a different flavor
+ or Item_subselect instead, as part of query rewriting.
+ */
+ unit->item= NULL;
+
+ DBUG_RETURN(result);
+}
+
Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param,
Item_subselect *parent,
st_select_lex *select_lex,
@@ -491,13 +525,13 @@ bool Item_singlerow_subselect::null_inside()
void Item_singlerow_subselect::bring_value()
{
- exec(FALSE);
+ exec();
}
double Item_singlerow_subselect::val_real()
{
DBUG_ASSERT(fixed == 1);
- if (!exec(FALSE) && !value->null_value)
+ if (!exec() && !value->null_value)
{
null_value= 0;
return value->val_real();
@@ -512,7 +546,7 @@ double Item_singlerow_subselect::val_real()
longlong Item_singlerow_subselect::val_int()
{
DBUG_ASSERT(fixed == 1);
- if (!exec(FALSE) && !value->null_value)
+ if (!exec() && !value->null_value)
{
null_value= 0;
return value->val_int();
@@ -526,7 +560,7 @@ longlong Item_singlerow_subselect::val_int()
String *Item_singlerow_subselect::val_str(String *str)
{
- if (!exec(FALSE) && !value->null_value)
+ if (!exec() && !value->null_value)
{
null_value= 0;
return value->val_str(str);
@@ -541,7 +575,7 @@ String *Item_singlerow_subselect::val_str(String *str)
my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value)
{
- if (!exec(FALSE) && !value->null_value)
+ if (!exec() && !value->null_value)
{
null_value= 0;
return value->val_decimal(decimal_value);
@@ -556,7 +590,7 @@ my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value)
bool Item_singlerow_subselect::val_bool()
{
- if (!exec(FALSE) && !value->null_value)
+ if (!exec() && !value->null_value)
{
null_value= 0;
return value->val_bool();
@@ -590,13 +624,13 @@ void Item_exists_subselect::print(String *str)
}
-bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit)
+bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit_arg)
{
- if (unit->fake_select_lex &&
- unit->fake_select_lex->test_limit())
+ if (unit_arg->fake_select_lex &&
+ unit_arg->fake_select_lex->test_limit())
return(1);
- SELECT_LEX *sl= unit->first_select();
+ SELECT_LEX *sl= unit_arg->first_select();
for (; sl; sl= sl->next_select())
{
if (sl->test_limit())
@@ -608,7 +642,7 @@ bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit)
Item_in_subselect::Item_in_subselect(Item * left_exp,
st_select_lex *select_lex):
Item_exists_subselect(), optimizer(0), transformed(0),
- enable_pushed_conds(TRUE), upper_item(0)
+ pushed_cond_guards(NULL), upper_item(0)
{
DBUG_ENTER("Item_in_subselect::Item_in_subselect");
left_expr= left_exp;
@@ -653,7 +687,7 @@ void Item_exists_subselect::fix_length_and_dec()
double Item_exists_subselect::val_real()
{
DBUG_ASSERT(fixed == 1);
- if (exec(FALSE))
+ if (exec())
{
reset();
return 0;
@@ -664,7 +698,7 @@ double Item_exists_subselect::val_real()
longlong Item_exists_subselect::val_int()
{
DBUG_ASSERT(fixed == 1);
- if (exec(FALSE))
+ if (exec())
{
reset();
return 0;
@@ -675,7 +709,7 @@ longlong Item_exists_subselect::val_int()
String *Item_exists_subselect::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- if (exec(FALSE))
+ if (exec())
{
reset();
return 0;
@@ -688,7 +722,7 @@ String *Item_exists_subselect::val_str(String *str)
my_decimal *Item_exists_subselect::val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
- if (exec(FALSE))
+ if (exec())
{
reset();
return 0;
@@ -701,7 +735,7 @@ my_decimal *Item_exists_subselect::val_decimal(my_decimal *decimal_value)
bool Item_exists_subselect::val_bool()
{
DBUG_ASSERT(fixed == 1);
- if (exec(FALSE))
+ if (exec())
{
reset();
return 0;
@@ -719,7 +753,7 @@ double Item_in_subselect::val_real()
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
null_value= 0;
- if (exec(!enable_pushed_conds))
+ if (exec())
{
reset();
null_value= 1;
@@ -740,7 +774,7 @@ longlong Item_in_subselect::val_int()
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
null_value= 0;
- if (exec(!enable_pushed_conds))
+ if (exec())
{
reset();
null_value= 1;
@@ -761,7 +795,7 @@ String *Item_in_subselect::val_str(String *str)
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
null_value= 0;
- if (exec(!enable_pushed_conds))
+ if (exec())
{
reset();
null_value= 1;
@@ -781,7 +815,7 @@ bool Item_in_subselect::val_bool()
{
DBUG_ASSERT(fixed == 1);
null_value= 0;
- if (exec(!enable_pushed_conds))
+ if (exec())
{
reset();
null_value= 1;
@@ -801,7 +835,7 @@ my_decimal *Item_in_subselect::val_decimal(my_decimal *decimal_value)
DBUG_ASSERT(0);
null_value= 0;
DBUG_ASSERT(fixed == 1);
- if (exec(!enable_pushed_conds))
+ if (exec())
{
reset();
null_value= 1;
@@ -868,7 +902,6 @@ Item_subselect::trans_res
Item_in_subselect::single_value_transformer(JOIN *join,
Comp_creator *func)
{
- Item_subselect::trans_res result= RES_ERROR;
SELECT_LEX *select_lex= join->select_lex;
DBUG_ENTER("Item_in_subselect::single_value_transformer");
@@ -965,8 +998,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (!substitution)
{
- //first call for this unit
- SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ /* We're invoked for the 1st (or the only) SELECT in the subquery UNION */
+ SELECT_LEX_UNIT *master_unit= select_lex->master_unit();
substitution= optimizer;
SELECT_LEX *current= thd->lex->current_select, *up;
@@ -989,21 +1022,16 @@ Item_in_subselect::single_value_transformer(JOIN *join,
(char *)"<no matter>",
(char *)in_left_expr_name);
- unit->uncacheable|= UNCACHEABLE_DEPENDENT;
+ master_unit->uncacheable|= UNCACHEABLE_DEPENDENT;
+ }
+ if (!abort_on_null && left_expr->maybe_null && !pushed_cond_guards)
+ {
+ if (!(pushed_cond_guards= (bool*)join->thd->alloc(sizeof(bool))))
+ DBUG_RETURN(RES_ERROR);
+ pushed_cond_guards[0]= TRUE;
}
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
- /*
- Add the left part of a subselect to a WHERE or HAVING clause of
- the right part, e.g.
-
- SELECT 1 IN (SELECT a FROM t1) =>
-
- SELECT Item_in_optimizer(1, SELECT a FROM t1 WHERE a=1)
-
- HAVING is used only if the right part contains a SUM function, a GROUP
- BY or a HAVING clause.
- */
if (join->having || select_lex->with_sum_func ||
select_lex->group_list.elements)
{
@@ -1015,13 +1043,13 @@ Item_in_subselect::single_value_transformer(JOIN *join,
ref_pointer_array,
(char *)"<ref>",
this->full_name()));
- if (!abort_on_null && ((Item*)select_lex->item_list.head())->maybe_null)
+ if (!abort_on_null && left_expr->maybe_null)
{
/*
We can encounter "NULL IN (SELECT ...)". Wrap the added condition
- within a trigger.
+ within a trig_cond.
*/
- item= new Item_func_trig_cond(item, &enable_pushed_conds);
+ item= new Item_func_trig_cond(item, get_cond_guard(0));
}
/*
@@ -1030,6 +1058,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
argument (reference) to fix_fields()
*/
select_lex->having= join->having= and_items(join->having, item);
+ if (join->having == item)
+ item->name= (char*)in_having_cond;
select_lex->having_fix_field= 1;
/*
we do not check join->having->fixed, because Item_and (from and_items)
@@ -1056,14 +1086,19 @@ Item_in_subselect::single_value_transformer(JOIN *join,
item= func->create(expr, item);
if (!abort_on_null && orig_item->maybe_null)
{
- having=
- new Item_func_trig_cond(new Item_is_not_null_test(this, having),
- &enable_pushed_conds);
+ having= new Item_is_not_null_test(this, having);
+ if (left_expr->maybe_null)
+ {
+ if (!(having= new Item_func_trig_cond(having,
+ get_cond_guard(0))))
+ DBUG_RETURN(RES_ERROR);
+ }
/*
Item_is_not_null_test can't be changed during fix_fields()
we can assign select_lex->having here, and pass 0 as last
argument (reference) to fix_fields()
*/
+ having->name= (char*)in_having_cond;
select_lex->having= join->having= having;
select_lex->having_fix_field= 1;
/*
@@ -1075,17 +1110,25 @@ Item_in_subselect::single_value_transformer(JOIN *join,
select_lex->having_fix_field= 0;
if (tmp)
DBUG_RETURN(RES_ERROR);
- /*
- NOTE: It is important that we add this "IS NULL" here, even when
- orig_item can't be NULL. This is needed so that this predicate is
- only used by ref[_or_null] analyzer (and, e.g. is not used by const
- propagation).
- */
item= new Item_cond_or(item,
new Item_func_isnull(orig_item));
- item= new Item_func_trig_cond(item, &enable_pushed_conds);
}
+ /*
+ If we may encounter NULL IN (SELECT ...) and care whether subquery
+ result is NULL or FALSE, wrap condition in a trig_cond.
+ */
+ if (!abort_on_null && left_expr->maybe_null)
+ {
+ if (!(item= new Item_func_trig_cond(item, get_cond_guard(0))))
+ DBUG_RETURN(RES_ERROR);
+ }
+ /*
+ TODO: figure out why the following is done here in
+ single_value_transformer but there is no corresponding action in
+ row_value_transformer?
+ */
item->name= (char *)in_additional_cond;
+
/*
AND can't be changed during fix_fields()
we can assign select_lex->having here, and pass 0 as last
@@ -1116,10 +1159,16 @@ Item_in_subselect::single_value_transformer(JOIN *join,
select_lex->ref_pointer_array,
(char *)"<no matter>",
(char *)"<result>"));
- new_having= new Item_func_trig_cond(new_having, &enable_pushed_conds);
+ if (!abort_on_null && left_expr->maybe_null)
+ {
+ if (!(new_having= new Item_func_trig_cond(new_having,
+ get_cond_guard(0))))
+ DBUG_RETURN(RES_ERROR);
+ }
+ new_having->name= (char*)in_having_cond;
select_lex->having= join->having= new_having;
-
select_lex->having_fix_field= 1;
+
/*
we do not check join->having->fixed, because comparison function
(from func->create) can't be fixed after creation
@@ -1172,7 +1221,7 @@ Item_in_subselect::row_value_transformer(JOIN *join)
if (!substitution)
{
//first call for this unit
- SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ SELECT_LEX_UNIT *master_unit= select_lex->master_unit();
substitution= optimizer;
SELECT_LEX *current= thd->lex->current_select, *up;
@@ -1188,7 +1237,16 @@ Item_in_subselect::row_value_transformer(JOIN *join)
optimizer->keep_top_level_cache();
thd->lex->current_select= current;
- unit->uncacheable|= UNCACHEABLE_DEPENDENT;
+ master_unit->uncacheable|= UNCACHEABLE_DEPENDENT;
+
+ if (!abort_on_null && left_expr->maybe_null && !pushed_cond_guards)
+ {
+ if (!(pushed_cond_guards= (bool*)join->thd->alloc(sizeof(bool) *
+ left_expr->cols())))
+ DBUG_RETURN(RES_ERROR);
+ for (uint i= 0; i < cols_num; i++)
+ pushed_cond_guards[i]= TRUE;
+ }
}
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
@@ -1205,13 +1263,14 @@ Item_in_subselect::row_value_transformer(JOIN *join)
is_not_null_test(v3))
where is_not_null_test used to register nulls in case if we have
not found matching to return correct NULL value
+ TODO: say here explicitly if the order of AND parts matters or not.
*/
Item *item_having_part2= 0;
for (uint i= 0; i < cols_num; i++)
{
DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed);
if (select_lex->ref_pointer_array[i]->
- check_cols(left_expr->el(i)->cols()))
+ check_cols(left_expr->element_index(i)->cols()))
DBUG_RETURN(RES_ERROR);
Item *item_eq=
new Item_func_eq(new
@@ -1233,21 +1292,28 @@ Item_in_subselect::row_value_transformer(JOIN *join)
(char *)"<no matter>",
(char *)"<list ref>")
);
- having_item=
- and_items(having_item,
- new Item_cond_or(item_eq, item_isnull));
- item_having_part2=
- and_items(item_having_part2,
- new
- Item_is_not_null_test(this,
- new
- Item_ref(&select_lex->context,
- select_lex->
- ref_pointer_array + i,
- (char *)"<no matter>",
- (char *)"<list ref>")
- )
- );
+ Item *col_item= new Item_cond_or(item_eq, item_isnull);
+ if (!abort_on_null && left_expr->element_index(i)->maybe_null)
+ {
+ if (!(col_item= new Item_func_trig_cond(col_item, get_cond_guard(i))))
+ DBUG_RETURN(RES_ERROR);
+ }
+ having_item= and_items(having_item, col_item);
+
+ Item *item_nnull_test=
+ new Item_is_not_null_test(this,
+ new Item_ref(&select_lex->context,
+ select_lex->
+ ref_pointer_array + i,
+ (char *)"<no matter>",
+ (char *)"<list ref>"));
+ if (!abort_on_null && left_expr->element_index(i)->maybe_null)
+ {
+ if (!(item_nnull_test=
+ new Item_func_trig_cond(item_nnull_test, get_cond_guard(i))))
+ DBUG_RETURN(RES_ERROR);
+ }
+ item_having_part2= and_items(item_having_part2, item_nnull_test);
item_having_part2->top_level_item();
}
having_item= and_items(having_item, item_having_part2);
@@ -1278,7 +1344,7 @@ Item_in_subselect::row_value_transformer(JOIN *join)
Item *item, *item_isnull;
DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed);
if (select_lex->ref_pointer_array[i]->
- check_cols(left_expr->el(i)->cols()))
+ check_cols(left_expr->element_index(i)->cols()))
DBUG_RETURN(RES_ERROR);
item=
new Item_func_eq(new
@@ -1296,18 +1362,15 @@ Item_in_subselect::row_value_transformer(JOIN *join)
);
if (!abort_on_null)
{
- having_item=
- and_items(having_item,
- new
- Item_is_not_null_test(this,
- new
- Item_ref(&select_lex->context,
- select_lex->
- ref_pointer_array + i,
- (char *)"<no matter>",
- (char *)"<list ref>")
- )
- );
+ Item *having_col_item=
+ new Item_is_not_null_test(this,
+ new
+ Item_ref(&select_lex->context,
+ select_lex->ref_pointer_array + i,
+ (char *)"<no matter>",
+ (char *)"<list ref>"));
+
+
item_isnull= new
Item_func_isnull(new
Item_direct_ref(&select_lex->context,
@@ -1316,14 +1379,23 @@ Item_in_subselect::row_value_transformer(JOIN *join)
(char *)"<no matter>",
(char *)"<list ref>")
);
-
item= new Item_cond_or(item, item_isnull);
+ /*
+ TODO: why we create the above for cases where the right part
+ cant be NULL?
+ */
+ if (left_expr->element_index(i)->maybe_null)
+ {
+ if (!(item= new Item_func_trig_cond(item, get_cond_guard(i))))
+ DBUG_RETURN(RES_ERROR);
+ if (!(having_col_item=
+ new Item_func_trig_cond(having_col_item, get_cond_guard(i))))
+ DBUG_RETURN(RES_ERROR);
+ }
+ having_item= and_items(having_item, having_col_item);
}
-
where_item= and_items(where_item, item);
}
- if (where_item)
- where_item= new Item_func_trig_cond(where_item, &enable_pushed_conds);
/*
AND can't be changed during fix_fields()
we can assign select_lex->where here, and pass 0 as last
@@ -1337,9 +1409,9 @@ Item_in_subselect::row_value_transformer(JOIN *join)
if (having_item)
{
bool res;
- having_item= new Item_func_trig_cond(having_item, &enable_pushed_conds);
-
select_lex->having= join->having= and_items(join->having, having_item);
+ if (having_item == select_lex->having)
+ having_item->name= (char*)in_having_cond;
select_lex->having->top_level_item();
/*
AND can't be changed during fix_fields()
@@ -1474,14 +1546,14 @@ void Item_in_subselect::print(String *str)
}
-bool Item_in_subselect::fix_fields(THD *thd, Item **ref)
+bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref)
{
bool result = 0;
- if(thd->lex->view_prepare_mode && left_expr && !left_expr->fixed)
- result = left_expr->fix_fields(thd, &left_expr);
+ if (thd_arg->lex->view_prepare_mode && left_expr && !left_expr->fixed)
+ result = left_expr->fix_fields(thd_arg, &left_expr);
- return result || Item_subselect::fix_fields(thd, ref);
+ return result || Item_subselect::fix_fields(thd_arg, ref);
}
@@ -1520,13 +1592,13 @@ void subselect_engine::set_thd(THD *thd_arg)
subselect_single_select_engine::
subselect_single_select_engine(st_select_lex *select,
- select_subselect *result,
- Item_subselect *item)
- :subselect_engine(item, result),
+ select_subselect *result_arg,
+ Item_subselect *item_arg)
+ :subselect_engine(item_arg, result_arg),
prepared(0), optimized(0), executed(0),
select_lex(select), join(0)
{
- select_lex->master_unit()->item= item;
+ select_lex->master_unit()->item= item_arg;
}
@@ -1725,7 +1797,7 @@ int init_read_record_seq(JOIN_TAB *tab);
int join_read_always_key_or_null(JOIN_TAB *tab);
int join_read_next_same_or_null(READ_RECORD *info);
-int subselect_single_select_engine::exec(bool full_scan)
+int subselect_single_select_engine::exec()
{
DBUG_ENTER("subselect_single_select_engine::exec");
char const *save_where= thd->where;
@@ -1763,9 +1835,12 @@ int subselect_single_select_engine::exec(bool full_scan)
if (!executed)
{
item->reset_value_registration();
- if (full_scan)
+ JOIN_TAB *changed_tabs[MAX_TABLES];
+ JOIN_TAB **last_changed_tab= changed_tabs;
+ if (item->have_guarded_conds())
{
/*
+ For at least one of the pushed predicates the following is true:
We should not apply optimizations based on the condition that was
pushed down into the subquery. Those optimizations are ref[_or_null]
acceses. Change them to be full table scans.
@@ -1773,32 +1848,36 @@ int subselect_single_select_engine::exec(bool full_scan)
for (uint i=join->const_tables ; i < join->tables ; i++)
{
JOIN_TAB *tab=join->join_tab+i;
- if (tab->keyuse && tab->keyuse->outer_ref)
+ if (tab && tab->keyuse)
{
- tab->read_first_record= init_read_record_seq;
- tab->read_record.record= tab->table->record[0];
- tab->read_record.thd= join->thd;
- tab->read_record.ref_length= tab->table->file->ref_length;
+ for (uint i= 0; i < tab->ref.key_parts; i++)
+ {
+ bool *cond_guard= tab->ref.cond_guards[i];
+ if (cond_guard && !*cond_guard)
+ {
+ /* Change the access method to full table scan */
+ tab->read_first_record= init_read_record_seq;
+ tab->read_record.record= tab->table->record[0];
+ tab->read_record.thd= join->thd;
+ tab->read_record.ref_length= tab->table->file->ref_length;
+ *(last_changed_tab++)= tab;
+ break;
+ }
+ }
}
}
}
join->exec();
- if (full_scan)
+ /* Enable the optimizations back */
+ for (JOIN_TAB **ptab= changed_tabs; ptab != last_changed_tab; ptab++)
{
- /* Enable the optimizations back */
- for (uint i=join->const_tables ; i < join->tables ; i++)
- {
- JOIN_TAB *tab=join->join_tab+i;
- if (tab->keyuse && tab->keyuse->outer_ref)
- {
- tab->read_record.record= 0;
- tab->read_record.ref_length= 0;
- tab->read_first_record= join_read_always_key_or_null;
- tab->read_record.read_record= join_read_next_same_or_null;
- }
- }
+ JOIN_TAB *tab= *ptab;
+ tab->read_record.record= 0;
+ tab->read_record.ref_length= 0;
+ tab->read_first_record= join_read_always_key_or_null;
+ tab->read_record.read_record= join_read_next_same_or_null;
}
executed= 1;
thd->where= save_where;
@@ -1810,13 +1889,9 @@ int subselect_single_select_engine::exec(bool full_scan)
DBUG_RETURN(0);
}
-int subselect_union_engine::exec(bool full_scan)
+int subselect_union_engine::exec()
{
char const *save_where= thd->where;
- /*
- Ignore the full_scan parameter: the pushed down predicates are only used
- for filtering, and the caller has disabled them if necessary.
- */
int res= unit->exec();
thd->where= save_where;
return res;
@@ -1824,7 +1899,7 @@ int subselect_union_engine::exec(bool full_scan)
/*
- Search for at least on row satisfying select condition
+ Search for at least one row satisfying select condition
SYNOPSIS
subselect_uniquesubquery_engine::scan_table()
@@ -1833,8 +1908,8 @@ int subselect_union_engine::exec(bool full_scan)
Scan the table using sequential access until we find at least one row
satisfying select condition.
- The result of this function (info about whether a row was found) is
- stored in this->empty_result_set.
+ The caller must set this->empty_result_set=FALSE before calling this
+ function. This function will set it to TRUE if it finds a matching row.
RETURN
FALSE - OK
@@ -1846,7 +1921,6 @@ int subselect_uniquesubquery_engine::scan_table()
int error;
TABLE *table= tab->table;
DBUG_ENTER("subselect_uniquesubquery_engine::scan_table");
- empty_result_set= TRUE;
if (table->file->inited)
table->file->ha_index_end();
@@ -1939,10 +2013,13 @@ bool subselect_uniquesubquery_engine::copy_ref_key()
- FALSE otherwise.
In some cases (IN subselect is a top level item, i.e. abort_on_null==TRUE)
- the caller doesn't distinguish between NULL and FALSE result and we just
+ the caller doesn't distinguish between NULL and FALSE result and we just
return FALSE.
- Otherwise we make a full table scan to see if there is at least one matching row.
-
+ Otherwise we make a full table scan to see if there is at least one
+ matching row.
+
+ The result of this function (info about whether a row was found) is
+ stored in this->empty_result_set.
NOTE
RETURN
@@ -1950,11 +2027,12 @@ bool subselect_uniquesubquery_engine::copy_ref_key()
TRUE - an error occured while scanning
*/
-int subselect_uniquesubquery_engine::exec(bool full_scan)
+int subselect_uniquesubquery_engine::exec()
{
DBUG_ENTER("subselect_uniquesubquery_engine::exec");
int error;
TABLE *table= tab->table;
+ empty_result_set= TRUE;
/* TODO: change to use of 'full_scan' here? */
if (copy_ref_key())
@@ -1975,9 +2053,13 @@ int subselect_uniquesubquery_engine::exec(bool full_scan)
{
error= 0;
table->null_row= 0;
- ((Item_in_subselect *) item)->value= (!table->status &&
- (!cond || cond->val_int()) ? 1 :
- 0);
+ if (!table->status && (!cond || cond->val_int()))
+ {
+ ((Item_in_subselect *) item)->value= 1;
+ empty_result_set= FALSE;
+ }
+ else
+ ((Item_in_subselect *) item)->value= 0;
}
DBUG_RETURN(error != 0);
@@ -2043,7 +2125,7 @@ subselect_uniquesubquery_engine::~subselect_uniquesubquery_engine()
1
*/
-int subselect_indexsubquery_engine::exec(bool full_scan)
+int subselect_indexsubquery_engine::exec()
{
DBUG_ENTER("subselect_indexsubquery_engine::exec");
int error;
@@ -2084,8 +2166,9 @@ int subselect_indexsubquery_engine::exec(bool full_scan)
table->null_row= 0;
if (!table->status)
{
- if (!cond || cond->val_int())
+ if ((!cond || cond->val_int()) && (!having || having->val_int()))
{
+ empty_result_set= FALSE;
if (null_finding)
((Item_in_subselect *) item)->was_null= 1;
else
@@ -2228,11 +2311,16 @@ void subselect_indexsubquery_engine::print(String *str)
str->append(key_info->name);
if (check_null)
str->append(STRING_WITH_LEN(" checking NULL"));
- if (cond)
+ if (cond)
{
str->append(STRING_WITH_LEN(" where "));
cond->print(str);
}
+ if (having)
+ {
+ str->append(STRING_WITH_LEN(" having "));
+ having->print(str);
+ }
str->append(')');
}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 5a0b2788678..37264f2136f 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -94,7 +94,7 @@ public:
return null_value;
}
bool fix_fields(THD *thd, Item **ref);
- virtual bool exec(bool full_scan);
+ virtual bool exec();
virtual void fix_length_and_dec();
table_map used_tables() const;
table_map not_null_tables() const { return 0; }
@@ -104,6 +104,7 @@ public:
Item *get_tmp_table_item(THD *thd);
void update_used_tables();
void print(String *str);
+ virtual bool have_guarded_conds() { return FALSE; }
bool change_engine(subselect_engine *eng)
{
old_engine= engine;
@@ -126,6 +127,12 @@ public:
enum_parsing_place place() { return parsing_place; }
bool walk(Item_processor processor, bool walk_subquery, byte *arg);
+ /**
+ Get the SELECT_LEX structure associated with this Item.
+ @return the SELECT_LEX structure associated with this Item
+ */
+ st_select_lex* get_select_lex();
+
friend class select_subselect;
friend class Item_in_optimizer;
friend bool Item_field::fix_fields(THD *, Item **);
@@ -163,12 +170,26 @@ public:
void fix_length_and_dec();
uint cols();
- Item* el(uint i) { return my_reinterpret_cast(Item*)(row[i]); }
+ Item* element_index(uint i) { return my_reinterpret_cast(Item*)(row[i]); }
Item** addr(uint i) { return (Item**)row + i; }
bool check_cols(uint c);
bool null_inside();
void bring_value();
+ /**
+ This method is used to implement a special case of semantic tree
+ rewriting, mandated by a SQL:2003 exception in the specification.
+ The only caller of this method is handle_sql2003_note184_exception(),
+ see the code there for more details.
+ Note that this method breaks the object internal integrity, by
+ removing it's association with the corresponding SELECT_LEX,
+ making this object orphan from the parse tree.
+ No other method, beside the destructor, should be called on this
+ object, as it is now invalid.
+ @return the SELECT_LEX structure that was given in the constructor.
+ */
+ st_select_lex* invalidate_and_restore_select_lex();
+
friend class select_singlerow_subselect;
};
@@ -250,13 +271,21 @@ protected:
bool transformed;
public:
/* Used to trigger on/off conditions that were pushed down to subselect */
- bool enable_pushed_conds;
+ bool *pushed_cond_guards;
+
+ bool *get_cond_guard(int i)
+ {
+ return pushed_cond_guards ? pushed_cond_guards + i : NULL;
+ }
+ void set_cond_guard_var(int i, bool v) { pushed_cond_guards[i]= v; }
+ bool have_guarded_conds() { return test(pushed_cond_guards); }
+
Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery
Item_in_subselect(Item * left_expr, st_select_lex *select_lex);
Item_in_subselect()
:Item_exists_subselect(), optimizer(0), abort_on_null(0), transformed(0),
- enable_pushed_conds(TRUE), upper_item(0)
+ pushed_cond_guards(NULL), upper_item(0)
{}
subs_type substype() { return IN_SUBS; }
@@ -341,23 +370,22 @@ public:
SYNOPSIS
exec()
- full_scan TRUE - Pushed-down predicates are disabled, the engine
- must disable made based on those predicates.
- FALSE - Pushed-down predicates are in effect.
+
DESCRIPTION
Execute the engine. The result of execution is subquery value that is
either captured by previously set up select_result-based 'sink' or
stored somewhere by the exec() method itself.
- A required side effect: if full_scan==TRUE, subselect_engine->no_rows()
- should return correct result.
+ A required side effect: If at least one pushed-down predicate is
+ disabled, subselect_engine->no_rows() must return correct result after
+ the exec() call.
RETURN
0 - OK
- 1 - Either an execution error, or the engine was be "changed", and
+ 1 - Either an execution error, or the engine was "changed", and the
caller should call exec() again for the new engine.
*/
- virtual int exec(bool full_scan)= 0;
+ virtual int exec()= 0;
virtual uint cols()= 0; /* return number of columns in select */
virtual uint8 uncacheable()= 0; /* query is uncacheable */
enum Item_result type() { return res_type; }
@@ -392,7 +420,7 @@ public:
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
- int exec(bool full_scan);
+ int exec();
uint cols();
uint8 uncacheable();
void exclude();
@@ -416,7 +444,7 @@ public:
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
- int exec(bool full_scan);
+ int exec();
uint cols();
uint8 uncacheable();
void exclude();
@@ -430,11 +458,30 @@ public:
struct st_join_table;
+
+
+/*
+ A subquery execution engine that evaluates the subquery by doing one index
+ lookup in a unique index.
+
+ This engine is used to resolve subqueries in forms
+
+ outer_expr IN (SELECT tbl.unique_key FROM tbl WHERE subq_where)
+
+ or, tuple-based:
+
+ (oe1, .. oeN) IN (SELECT uniq_key_part1, ... uniq_key_partK
+ FROM tbl WHERE subqwhere)
+
+ i.e. the subquery is a single table SELECT without GROUP BY, aggregate
+ functions, etc.
+*/
+
class subselect_uniquesubquery_engine: public subselect_engine
{
protected:
st_join_table *tab;
- Item *cond;
+ Item *cond; /* The WHERE condition of subselect */
/*
TRUE<=> last execution produced empty set. Valid only when left
expression is NULL.
@@ -454,7 +501,7 @@ public:
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
- int exec(bool full_scan);
+ int exec();
uint cols() { return 1; }
uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
void exclude();
@@ -472,16 +519,47 @@ class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine
{
/* FALSE for 'ref', TRUE for 'ref-or-null'. */
bool check_null;
+ /*
+ The "having" clause. This clause (further reffered to as "artificial
+ having") was inserted by subquery transformation code. It contains
+ Item(s) that have a side-effect: they record whether the subquery has
+ produced a row with NULL certain components. We need to use it for cases
+ like
+ (oe1, oe2) IN (SELECT t.key, t.no_key FROM t1)
+ where we do index lookup on t.key=oe1 but need also to check if there
+ was a row such that t.no_key IS NULL.
+
+ NOTE: This is currently here and not in the uniquesubquery_engine. Ideally
+ it should have been in uniquesubquery_engine in order to allow execution of
+ subqueries like
+
+ (oe1, oe2) IN (SELECT primary_key, non_key_maybe_null_field FROM tbl)
+
+ We could use uniquesubquery_engine for the first component and let
+ Item_is_not_null_test( non_key_maybe_null_field) to handle the second.
+
+ However, subqueries like the above are currently not handled by index
+ lookup-based subquery engines, the engine applicability check misses
+ them: it doesn't switch the engine for case of artificial having and
+ [eq_]ref access (only for artifical having + ref_or_null or no having).
+ The above example subquery is handled as a full-blown SELECT with eq_ref
+ access to one table.
+
+ Due to this limitation, the "artificial having" currently needs to be
+ checked by only in indexsubquery_engine.
+ */
+ Item *having;
public:
// constructor can assign THD because it will be called after JOIN::prepare
- subselect_indexsubquery_engine(THD *thd, st_join_table *tab_arg,
+ subselect_indexsubquery_engine(THD *thd_arg, st_join_table *tab_arg,
Item_subselect *subs, Item *where,
- bool chk_null)
- :subselect_uniquesubquery_engine(thd, tab_arg, subs, where),
- check_null(chk_null)
+ Item *having_arg, bool chk_null)
+ :subselect_uniquesubquery_engine(thd_arg, tab_arg, subs, where),
+ check_null(chk_null),
+ having(having_arg)
{}
- int exec(bool full_scan);
+ int exec();
void print (String *str);
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 99053587de5..f34fc008186 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -400,7 +400,7 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table,
Field *field;
switch (result_type()) {
case REAL_RESULT:
- field= new Field_double(max_length, maybe_null, name, decimals);
+ field= new Field_double(max_length, maybe_null, name, decimals, TRUE);
break;
case INT_RESULT:
field= new Field_longlong(max_length, maybe_null, name, unsigned_flag);
@@ -1135,7 +1135,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
field= new Field_new_decimal(max_length, maybe_null, name,
decimals, unsigned_flag);
else
- field= new Field_double(max_length, maybe_null, name, decimals);
+ field= new Field_double(max_length, maybe_null, name, decimals, TRUE);
if (field)
field->init(table);
return field;
@@ -1172,7 +1172,7 @@ double Item_sum_avg::val_real()
my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
{
- my_decimal sum, cnt;
+ my_decimal sum_buff, cnt;
const my_decimal *sum_dec;
DBUG_ASSERT(fixed == 1);
if (!count)
@@ -1180,7 +1180,7 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
null_value=1;
return NULL;
}
- sum_dec= Item_sum_sum::val_decimal(&sum);
+ sum_dec= Item_sum_sum::val_decimal(&sum_buff);
int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt);
my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, prec_increment);
return val;
@@ -1334,7 +1334,7 @@ Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
field= new Field_string(sizeof(double)*2 + sizeof(longlong), 0, name, &my_charset_bin);
}
else
- field= new Field_double(max_length, maybe_null, name, decimals);
+ field= new Field_double(max_length, maybe_null, name, decimals, TRUE);
if (field != NULL)
field->init(table);
@@ -1627,7 +1627,7 @@ bool Item_sum_min::add()
break;
case DECIMAL_RESULT:
{
- my_decimal value, *val= args[0]->val_decimal(&value);
+ my_decimal value_buff, *val= args[0]->val_decimal(&value_buff);
if (!args[0]->null_value &&
(null_value || (my_decimal_cmp(&sum_dec, val) > 0)))
{
@@ -1691,7 +1691,7 @@ bool Item_sum_max::add()
break;
case DECIMAL_RESULT:
{
- my_decimal value, *val= args[0]->val_decimal(&value);
+ my_decimal value_buff, *val= args[0]->val_decimal(&value_buff);
if (!args[0]->null_value &&
(null_value || (my_decimal_cmp(val, &sum_dec) > 0)))
{
@@ -1856,7 +1856,7 @@ void Item_sum_hybrid::reset_field()
}
case DECIMAL_RESULT:
{
- my_decimal value, *arg_dec= args[0]->val_decimal(&value);
+ my_decimal value_buff, *arg_dec= args[0]->val_decimal(&value_buff);
if (maybe_null)
{
@@ -2484,11 +2484,11 @@ bool Item_sum_count_distinct::setup(THD *thd)
for (tree_key_length= 0; field < field_end; ++field)
{
Field *f= *field;
- enum enum_field_types type= f->type();
+ enum enum_field_types f_type= f->type();
tree_key_length+= f->pack_length();
- if ((type == MYSQL_TYPE_VARCHAR) ||
- !f->binary() && (type == MYSQL_TYPE_STRING ||
- type == MYSQL_TYPE_VAR_STRING))
+ if ((f_type == MYSQL_TYPE_VARCHAR) ||
+ !f->binary() && (f_type == MYSQL_TYPE_STRING ||
+ f_type == MYSQL_TYPE_VAR_STRING))
{
all_binary= FALSE;
break;
@@ -3073,8 +3073,6 @@ Item_func_group_concat::Item_func_group_concat(THD *thd,
void Item_func_group_concat::cleanup()
{
- THD *thd= current_thd;
-
DBUG_ENTER("Item_func_group_concat::cleanup");
Item_sum::cleanup();
@@ -3083,7 +3081,7 @@ void Item_func_group_concat::cleanup()
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
- warning->set_msg(thd, warn_buff);
+ warning->set_msg(current_thd, warn_buff);
warning= 0;
}
@@ -3113,8 +3111,7 @@ void Item_func_group_concat::cleanup()
warning= 0;
}
}
- DBUG_ASSERT(tree == 0);
- DBUG_ASSERT(warning == 0);
+ DBUG_ASSERT(tree == 0 && warning == 0);
}
DBUG_VOID_RETURN;
}
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index faeef7fd5db..1bf1fec5cfb 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1007,7 +1007,8 @@ longlong Item_func_quarter::val_int()
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
- (void) get_arg0_date(&ltime, TIME_FUZZY_DATE);
+ if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
+ return 0;
return (longlong) ((ltime.month+2)/3);
}
@@ -1119,14 +1120,14 @@ String* Item_func_dayname::val_str(String* str)
{
DBUG_ASSERT(fixed == 1);
uint weekday=(uint) val_int(); // Always Item_func_daynr()
- const char *name;
+ const char *day_name;
THD *thd= current_thd;
if (null_value)
return (String*) 0;
- name= thd->variables.lc_time_names->day_names->type_names[weekday];
- str->set(name, strlen(name), system_charset_info);
+ day_name= thd->variables.lc_time_names->day_names->type_names[weekday];
+ str->set(day_name, strlen(day_name), system_charset_info);
return str;
}
@@ -1586,7 +1587,7 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions)
void Item_func_sysdate_local::store_now_in_TIME(TIME *now_time)
{
THD *thd= current_thd;
- thd->variables.time_zone->gmt_sec_to_TIME(now_time, time(NULL));
+ thd->variables.time_zone->gmt_sec_to_TIME(now_time, (my_time_t) time(NULL));
thd->time_zone_used= 1;
}
@@ -1647,6 +1648,7 @@ String *Item_func_sec_to_time::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
+ longlong arg_val= args[0]->val_int();
if ((null_value=args[0]->null_value) || str->alloc(19))
{
@@ -1654,7 +1656,7 @@ String *Item_func_sec_to_time::val_str(String *str)
return (String*) 0;
}
- sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, &ltime);
+ sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
make_time((DATE_TIME_FORMAT *) 0, &ltime, str);
return str;
@@ -1665,11 +1667,12 @@ longlong Item_func_sec_to_time::val_int()
{
DBUG_ASSERT(fixed == 1);
TIME ltime;
+ longlong arg_val= args[0]->val_int();
if ((null_value=args[0]->null_value))
return 0;
- sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, &ltime);
+ sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
return (ltime.neg ? -1 : 1) *
((ltime.hour)*10000 + ltime.minute*100 + ltime.second);
@@ -2528,7 +2531,10 @@ longlong Item_date_typecast::val_int()
DBUG_ASSERT(fixed == 1);
TIME ltime;
if (args[0]->get_date(&ltime, TIME_FUZZY_DATE))
+ {
+ null_value= 1;
return 0;
+ }
return (longlong) (ltime.year * 10000L + ltime.month * 100 + ltime.day);
}
@@ -3168,10 +3174,10 @@ bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date)
{
DATE_TIME_FORMAT date_time_format;
char val_buff[64], format_buff[64];
- String val_str(val_buff, sizeof(val_buff), &my_charset_bin), *val;
+ String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val;
String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format;
- val= args[0]->val_str(&val_str);
+ val= args[0]->val_str(&val_string);
format= args[1]->val_str(&format_str);
if (args[0]->null_value || args[1]->null_value)
goto null_date;
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 3da68cf43c2..26474990644 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -577,7 +577,6 @@ String * Item_nodeset_func_union::val_nodeset(String *nodeset)
both_str.alloc(numnodes);
char *both= (char*) both_str.ptr();
bzero((void*)both, numnodes);
- uint pos= 0;
MY_XPATH_FLT *flt;
fltbeg= (MY_XPATH_FLT*) s0->ptr();
@@ -1045,12 +1044,12 @@ static struct my_xpath_keyword_names_st my_keyword_names[] =
{MY_XPATH_LEX_OR , "or" , 2, 0 },
{MY_XPATH_LEX_DIV , "div" , 3, 0 },
{MY_XPATH_LEX_MOD , "mod" , 3, 0 },
-
- {MY_XPATH_LEX_NODETYPE, "comment" , 7, 0 },
- {MY_XPATH_LEX_NODETYPE, "text" , 4, 0 },
- {MY_XPATH_LEX_NODETYPE, "processing-instruction" , 22,0 },
- {MY_XPATH_LEX_NODETYPE, "node" , 4, 0 },
-
+ {0,NULL,0,0}
+};
+
+
+static struct my_xpath_keyword_names_st my_axis_names[]=
+{
{MY_XPATH_LEX_AXIS,"ancestor" , 8,MY_XPATH_AXIS_ANCESTOR },
{MY_XPATH_LEX_AXIS,"ancestor-or-self" ,16,MY_XPATH_AXIS_ANCESTOR_OR_SELF },
{MY_XPATH_LEX_AXIS,"attribute" , 9,MY_XPATH_AXIS_ATTRIBUTE },
@@ -1064,7 +1063,16 @@ static struct my_xpath_keyword_names_st my_keyword_names[] =
{MY_XPATH_LEX_AXIS,"preceding" , 9,MY_XPATH_AXIS_PRECEDING },
{MY_XPATH_LEX_AXIS,"preceding-sibling" ,17,MY_XPATH_AXIS_PRECEDING_SIBLING },
{MY_XPATH_LEX_AXIS,"self" , 4,MY_XPATH_AXIS_SELF },
+ {0,NULL,0,0}
+};
+
+static struct my_xpath_keyword_names_st my_nodetype_names[]=
+{
+ {MY_XPATH_LEX_NODETYPE, "comment" , 7, 0 },
+ {MY_XPATH_LEX_NODETYPE, "text" , 4, 0 },
+ {MY_XPATH_LEX_NODETYPE, "processing-instruction" , 22,0 },
+ {MY_XPATH_LEX_NODETYPE, "node" , 4, 0 },
{0,NULL,0,0}
};
@@ -1079,11 +1087,14 @@ static struct my_xpath_keyword_names_st my_keyword_names[] =
- Token type, on lookup success.
- MY_XPATH_LEX_IDENT, on lookup failure.
*/
-static int my_xpath_keyword(MY_XPATH *x, const char *beg, const char *end)
+static int
+my_xpath_keyword(MY_XPATH *x,
+ struct my_xpath_keyword_names_st *keyword_names,
+ const char *beg, const char *end)
{
struct my_xpath_keyword_names_st *k;
size_t length= end-beg;
- for (k= my_keyword_names; k->name; k++)
+ for (k= keyword_names; k->name; k++)
{
if (length == k->length && !strncasecmp(beg, k->name, length))
{
@@ -1369,15 +1380,32 @@ my_xpath_lex_scan(MY_XPATH *xpath,
beg+= length) /* no op */;
lex->end= beg;
- // check if a function call
- if (*beg == '(' && (xpath->func= my_xpath_function(lex->beg, beg)))
+ if (beg < end)
{
- lex->term= MY_XPATH_LEX_FUNC;
- return;
+ if (*beg == '(')
+ {
+ /*
+ check if a function call, e.g.: count(/a/b)
+ or a nodetype test, e.g.: /a/b/text()
+ */
+ if ((xpath->func= my_xpath_function(lex->beg, beg)))
+ lex->term= MY_XPATH_LEX_FUNC;
+ else
+ lex->term= my_xpath_keyword(xpath, my_nodetype_names,
+ lex->beg, beg);
+ return;
+ }
+ // check if an axis specifier, e.g.: /a/b/child::*
+ else if (*beg == ':' && beg + 1 < end && beg[1] == ':')
+ {
+ lex->term= my_xpath_keyword(xpath, my_axis_names,
+ lex->beg, beg);
+ return;
+ }
}
-
// check if a keyword
- lex->term= my_xpath_keyword(xpath, lex->beg, beg);
+ lex->term= my_xpath_keyword(xpath, my_keyword_names,
+ lex->beg, beg);
return;
}
@@ -1484,7 +1512,6 @@ static int my_xpath_parse_AxisName(MY_XPATH *xpath)
static int my_xpath_parse_LocationPath(MY_XPATH *xpath);
static int my_xpath_parse_AbsoluteLocationPath(MY_XPATH *xpath);
static int my_xpath_parse_RelativeLocationPath(MY_XPATH *xpath);
-static int my_xpath_parse_AbbreviatedAbsoluteLocationPath(MY_XPATH *xpath);
static int my_xpath_parse_AbbreviatedStep(MY_XPATH *xpath);
static int my_xpath_parse_Step(MY_XPATH *xpath);
static int my_xpath_parse_AxisSpecifier(MY_XPATH *xpath);
@@ -1503,7 +1530,6 @@ static int my_xpath_parse_RelationalExpr(MY_XPATH *xpath);
static int my_xpath_parse_AndExpr(MY_XPATH *xpath);
static int my_xpath_parse_EqualityExpr(MY_XPATH *xpath);
static int my_xpath_parse_VariableReference(MY_XPATH *xpath);
-static int my_xpath_parse_slash_opt_slash(MY_XPATH *xpath);
/*
@@ -2332,6 +2358,36 @@ static int my_xpath_parse_Number(MY_XPATH *xpath)
/*
+ Scan NCName.
+
+ SYNOPSYS
+
+ The keywords AND, OR, MOD, DIV are valid identitiers
+ when they are in identifier context:
+
+ SELECT
+ ExtractValue('<and><or><mod><div>VALUE</div></mod></or></and>',
+ '/and/or/mod/div')
+ -> VALUE
+
+ RETURN
+ 1 - success
+ 0 - failure
+*/
+
+static int
+my_xpath_parse_NCName(MY_XPATH *xpath)
+{
+ return
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT) ||
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_AND) ||
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_OR) ||
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_MOD) ||
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_DIV) ? 1 : 0;
+}
+
+
+/*
QName grammar can be found in a separate document
http://www.w3.org/TR/REC-xml-names/#NT-QName
@@ -2339,16 +2395,17 @@ static int my_xpath_parse_Number(MY_XPATH *xpath)
[7] Prefix ::= NCName
[8] LocalPart ::= NCName
*/
+
static int
my_xpath_parse_QName(MY_XPATH *xpath)
{
const char *beg;
- if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))
+ if (!my_xpath_parse_NCName(xpath))
return 0;
beg= xpath->prevtok.beg;
if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_COLON))
return 1; /* Non qualified name */
- if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))
+ if (!my_xpath_parse_NCName(xpath))
return 0;
xpath->prevtok.beg= beg;
return 1;
@@ -2699,7 +2756,6 @@ String *Item_func_xml_update::val_str(String *str)
}
MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml.ptr();
- MY_XML_NODE *nodeend= (MY_XML_NODE*) pxml.ptr() + pxml.length();
MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) nodeset->ptr();
MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (nodeset->ptr() + nodeset->length());
diff --git a/sql/lex.h b/sql/lex.h
index 2bf0e08c825..45155da7692 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -222,7 +222,7 @@ static SYMBOL symbols[] = {
{ "GLOBAL", SYM(GLOBAL_SYM)},
{ "GRANT", SYM(GRANT)},
{ "GRANTS", SYM(GRANTS)},
- { "GROUP", SYM(GROUP)},
+ { "GROUP", SYM(GROUP_SYM)},
{ "HANDLER", SYM(HANDLER_SYM)},
{ "HASH", SYM(HASH_SYM)},
{ "HAVING", SYM(HAVING)},
diff --git a/sql/lock.cc b/sql/lock.cc
index 533307c6b85..a93033bfdd0 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -485,7 +485,7 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
for (uint i=0; i < locked->lock_count; i++)
{
if (thr_abort_locks_for_thread(locked->locks[i]->lock,
- table->in_use->real_id))
+ table->in_use->thread_id))
result= TRUE;
}
my_free((gptr) locked,MYF(0));
@@ -604,7 +604,7 @@ TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
for (; haystack; haystack= haystack->next_global)
{
- if (haystack->placeholder() || haystack->schema_table)
+ if (haystack->placeholder())
continue;
table2= haystack->table;
if (table2->s->tmp_table == TMP_TABLE)
diff --git a/sql/log.cc b/sql/log.cc
index 1b432ca15c0..3b7d0c84106 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -31,15 +31,6 @@
#include <mysql/plugin.h>
-/*
- Define placement versions of operator new and operator delete since
- we cannot be sure that the <new> include exists.
- */
-inline void *operator new(size_t, void *ptr) { return ptr; }
-inline void *operator new[](size_t, void *ptr) { return ptr; }
-inline void operator delete(void*, void*) { /* Do nothing */ }
-inline void operator delete[](void*, void*) { /* Do nothing */ }
-
/* max size of the log message */
#define MAX_LOG_BUFFER_SIZE 1024
#define MAX_USER_HOST_SIZE 512
@@ -147,8 +138,8 @@ public:
*/
void truncate(my_off_t pos)
{
- DBUG_PRINT("info", ("truncating to position %lu", pos));
- DBUG_PRINT("info", ("before_stmt_pos=%lu", pos));
+ DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos));
+ DBUG_PRINT("info", ("before_stmt_pos=%lu", (ulong) pos));
delete pending();
set_pending(0);
reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0);
@@ -268,7 +259,7 @@ bool Log_to_csv_event_handler::open_log_table(uint log_table_type)
table->table_name_length= 8;
break;
default:
- DBUG_ASSERT(0);
+ assert(0); // Impossible
}
/*
@@ -312,6 +303,7 @@ bool Log_to_csv_event_handler::open_log_table(uint log_table_type)
{
table->table->use_all_columns();
table->table->locked_by_logger= TRUE;
+ table->table->no_replicate= TRUE;
}
/* restore thread settings */
if (curr)
@@ -909,7 +901,7 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length,
my_time_t current_time;
Security_context *sctx= thd->security_ctx;
- uint message_buff_len= 0, user_host_len= 0;
+ uint user_host_len= 0;
longlong query_time= 0, lock_time= 0;
/*
@@ -1162,7 +1154,7 @@ void LOGGER::deactivate_log_handler(THD *thd, uint log_type)
log_thd= table_log_handler->general_log_thd;
break;
default:
- DBUG_ASSERT(0);
+ assert(0); // Impossible
}
if (!(*tmp_opt))
@@ -1311,7 +1303,7 @@ void Log_to_csv_event_handler::
table= &slow_log;
break;
default:
- DBUG_ASSERT(0);
+ assert(0); // Impossible
}
/*
@@ -1544,23 +1536,21 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all)
do nothing.
just pretend we can do 2pc, so that MySQL won't
switch to 1pc.
- real work will be done in MYSQL_BIN_LOG::log()
+ real work will be done in MYSQL_BIN_LOG::log_xid()
*/
return 0;
}
static int binlog_commit(handlerton *hton, THD *thd, bool all)
{
- int error= 0;
DBUG_ENTER("binlog_commit");
binlog_trx_data *const trx_data=
(binlog_trx_data*) thd->ha_data[binlog_hton->slot];
- IO_CACHE *trans_log= &trx_data->trans_log;
DBUG_ASSERT(mysql_bin_log.is_open());
if (all && trx_data->empty())
{
- // we're here because trans_log was flushed in MYSQL_BIN_LOG::log()
+ // we're here because trans_log was flushed in MYSQL_BIN_LOG::log_xid()
trx_data->reset();
DBUG_RETURN(0);
}
@@ -1584,7 +1574,6 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
int error=0;
binlog_trx_data *const trx_data=
(binlog_trx_data*) thd->ha_data[binlog_hton->slot];
- IO_CACHE *trans_log= &trx_data->trans_log;
DBUG_ASSERT(mysql_bin_log.is_open());
if (trx_data->empty()) {
@@ -1647,9 +1636,6 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
{
DBUG_ENTER("binlog_savepoint_rollback");
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd->ha_data[binlog_hton->slot];
- IO_CACHE *trans_log= &trx_data->trans_log;
DBUG_ASSERT(mysql_bin_log.is_open());
/*
@@ -1660,7 +1646,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
if (unlikely(thd->options &
(OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG)))
{
- int const error=
+ int error=
thd->binlog_query(THD::STMT_QUERY_TYPE,
thd->query, thd->query_length, TRUE, FALSE);
DBUG_RETURN(error);
@@ -1669,6 +1655,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
DBUG_RETURN(0);
}
+
int check_binlog_magic(IO_CACHE* log, const char** errmsg)
{
char magic[4];
@@ -1689,6 +1676,7 @@ int check_binlog_magic(IO_CACHE* log, const char** errmsg)
return 0;
}
+
File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
{
File file;
@@ -1747,7 +1735,7 @@ void setup_windows_event_source()
/* Register EventMessageFile */
dwError = RegSetValueEx(hRegKey, "EventMessageFile", 0, REG_EXPAND_SZ,
- (PBYTE) szPath, strlen(szPath)+1);
+ (PBYTE) szPath, (DWORD) (strlen(szPath) + 1));
/* Register supported event types */
dwTypes= (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
@@ -2195,7 +2183,6 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
{
- Security_context *sctx= thd->security_ctx;
if (current_time != last_time)
{
last_time= current_time;
@@ -2434,7 +2421,6 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
bool null_created_arg)
{
File file= -1;
- int open_flags = O_CREAT | O_BINARY;
DBUG_ENTER("MYSQL_BIN_LOG::open");
DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
@@ -2596,6 +2582,8 @@ int MYSQL_BIN_LOG::raw_get_current_log(LOG_INFO* linfo)
0 ok
*/
+#ifdef HAVE_REPLICATION
+
static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset)
{
int bytes_read;
@@ -2629,6 +2617,7 @@ err:
DBUG_RETURN(1);
}
+#endif /* HAVE_REPLICATION */
/*
Find the position in the log-index-file for the given log name
@@ -3121,8 +3110,6 @@ err:
pthread_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
-
-
#endif /* HAVE_REPLICATION */
@@ -3244,7 +3231,6 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
We log the whole file name for log file as the user may decide
to change base names at some point.
*/
- THD *thd = current_thd; /* may be 0 if we are reacting to SIGHUP */
Rotate_log_event r(new_name+dirname_length(new_name),
0, LOG_EVENT_OFFSET, 0);
r.write(&log_file);
@@ -3359,13 +3345,13 @@ bool MYSQL_BIN_LOG::flush_and_sync()
return err;
}
-void MYSQL_BIN_LOG::start_union_events(THD *thd)
+void MYSQL_BIN_LOG::start_union_events(THD *thd, query_id_t query_id_param)
{
DBUG_ASSERT(!thd->binlog_evt_union.do_union);
thd->binlog_evt_union.do_union= TRUE;
thd->binlog_evt_union.unioned_events= FALSE;
thd->binlog_evt_union.unioned_events_trans= FALSE;
- thd->binlog_evt_union.first_query_id= thd->query_id;
+ thd->binlog_evt_union.first_query_id= query_id_param;
}
void MYSQL_BIN_LOG::stop_union_events(THD *thd)
@@ -3480,10 +3466,10 @@ int THD::binlog_flush_transaction_cache()
{
DBUG_ENTER("binlog_flush_transaction_cache");
binlog_trx_data *trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot];
- DBUG_PRINT("enter", ("trx_data=0x%lu", trx_data));
+ DBUG_PRINT("enter", ("trx_data=0x%lu", (ulong) trx_data));
if (trx_data)
- DBUG_PRINT("enter", ("trx_data->before_stmt_pos=%u",
- trx_data->before_stmt_pos));
+ DBUG_PRINT("enter", ("trx_data->before_stmt_pos=%lu",
+ (ulong) trx_data->before_stmt_pos));
/*
Write the transaction cache to the binary log. We don't flush and
@@ -3698,14 +3684,14 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
*/
if (likely(is_open()))
{
- const char *local_db= event_info->get_db();
IO_CACHE *file= &log_file;
#ifdef HAVE_REPLICATION
/*
- In the future we need to add to the following if tests like
- "do the involved tables match (to be implemented)
- binlog_[wild_]{do|ignore}_table?" (WL#1049)"
+ In the future we need to add to the following if tests like
+ "do the involved tables match (to be implemented)
+ binlog_[wild_]{do|ignore}_table?" (WL#1049)"
*/
+ const char *local_db= event_info->get_db();
if ((thd && !(thd->options & OPTION_BIN_LOG)) ||
(!binlog_filter->db_ok(local_db)))
{
@@ -3894,7 +3880,7 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
#ifdef HAVE_REPLICATION
if (expire_logs_days)
{
- long purge_time= time(0) - expire_logs_days*24*60*60;
+ long purge_time= (long) (time(0) - expire_logs_days*24*60*60);
if (purge_time >= 0)
purge_logs_before_date(purge_time);
}
@@ -3981,8 +3967,6 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
if (likely(is_open())) // Should always be true
{
- uint length;
-
/*
We only bother to write to the binary log if there is anything
to write.
@@ -4022,9 +4006,6 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
if (commit_event && commit_event->write(&log_file))
goto err;
-#ifndef DBUG_OFF
- DBUG_skip_commit:
-#endif
if (flush_and_sync())
goto err;
DBUG_EXECUTE_IF("half_binlogged_transaction", abort(););
@@ -4537,7 +4518,7 @@ int TC_LOG_MMAP::open(const char *opt_name)
goto err;
if (using_heuristic_recover())
return 1;
- if ((fd= my_create(logname, O_RDWR, 0, MYF(MY_WME))) < 0)
+ if ((fd= my_create(logname, CREATE_MODE, O_RDWR, MYF(MY_WME))) < 0)
goto err;
inited=1;
file_length= opt_tc_log_size;
@@ -4684,21 +4665,34 @@ int TC_LOG_MMAP::overflow()
}
/*
- all access to active page is serialized but it's not a problem, as
- we're assuming that fsync() will be a main bottleneck.
- That is, parallelizing writes to log pages we'll decrease number of
- threads waiting for a page, but then all these threads will be waiting
- for a fsync() anyway
+ Record that transaction XID is committed on the persistent storage
+
+ NOTES
+ This function is called in the middle of two-phase commit:
+ First all resources prepare the transaction, then tc_log->log() is called,
+ then all resources commit the transaction, then tc_log->unlog() is called.
+
+ All access to active page is serialized but it's not a problem, as
+ we're assuming that fsync() will be a main bottleneck.
+ That is, parallelizing writes to log pages we'll decrease number of
+ threads waiting for a page, but then all these threads will be waiting
+ for a fsync() anyway
+
+ IMPLEMENTATION
+ If tc_log == MYSQL_LOG then tc_log writes transaction to binlog and
+ records XID in a special Xid_log_event.
+ If tc_log = TC_LOG_MMAP then xid is written in a special memory-mapped
+ log.
RETURN
- 0 - error
- otherwise - "cookie", a number that will be passed as an argument
- to unlog() call. tc_log can define it any way it wants,
- and use for whatever purposes. TC_LOG_MMAP sets it
- to the position in memory where xid was logged to.
+ 0 Error
+ # "cookie", a number that will be passed as an argument
+ to unlog() call. tc_log can define it any way it wants,
+ and use for whatever purposes. TC_LOG_MMAP sets it
+ to the position in memory where xid was logged to.
*/
-int TC_LOG_MMAP::log(THD *thd, my_xid xid)
+int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid)
{
int err;
PAGE *p;
@@ -4807,6 +4801,7 @@ int TC_LOG_MMAP::sync()
erase xid from the page, update page free space counters/pointers.
cookie points directly to the memory where xid was logged
*/
+
void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
{
PAGE *p=pages+(cookie/tc_log_page_size);
@@ -5049,7 +5044,7 @@ void TC_LOG_BINLOG::close()
0 - error
1 - success
*/
-int TC_LOG_BINLOG::log(THD *thd, my_xid xid)
+int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid)
{
DBUG_ENTER("TC_LOG_BINLOG::log");
Xid_log_event xle(thd, xid);
diff --git a/sql/log.h b/sql/log.h
index 61db7052f75..970823dcd4a 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -33,7 +33,7 @@ class TC_LOG
virtual int open(const char *opt_name)=0;
virtual void close()=0;
- virtual int log(THD *thd, my_xid xid)=0;
+ virtual int log_xid(THD *thd, my_xid xid)=0;
virtual void unlog(ulong cookie, my_xid xid)=0;
};
@@ -43,7 +43,7 @@ public:
TC_LOG_DUMMY() {}
int open(const char *opt_name) { return 0; }
void close() { }
- int log(THD *thd, my_xid xid) { return 1; }
+ int log_xid(THD *thd, my_xid xid) { return 1; }
void unlog(ulong cookie, my_xid xid) { }
};
@@ -88,7 +88,7 @@ class TC_LOG_MMAP: public TC_LOG
TC_LOG_MMAP(): inited(0) {}
int open(const char *opt_name);
void close();
- int log(THD *thd, my_xid xid);
+ int log_xid(THD *thd, my_xid xid);
void unlog(ulong cookie, my_xid xid);
int recover();
@@ -287,7 +287,7 @@ public:
int open(const char *opt_name);
void close();
- int log(THD *thd, my_xid xid);
+ int log_xid(THD *thd, my_xid xid);
void unlog(ulong cookie, my_xid xid);
int recover(IO_CACHE *log, Format_description_log_event *fdle);
#if !defined(MYSQL_CLIENT)
@@ -341,7 +341,7 @@ public:
int write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync);
- void start_union_events(THD *thd);
+ void start_union_events(THD *thd, query_id_t query_id_param);
void stop_union_events(THD *thd);
bool is_query_in_union(THD *thd, query_id_t query_id_param);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 82fb64bfe15..f8d3c43bfba 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -139,22 +139,6 @@ static void pretty_print_str(IO_CACHE* cache, char* str, int len)
}
#endif /* MYSQL_CLIENT */
-#ifdef HAVE_purify
-static void
-valgrind_check_mem(void *ptr, size_t len)
-{
- static volatile uchar dummy;
- for (volatile uchar *p= (uchar*) ptr ; p != (uchar*) ptr + len ; ++p)
- {
- int const c = *p;
- if (c < 128)
- dummy= c + 1;
- else
- dummy = c - 1;
- }
-}
-#endif
-
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
static void clear_all_errors(THD *thd, struct st_relay_log_info *rli)
@@ -381,12 +365,14 @@ append_query_string(CHARSET_INFO *csinfo,
}
#endif
+
/*
Prints a "session_var=value" string. Used by mysqlbinlog to print some SET
commands just before it prints a query.
*/
#ifdef MYSQL_CLIENT
+
static void print_set_option(IO_CACHE* file, uint32 bits_changed,
uint32 option, uint32 flags, const char* name,
bool* need_comma)
@@ -1144,13 +1130,18 @@ void Log_event::print_header(IO_CACHE* file,
char emit_buf[256];
int const bytes_written=
my_snprintf(emit_buf, sizeof(emit_buf),
- "# %8.8lx %-48.48s |%s|\n# ",
+ "# %8.8lx %-48.48s |%s|\n",
(unsigned long) (hexdump_from + (i & 0xfffffff0)),
hex_string, char_string);
DBUG_ASSERT(bytes_written >= 0);
DBUG_ASSERT(static_cast<my_size_t>(bytes_written) < sizeof(emit_buf));
my_b_write(file, (byte*) emit_buf, bytes_written);
}
+ /*
+ need a # to prefix the rest of printouts for example those of
+ Rows_log_event::print_helper().
+ */
+ my_b_write(file, reinterpret_cast<const byte*>("# "), 2);
}
DBUG_VOID_RETURN;
}
@@ -1162,7 +1153,6 @@ void Log_event::print_base64(IO_CACHE* file,
{
const uchar *ptr= (const uchar *)temp_buf;
uint32 size= uint4korr(ptr + EVENT_LEN_OFFSET);
-
DBUG_ENTER("Log_event::print_base64");
size_t const tmp_str_sz= base64_needed_encoded_length((int) size);
@@ -1173,8 +1163,10 @@ void Log_event::print_base64(IO_CACHE* file,
DBUG_VOID_RETURN;
}
- int const res= base64_encode(ptr, (size_t) size, tmp_str);
- DBUG_ASSERT(res == 0);
+ if (base64_encode(ptr, (size_t) size, tmp_str))
+ {
+ DBUG_ASSERT(0);
+ }
if (my_b_tell(file) == 0)
my_b_printf(file, "\nBINLOG '\n");
@@ -1289,7 +1281,8 @@ bool Query_log_event::write(IO_CACHE* file)
1+4+ // code of autoinc and the 2 autoinc variables
1+6+ // code of charset and charset
1+1+MAX_TIME_ZONE_NAME_LENGTH+ // code of tz and tz length and tz name
- 1+2 // code of lc_time_names and lc_time_names_number
+ 1+2+ // code of lc_time_names and lc_time_names_number
+ 1+2 // code of charset_database and charset_database_number
], *start, *start_of_status;
ulong event_length;
@@ -1408,6 +1401,13 @@ bool Query_log_event::write(IO_CACHE* file)
int2store(start, lc_time_names_number);
start+= 2;
}
+ if (charset_database_number)
+ {
+ DBUG_ASSERT(charset_database_number <= 0xFFFF);
+ *start++= Q_CHARSET_DATABASE_CODE;
+ int2store(start, charset_database_number);
+ start+= 2;
+ }
/*
Here there could be code like
if (command-line-option-which-says-"log_this_variable" && inited)
@@ -1473,7 +1473,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
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),
- lc_time_names_number(thd_arg->variables.lc_time_names->number)
+ lc_time_names_number(thd_arg->variables.lc_time_names->number),
+ charset_database_number(0)
{
time_t end_time;
time(&end_time);
@@ -1481,6 +1482,9 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
catalog_len = (catalog) ? (uint32) strlen(catalog) : 0;
/* status_vars_len is set just before writing the event */
db_len = (db) ? (uint32) strlen(db) : 0;
+ if (thd_arg->variables.collation_database != thd_arg->db_charset)
+ charset_database_number= thd_arg->variables.collation_database->number;
+
/*
If we don't use flags2 for anything else than options contained in
thd->options, it would be more efficient to flags2=thd_arg->options
@@ -1551,7 +1555,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
db(NullS), catalog_len(0), status_vars_len(0),
flags2_inited(0), sql_mode_inited(0), charset_inited(0),
auto_increment_increment(1), auto_increment_offset(1),
- time_zone_len(0), lc_time_names_number(0)
+ time_zone_len(0), lc_time_names_number(0), charset_database_number(0)
{
ulong data_len;
uint32 tmp;
@@ -1656,6 +1660,10 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
lc_time_names_number= uint2korr(pos);
pos+= 2;
break;
+ case Q_CHARSET_DATABASE_CODE:
+ charset_database_number= uint2korr(pos);
+ pos+= 2;
+ 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\
@@ -1854,6 +1862,16 @@ void Query_log_event::print_query_header(IO_CACHE* file,
lc_time_names_number, print_event_info->delimiter);
print_event_info->lc_time_names_number= lc_time_names_number;
}
+ if (charset_database_number != print_event_info->charset_database_number)
+ {
+ if (charset_database_number)
+ my_b_printf(file, "SET @@session.collation_database=%d%s\n",
+ charset_database_number, print_event_info->delimiter);
+ else
+ my_b_printf(file, "SET @@session.collation_database=DEFAULT%s\n",
+ print_event_info->delimiter);
+ print_event_info->charset_database_number= charset_database_number;
+ }
}
@@ -2009,7 +2027,21 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli,
}
else
thd->variables.lc_time_names= &my_locale_en_US;
-
+ if (charset_database_number)
+ {
+ CHARSET_INFO *cs;
+ if (!(cs= get_charset(charset_database_number, MYF(0))))
+ {
+ char buf[20];
+ int10_to_str((int) charset_database_number, buf, -10);
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), buf);
+ goto compare_errors;
+ }
+ thd->variables.collation_database= cs;
+ }
+ else
+ thd->variables.collation_database= thd->db_charset;
+
/* Execute the query (note that we bypass dispatch_command()) */
mysql_parse(thd, thd->query, thd->query_length);
@@ -2254,6 +2286,8 @@ Start_log_event_v3::Start_log_event_v3(const char* buf,
binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET);
memcpy(server_version, buf+ST_SERVER_VER_OFFSET,
ST_SERVER_VER_LEN);
+ // prevent overrun if log is corrupted on disk
+ server_version[ST_SERVER_VER_LEN-1]= 0;
created= uint4korr(buf+ST_CREATED_OFFSET);
/* We use log_pos to mark if this was an artificial event or not */
artificial_event= (log_pos == 0);
@@ -2377,6 +2411,8 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
switch (binlog_ver) {
case 4: /* MySQL 5.0 */
memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
+ DBUG_EXECUTE_IF("pretend_version_50034_in_binlog",
+ strmov(server_version, "5.0.34"););
common_header_len= LOG_EVENT_HEADER_LEN;
number_of_event_types= LOG_EVENT_TYPES;
/* we'll catch my_malloc() error in is_valid() */
@@ -2467,6 +2503,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
post_header_len= 0; /* will make is_valid() fail */
break;
}
+ calc_server_version_split();
}
@@ -2506,6 +2543,7 @@ Format_description_log_event(const char* buf,
post_header_len= (uint8*) my_memdup((byte*)buf+ST_COMMON_HEADER_LEN_OFFSET+1,
number_of_event_types*
sizeof(*post_header_len), MYF(0));
+ calc_server_version_split();
DBUG_VOID_RETURN;
}
@@ -2606,6 +2644,37 @@ int Format_description_log_event::exec_event(struct st_relay_log_info* rli)
}
#endif
+
+/**
+ Splits the event's 'server_version' string into three numeric pieces stored
+ into 'server_version_split':
+ X.Y.Zabc (X,Y,Z numbers, a not a digit) -> {X,Y,Z}
+ X.Yabc -> {X,Y,0}
+ Xabc -> {X,0,0}
+ 'server_version_split' is then used for lookups to find if the server which
+ created this event has some known bug.
+*/
+void Format_description_log_event::calc_server_version_split()
+{
+ char *p= server_version, *r;
+ ulong number;
+ for (uint i= 0; i<=2; i++)
+ {
+ number= strtoul(p, &r, 10);
+ server_version_split[i]= (uchar)number;
+ DBUG_ASSERT(number < 256); // fit in uchar
+ p= r;
+ DBUG_ASSERT(!((i == 0) && (*r != '.'))); // should be true in practice
+ if (*r == '.')
+ p++; // skip the dot
+ }
+ DBUG_PRINT("info",("Format_description_log_event::server_version_split:"
+ " '%s' %d %d %d", server_version,
+ server_version_split[0],
+ server_version_split[1], server_version_split[2]));
+}
+
+
/**************************************************************************
Load_log_event methods
General note about Load_log_event: the binlogging of LOAD DATA INFILE is
@@ -3266,10 +3335,9 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
ex.skip_lines = skip_lines;
List<Item> field_list;
- thd->main_lex.select_lex.context.resolve_in_table_list_only(&tables);
- set_fields(tables.db, field_list, &thd->main_lex.select_lex.context);
+ thd->lex->select_lex.context.resolve_in_table_list_only(&tables);
+ set_fields(tables.db, field_list, &thd->lex->select_lex.context);
thd->variables.pseudo_thread_id= thread_id;
- List<Item> set_fields;
if (net)
{
// mysql_load will use thd->net to read the file
@@ -3280,10 +3348,11 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
thd->net.pkt_nr = net->pkt_nr;
}
/*
- It is safe to use set_fields twice because we are not going to
+ It is safe to use tmp_list twice because we are not going to
update it inside mysql_load().
*/
- if (mysql_load(thd, &ex, &tables, field_list, set_fields, set_fields,
+ List<Item> tmp_list;
+ if (mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list,
handle_dup, ignore, net != 0))
thd->query_error= 1;
if (thd->cuted_fields)
@@ -5478,15 +5547,14 @@ int Rows_log_event::do_add_row_data(byte *const row_data,
DBUG_ASSERT(m_rows_cur <= m_rows_end);
/* The cast will always work since m_rows_cur <= m_rows_end */
- if (static_cast<my_size_t>(m_rows_end - m_rows_cur) < length)
+ if (static_cast<my_size_t>(m_rows_end - m_rows_cur) <= length)
{
my_size_t const block_size= 1024;
- my_ptrdiff_t const old_alloc= m_rows_end - m_rows_buf;
my_ptrdiff_t const cur_size= m_rows_cur - m_rows_buf;
my_ptrdiff_t const new_alloc=
- block_size * ((cur_size + length) / block_size + block_size - 1);
+ block_size * ((cur_size + length + block_size - 1) / block_size);
- byte* const new_buf= (byte*)my_realloc((gptr)m_rows_buf, new_alloc,
+ byte* const new_buf= (byte*)my_realloc((gptr)m_rows_buf, (uint) new_alloc,
MYF(MY_ALLOW_ZERO_PTR|MY_WME));
if (unlikely(!new_buf))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
@@ -5505,7 +5573,7 @@ int Rows_log_event::do_add_row_data(byte *const row_data,
m_rows_end= m_rows_buf + new_alloc;
}
- DBUG_ASSERT(m_rows_cur + length < m_rows_end);
+ DBUG_ASSERT(m_rows_cur + length <= m_rows_end);
memcpy(m_rows_cur, row_data, length);
m_rows_cur+= length;
m_row_count++;
@@ -5717,9 +5785,26 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
{
if (!need_reopen)
{
- slave_print_msg(ERROR_LEVEL, rli, error,
- "Error in %s event: when locking tables",
- get_type_str());
+ if (thd->query_error || thd->is_fatal_error)
+ {
+ /*
+ Error reporting borrowed from Query_log_event with many excessive
+ simplifications (we don't honour --slave-skip-errors)
+ */
+ uint actual_error= thd->net.last_errno;
+ slave_print_msg(ERROR_LEVEL, rli, actual_error,
+ "Error '%s' in %s event: when locking tables",
+ (actual_error ? thd->net.last_error :
+ "unexpected success or fatal error"),
+ get_type_str());
+ thd->is_fatal_error= 1;
+ }
+ else
+ {
+ slave_print_msg(ERROR_LEVEL, rli, error,
+ "Error in %s event: when locking tables",
+ get_type_str());
+ }
rli->clear_tables_to_lock();
DBUG_RETURN(error);
}
@@ -5738,10 +5823,10 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
need to add code to assert that is the case.
*/
thd->binlog_flush_pending_rows_event(false);
- close_tables_for_reopen(thd, &rli->tables_to_lock);
+ TABLE_LIST *tables= rli->tables_to_lock;
+ close_tables_for_reopen(thd, &tables);
- if ((error= open_tables(thd, &rli->tables_to_lock,
- &rli->tables_to_lock_count, 0)))
+ if ((error= open_tables(thd, &tables, &rli->tables_to_lock_count, 0)))
{
if (thd->query_error || thd->is_fatal_error)
{
@@ -5760,15 +5845,45 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
DBUG_RETURN(error);
}
}
+
+ /*
+ When the open and locking succeeded, we check all tables to
+ ensure that they still have the correct type.
+
+ We can use a down cast here since we know that every table added
+ to the tables_to_lock is a RPL_TABLE_LIST.
+ */
+
+ {
+ RPL_TABLE_LIST *ptr= rli->tables_to_lock;
+ for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global))
+ {
+ if (ptr->m_tabledef.compatible_with(rli, ptr->table))
+ {
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock= 0;
+ thd->query_error= 1;
+ rli->clear_tables_to_lock();
+ DBUG_RETURN(ERR_BAD_TABLE_DEF);
+ }
+ }
+ }
+
/*
- When the open and locking succeeded, we add all the tables to
- the table map and remove them from tables to lock.
+ ... and then we add all the tables to the table map and remove
+ them from tables to lock.
We also invalidate the query cache for all the tables, since
they will now be changed.
+
+ TODO [/Matz]: Maybe the query cache should not be invalidated
+ here? It might be that a table is not changed, even though it
+ was locked for the statement. We do know that each
+ Rows_log_event contain at least one row, so after processing one
+ Rows_log_event, we can invalidate the query cache for the
+ associated table.
*/
- TABLE_LIST *ptr;
- for (ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
+ for (TABLE_LIST *ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
{
rli->m_table_map.set_table(ptr->table_id, ptr->table);
}
@@ -6012,7 +6127,7 @@ bool Rows_log_event::write_data_body(IO_CACHE*file)
sbuf_end - sbuf) ||
my_b_safe_write(file, reinterpret_cast<byte*>(m_cols.bitmap),
no_bytes_in_map(&m_cols)) ||
- my_b_safe_write(file, m_rows_buf, data_size));
+ my_b_safe_write(file, m_rows_buf, (uint) data_size));
}
#endif
@@ -6039,7 +6154,7 @@ void Rows_log_event::print_helper(FILE *file,
{
bool const last_stmt_event= get_flags(STMT_END_F);
print_header(head, print_event_info, !last_stmt_event);
- my_b_printf(head, "\t%s: table id %lu", name, m_table_id);
+ my_b_printf(head, "\t%s: table id %lu\n", name, m_table_id);
print_base64(body, print_event_info, !last_stmt_event);
}
@@ -6221,11 +6336,11 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
thd->query_id= next_query_id();
pthread_mutex_unlock(&LOCK_thread_count);
- TABLE_LIST *table_list;
+ RPL_TABLE_LIST *table_list;
char *db_mem, *tname_mem;
void *const memory=
my_multi_malloc(MYF(MY_WME),
- &table_list, sizeof(TABLE_LIST),
+ &table_list, sizeof(RPL_TABLE_LIST),
&db_mem, NAME_LEN + 1,
&tname_mem, NAME_LEN + 1,
NULL);
@@ -6271,11 +6386,27 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
}
/*
- Open the table if it is not already open and add the table to table map.
- Note that for any table that should not be replicated, a filter is needed.
+ Open the table if it is not already open and add the table to
+ table map. Note that for any table that should not be
+ replicated, a filter is needed.
+
+ The creation of a new TABLE_LIST is used to up-cast the
+ table_list consisting of RPL_TABLE_LIST items. This will work
+ since the only case where the argument to open_tables() is
+ changed, is when thd->lex->query_tables == table_list, i.e.,
+ when the statement requires prelocking. Since this is not
+ executed when a statement is executed, this case will not occur.
+ As a precaution, an assertion is added to ensure that the bad
+ case is not a fact.
+
+ Either way, the memory in the list is *never* released
+ internally in the open_tables() function, hence we take a copy
+ of the pointer to make sure that it's not lost.
*/
uint count;
- if ((error= open_tables(thd, &table_list, &count, 0)))
+ DBUG_ASSERT(thd->lex->query_tables != table_list);
+ TABLE_LIST *tmp_table_list= table_list;
+ if ((error= open_tables(thd, &tmp_table_list, &count, 0)))
{
if (thd->query_error || thd->is_fatal_error)
{
@@ -6302,14 +6433,17 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
*/
DBUG_ASSERT(m_table->in_use);
- table_def const def(m_coltype, m_colcnt);
- if (def.compatible_with(rli, m_table))
- {
- thd->query_error= 1;
- error= ERR_BAD_TABLE_DEF;
- goto err;
- /* purecov: end */
- }
+ /*
+ Use placement new to construct the table_def instance in the
+ memory allocated for it inside table_list.
+
+ The memory allocated by the table_def structure (i.e., not the
+ memory allocated *for* the table_def structure) is released
+ inside st_relay_log_info::clear_tables_to_lock() by calling the
+ table_def destructor explicitly.
+ */
+ new (&table_list->m_tabledef) table_def(m_coltype, m_colcnt);
+ table_list->m_tabledef_valid= TRUE;
/*
We record in the slave's information that the table should be
@@ -6365,8 +6499,8 @@ bool Table_map_log_event::write_data_body(IO_CACHE *file)
DBUG_ASSERT(m_dblen < 128);
DBUG_ASSERT(m_tbllen < 128);
- byte const dbuf[]= { m_dblen };
- byte const tbuf[]= { m_tbllen };
+ byte const dbuf[]= { (byte) m_dblen };
+ byte const tbuf[]= { (byte) m_tbllen };
char cbuf[sizeof(m_colcnt)];
char *const cbuf_end= net_store_length((char*) cbuf, (uint) m_colcnt);
diff --git a/sql/log_event.h b/sql/log_event.h
index 5994beb0df3..7cbe8925d9a 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -272,6 +272,7 @@ struct sql_ex_info
#define Q_LC_TIME_NAMES_CODE 7
+#define Q_CHARSET_DATABASE_CODE 8
/* Intvar event post-header */
#define I_TYPE_OFFSET 0
@@ -533,10 +534,11 @@ typedef struct st_print_event_info
char charset[6]; // 3 variables, each of them storable in 2 bytes
char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH];
uint lc_time_names_number;
+ uint charset_database_number;
st_print_event_info()
:flags2_inited(0), sql_mode_inited(0),
auto_increment_increment(1),auto_increment_offset(1), charset_inited(0),
- lc_time_names_number(0)
+ lc_time_names_number(0), charset_database_number(0)
{
/*
Currently we only use static PRINT_EVENT_INFO objects, so zeroed at
@@ -546,16 +548,19 @@ typedef struct st_print_event_info
bzero(db, sizeof(db));
bzero(charset, sizeof(charset));
bzero(time_zone_str, sizeof(time_zone_str));
- strcpy(delimiter, ";");
- uint const flags = MYF(MY_WME | MY_NABP);
- init_io_cache(&head_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags);
- init_io_cache(&body_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags);
+ delimiter[0]= ';';
+ delimiter[1]= 0;
+ myf const flags = MYF(MY_WME | MY_NABP);
+ open_cached_file(&head_cache, NULL, NULL, 0, flags);
+ open_cached_file(&body_cache, NULL, NULL, 0, flags);
}
~st_print_event_info() {
- end_io_cache(&head_cache);
- end_io_cache(&body_cache);
+ close_cached_file(&head_cache);
+ close_cached_file(&body_cache);
}
+ bool init_ok() /* tells if construction was successful */
+ { return my_b_inited(&head_cache) && my_b_inited(&body_cache); }
/* Settings on how to print the events */
@@ -846,6 +851,7 @@ public:
uint time_zone_len; /* 0 means uninited */
const char *time_zone_str;
uint lc_time_names_number; /* 0 means en_US */
+ uint charset_database_number;
#ifndef MYSQL_CLIENT
@@ -1153,6 +1159,7 @@ public:
uint8 number_of_event_types;
/* The list of post-headers' lengthes */
uint8 *post_header_len;
+ uchar server_version_split[3];
Format_description_log_event(uint8 binlog_ver, const char* server_ver=0);
@@ -1184,6 +1191,7 @@ public:
*/
return FORMAT_DESCRIPTION_HEADER_LEN;
}
+ void calc_server_version_split();
};
@@ -1727,14 +1735,17 @@ public:
TYPE_CODE = TABLE_MAP_EVENT
};
+ /**
+ Enumeration of the errors that can be returned.
+ */
enum enum_error
{
- ERR_OPEN_FAILURE = -1, /* Failure to open table */
- ERR_OK = 0, /* No error */
- ERR_TABLE_LIMIT_EXCEEDED = 1, /* No more room for tables */
- ERR_OUT_OF_MEM = 2, /* Out of memory */
- ERR_BAD_TABLE_DEF = 3, /* Table definition does not match */
- ERR_RBR_TO_SBR = 4 /* daisy-chanining RBR to SBR not allowed */
+ ERR_OPEN_FAILURE = -1, /**< Failure to open table */
+ ERR_OK = 0, /**< No error */
+ ERR_TABLE_LIMIT_EXCEEDED = 1, /**< No more room for tables */
+ ERR_OUT_OF_MEM = 2, /**< Out of memory */
+ ERR_BAD_TABLE_DEF = 3, /**< Table definition does not match */
+ ERR_RBR_TO_SBR = 4 /**< daisy-chanining RBR to SBR not allowed */
};
enum enum_flag
@@ -1814,7 +1825,7 @@ private:
Row level log event class.
- Common base class for all row-level log events.
+ Common base class for all row-containing log events.
RESPONSIBILITIES
@@ -1828,6 +1839,19 @@ private:
class Rows_log_event : public Log_event
{
public:
+ /**
+ Enumeration of the errors that can be returned.
+ */
+ enum enum_error
+ {
+ ERR_OPEN_FAILURE = -1, /**< Failure to open table */
+ ERR_OK = 0, /**< No error */
+ ERR_TABLE_LIMIT_EXCEEDED = 1, /**< No more room for tables */
+ ERR_OUT_OF_MEM = 2, /**< Out of memory */
+ ERR_BAD_TABLE_DEF = 3, /**< Table definition does not match */
+ ERR_RBR_TO_SBR = 4 /**< daisy-chanining RBR to SBR not allowed */
+ };
+
/*
These definitions allow you to combine the flags into an
appropriate flag set using the normal bitwise operators. The
@@ -1835,7 +1859,6 @@ public:
accepted by the compiler, which is then used to set the real set
of flags.
*/
-
enum enum_flag
{
/* Last event of a statement */
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index caeeb615e0a..c812aa800c9 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -38,6 +38,7 @@
#include <queues.h>
#include "sql_bitmap.h"
#include "sql_array.h"
+#include "scheduler.h"
/* TODO convert all these three maps to Bitmap classes */
typedef ulonglong table_map; /* Used for table bits in join */
@@ -57,10 +58,10 @@ typedef ulonglong nested_join_map;
/* query_id */
typedef ulonglong query_id_t;
-extern query_id_t query_id;
+extern query_id_t global_query_id;
/* increment query_id and return it. */
-inline query_id_t next_query_id() { return query_id++; }
+inline query_id_t next_query_id() { return global_query_id++; }
/* useful constants */
extern const key_map key_map_empty;
@@ -87,20 +88,26 @@ void sql_kill(THD *thd, ulong id, bool only_kill_query);
bool net_request_file(NET* net, const char* fname);
char* query_table_status(THD *thd,const char *db,const char *table_name);
+void net_set_write_timeout(NET *net, uint timeout);
+void net_set_read_timeout(NET *net, uint timeout);
+
#define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); }
#define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } }
#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
#define all_bits_set(A,B) ((A) & (B) != (B))
-#define WARN_DEPRECATED(Thd,Ver,Old,New) \
- do { \
- DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) >= 0); \
- push_warning_printf(((THD *)Thd), MYSQL_ERROR::WARN_LEVEL_WARN, \
- ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), \
- (Old), (Ver), (New)); \
+#define WARN_DEPRECATED(Thd,Ver,Old,New) \
+ do { \
+ DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) > 0); \
+ if (((gptr)Thd) != NULL) \
+ push_warning_printf(((THD *)Thd), MYSQL_ERROR::WARN_LEVEL_WARN, \
+ ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), \
+ (Old), (Ver), (New)); \
+ else \
+ sql_print_warning("The syntax %s is deprecated and will be removed " \
+ "in MySQL %s. Please use %s instead.", (Old), (Ver), (New)); \
} while(0)
-
extern CHARSET_INFO *system_charset_info, *files_charset_info ;
extern CHARSET_INFO *national_charset_info, *table_alias_charset;
@@ -167,7 +174,7 @@ MY_LOCALE *my_locale_by_number(uint number);
Feel free to raise this by the smallest amount you can to get the
"execution_constants" test to pass.
*/
-#define STACK_MIN_SIZE 10788 // Abort if less stack during eval.
+#define STACK_MIN_SIZE 12000 // Abort if less stack during eval.
#define STACK_MIN_SIZE_FOR_OPEN 1024*80
#define STACK_BUFF_ALLOC 256 // For stack overrun checks
@@ -279,7 +286,6 @@ MY_LOCALE *my_locale_by_number(uint number);
#define TEST_MIT_THREAD 4
#define TEST_BLOCKING 8
#define TEST_KEEP_TMP_TABLES 16
-#define TEST_NO_THREADS 32 /* For debugging under Linux */
#define TEST_READCHECK 64 /* Force use of readcheck */
#define TEST_NO_EXTRA 128
#define TEST_CORE_ON_SIGNAL 256 /* Give core if signal */
@@ -307,33 +313,33 @@ MY_LOCALE *my_locale_by_number(uint number);
TODO: separate three contexts above, move them to separate bitfields.
*/
-#define SELECT_DISTINCT (ULL(1) << 0) // SELECT, user
-#define SELECT_STRAIGHT_JOIN (ULL(1) << 1) // SELECT, user
-#define SELECT_DESCRIBE (ULL(1) << 2) // SELECT, user
-#define SELECT_SMALL_RESULT (ULL(1) << 3) // SELECT, user
-#define SELECT_BIG_RESULT (ULL(1) << 4) // SELECT, user
-#define OPTION_FOUND_ROWS (ULL(1) << 5) // SELECT, user
-#define OPTION_TO_QUERY_CACHE (ULL(1) << 6) // SELECT, user
-#define SELECT_NO_JOIN_CACHE (ULL(1) << 7) // intern
-#define OPTION_BIG_TABLES (ULL(1) << 8) // THD, user
-#define OPTION_BIG_SELECTS (ULL(1) << 9) // THD, user
-#define OPTION_LOG_OFF (ULL(1) << 10) // THD, user
-#define OPTION_QUOTE_SHOW_CREATE (ULL(1) << 11) // THD, user
-#define TMP_TABLE_ALL_COLUMNS (ULL(1) << 12) // SELECT, intern
-#define OPTION_WARNINGS (ULL(1) << 13) // THD, user
-#define OPTION_AUTO_IS_NULL (ULL(1) << 14) // THD, user, binlog
-#define OPTION_FOUND_COMMENT (ULL(1) << 15) // SELECT, intern, parser
-#define OPTION_SAFE_UPDATES (ULL(1) << 16) // THD, user
-#define OPTION_BUFFER_RESULT (ULL(1) << 17) // SELECT, user
-#define OPTION_BIN_LOG (ULL(1) << 18) // THD, user
-#define OPTION_NOT_AUTOCOMMIT (ULL(1) << 19) // THD, user
-#define OPTION_BEGIN (ULL(1) << 20) // THD, intern
-#define OPTION_TABLE_LOCK (ULL(1) << 21) // THD, intern
-#define OPTION_QUICK (ULL(1) << 22) // SELECT (for DELETE)
-#define OPTION_KEEP_LOG (ULL(1) << 23) // Keep binlog on rollback
+#define SELECT_DISTINCT (ULL(1) << 0) // SELECT, user
+#define SELECT_STRAIGHT_JOIN (ULL(1) << 1) // SELECT, user
+#define SELECT_DESCRIBE (ULL(1) << 2) // SELECT, user
+#define SELECT_SMALL_RESULT (ULL(1) << 3) // SELECT, user
+#define SELECT_BIG_RESULT (ULL(1) << 4) // SELECT, user
+#define OPTION_FOUND_ROWS (ULL(1) << 5) // SELECT, user
+#define OPTION_TO_QUERY_CACHE (ULL(1) << 6) // SELECT, user
+#define SELECT_NO_JOIN_CACHE (ULL(1) << 7) // intern
+#define OPTION_BIG_TABLES (ULL(1) << 8) // THD, user
+#define OPTION_BIG_SELECTS (ULL(1) << 9) // THD, user
+#define OPTION_LOG_OFF (ULL(1) << 10) // THD, user
+#define OPTION_QUOTE_SHOW_CREATE (ULL(1) << 11) // THD, user, unused
+#define TMP_TABLE_ALL_COLUMNS (ULL(1) << 12) // SELECT, intern
+#define OPTION_WARNINGS (ULL(1) << 13) // THD, user
+#define OPTION_AUTO_IS_NULL (ULL(1) << 14) // THD, user, binlog
+#define OPTION_FOUND_COMMENT (ULL(1) << 15) // SELECT, intern, parser
+#define OPTION_SAFE_UPDATES (ULL(1) << 16) // THD, user
+#define OPTION_BUFFER_RESULT (ULL(1) << 17) // SELECT, user
+#define OPTION_BIN_LOG (ULL(1) << 18) // THD, user
+#define OPTION_NOT_AUTOCOMMIT (ULL(1) << 19) // THD, user
+#define OPTION_BEGIN (ULL(1) << 20) // THD, intern
+#define OPTION_TABLE_LOCK (ULL(1) << 21) // THD, intern
+#define OPTION_QUICK (ULL(1) << 22) // SELECT (for DELETE)
+#define OPTION_KEEP_LOG (ULL(1) << 23) // THD, user
/* The following is used to detect a conflict with DISTINCT */
-#define SELECT_ALL (ULL(1) << 24) // SELECT, user, parser
+#define SELECT_ALL (ULL(1) << 24) // SELECT, user, parser
/* Set if we are updating a non-transaction safe table */
#define OPTION_STATUS_NO_TRANS_UPDATE (ULL(1) << 25) // THD, intern
@@ -350,12 +356,13 @@ MY_LOCALE *my_locale_by_number(uint number);
#define OPTION_SETUP_TABLES_DONE (ULL(1) << 30) // intern
/* If not set then the thread will ignore all warnings with level notes. */
#define OPTION_SQL_NOTES (ULL(1) << 31) // THD, user
-/*
+/*
Force the used temporary table to be a MyISAM table (because we will use
fulltext functions when reading from it.
*/
#define TMP_TABLE_FORCE_MYISAM (ULL(1) << 32)
+
/*
Maximum length of time zone name that we support
(Time zone name is char(64) in db). mysqlbinlog needs it.
@@ -420,7 +427,11 @@ MY_LOCALE *my_locale_by_number(uint number);
#define UNCACHEABLE_EXPLAIN 8
/* Don't evaluate subqueries in prepare even if they're not correlated */
#define UNCACHEABLE_PREPARE 16
+/* For uncorrelated SELECT in an UNION with some correlated SELECTs */
+#define UNCACHEABLE_UNITED 32
+/* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */
+#define UNDEF_POS (-1)
#ifdef EXTRA_DEBUG
/*
Sync points allow us to force the server to reach a certain line of code
@@ -779,6 +790,23 @@ uint build_table_path(char *buff, size_t bufflen, const char *db,
void write_bin_log(THD *thd, bool clear_error,
char const *query, ulong query_length);
+/* sql_connect.cc */
+int check_user(THD *thd, enum enum_server_command command,
+ const char *passwd, uint passwd_len, const char *db,
+ bool check_count);
+pthread_handler_t handle_one_connection(void *arg);
+bool init_new_connection_handler_thread();
+void reset_mqh(LEX_USER *lu, bool get_them);
+bool check_mqh(THD *thd, uint check_command);
+void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
+int check_for_max_user_connections(THD *thd, USER_CONN *uc);
+void decrease_user_connections(USER_CONN *uc);
+void thd_init_client_charset(THD *thd, uint cs_number);
+bool setup_connection_thread_globals(THD *thd);
+bool login_connection(THD *thd);
+void prepare_new_connection_state(THD* thd);
+void end_connection(THD *thd);
+
bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
@@ -814,16 +842,14 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
void init_max_user_conn(void);
void init_update_queries(void);
void free_max_user_conn(void);
-pthread_handler_t handle_one_connection(void *arg);
pthread_handler_t handle_bootstrap(void *arg);
-void end_thread(THD *thd,bool put_in_cache);
-void flush_thread_cache();
bool mysql_execute_command(THD *thd);
bool do_command(THD *thd);
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length);
void log_slow_statement(THD *thd);
bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
+bool compare_record(TABLE *table);
bool append_file_to_dir(THD *thd, const char **filename_ptr,
const char *table_name);
@@ -892,6 +918,8 @@ int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool *hidden_group_fields);
+bool fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
+ Item **ref_pointer_array);
bool handle_select(THD *thd, LEX *lex, select_result *result,
ulong setup_tables_done_option);
@@ -1093,7 +1121,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
-bool get_schema_tables_result(JOIN *join);
+bool get_schema_tables_result(JOIN *join,
+ enum enum_schema_table_state executed_place);
#define is_schema_db(X) \
!my_strcasecmp(system_charset_info, information_schema_name.str, (X))
@@ -1147,7 +1176,8 @@ bool push_new_name_resolution_context(THD *thd,
TABLE_LIST *left_op,
TABLE_LIST *right_op);
void add_join_on(TABLE_LIST *b,Item *expr);
-void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields);
+void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields,
+ SELECT_LEX *lex);
bool add_proc_to_list(THD *thd, Item *item);
TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
void update_non_unique_table_error(TABLE_LIST *update,
@@ -1484,6 +1514,11 @@ File open_binlog(IO_CACHE *log, const char *log_file_name,
extern void MYSQLerror(const char*);
void refresh_status(THD *thd);
my_bool mysql_rm_tmp_tables(void);
+void handle_connection_in_main_thread(THD *thd);
+void create_thread_to_handle_connection(THD *thd);
+void unlink_thd(THD *thd);
+bool one_thread_per_connection_end(THD *thd, bool put_in_cache);
+void flush_thread_cache();
/* item_func.cc */
extern bool check_reserved_words(LEX_STRING *name);
@@ -1518,7 +1553,7 @@ extern int creating_table; // How many mysql_create_table() are running
External variables
*/
-extern time_t start_time;
+extern time_t server_start_time;
extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH],
mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[],
def_ft_boolean_syntax[sizeof(ft_boolean_syntax)];
@@ -1528,7 +1563,7 @@ extern const LEX_STRING command_name[];
extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword;
extern const char **errmesg; /* Error messages */
extern const char *myisam_recover_options_str;
-extern const char *in_left_expr_name, *in_additional_cond;
+extern const char *in_left_expr_name, *in_additional_cond, *in_having_cond;
extern const char * const triggers_file_ext;
extern const char * const trigname_file_ext;
extern Eq_creator eq_creator;
@@ -1543,10 +1578,11 @@ extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file;
extern char log_error_file[FN_REFLEN], *opt_tc_log_file;
extern double log_10[32];
+extern double log_01[32];
extern ulonglong log_10_int[20];
extern ulonglong keybuff_size;
extern ulonglong thd_startup_options;
-extern ulong refresh_version,flush_version, thread_id;
+extern ulong refresh_version, thread_id;
extern ulong binlog_cache_use, binlog_cache_disk_use;
extern ulong aborted_threads,aborted_connects;
extern ulong delayed_insert_timeout;
@@ -1566,7 +1602,7 @@ extern ulong max_prepared_stmt_count, prepared_stmt_count;
extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
extern ulong max_binlog_size, max_relay_log_size;
extern ulong opt_binlog_rows_event_max_size;
-extern ulong rpl_recovery_rank, thread_cache_size;
+extern ulong rpl_recovery_rank, thread_cache_size, thread_pool_size;
extern ulong back_log;
extern ulong specialflag, current_pid;
extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter;
@@ -1651,6 +1687,9 @@ extern TABLE *unused_tables;
extern const char* any_db;
extern struct my_option my_long_options[];
extern const LEX_STRING view_type;
+extern scheduler_functions thread_scheduler;
+extern TYPELIB thread_handling_typelib;
+extern uint8 uc_update_queries[SQLCOM_END+1];
extern uint sql_command_flags[];
extern TYPELIB log_output_typelib;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 6114c5da0cd..83b16d9af0a 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -59,10 +59,6 @@
#define mysqld_charset &my_charset_latin1
-#ifndef DBUG_OFF
-#define ONE_THREAD
-#endif
-
#ifdef HAVE_purify
#define IF_PURIFY(A,B) (A)
#else
@@ -282,6 +278,16 @@ static TYPELIB tc_heuristic_recover_typelib=
array_elements(tc_heuristic_recover_names)-1,"",
tc_heuristic_recover_names, NULL
};
+
+static const char *thread_handling_names[]=
+{ "one-thread-per-connection", "no-threads", "pool-of-threads", NullS};
+
+TYPELIB thread_handling_typelib=
+{
+ array_elements(thread_handling_names) - 1, "",
+ thread_handling_names, NULL
+};
+
const char *first_keyword= "first", *binary_keyword= "BINARY";
const char *my_localhost= "localhost", *delayed_user= "DELAYED";
#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES)
@@ -361,6 +367,7 @@ my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
my_bool opt_log_slave_updates= 0;
my_bool opt_innodb;
+bool slave_warning_issued = false;
/*
Legacy global handlerton. These will be removed (please do not add more).
@@ -448,9 +455,10 @@ my_bool sp_automatic_privileges= 1;
ulong opt_binlog_rows_event_max_size;
const char *binlog_format_names[]= {"STATEMENT", "ROW", "MIXED", NullS};
TYPELIB binlog_format_typelib=
- { array_elements(binlog_format_names)-1,"",
+ { array_elements(binlog_format_names) - 1, "",
binlog_format_names, NULL };
-
+ulong opt_binlog_format_id= (ulong) BINLOG_FORMAT_UNSPEC;
+const char *opt_binlog_format= binlog_format_names[opt_binlog_format_id];
#ifdef HAVE_INITGROUPS
static bool calling_initgroups= FALSE; /* Used in SIGSEGV handler. */
#endif
@@ -467,10 +475,11 @@ ulong thread_stack, what_to_log;
ulong query_buff_size, slow_launch_time, slave_open_temp_tables;
ulong open_files_limit, max_binlog_size, max_relay_log_size;
ulong slave_net_timeout, slave_trans_retries;
-ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
+ulong thread_cache_size=0, thread_pool_size= 0;
+ulong binlog_cache_size=0, max_binlog_cache_size=0;
ulong query_cache_size=0;
-ulong refresh_version, flush_version; /* Increments on each reload */
-query_id_t query_id;
+ulong refresh_version; /* Increments on each reload */
+query_id_t global_query_id;
ulong aborted_threads, aborted_connects;
ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size;
ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use;
@@ -502,7 +511,8 @@ ulong rpl_recovery_rank=0;
const char *log_output_str= "TABLE";
double log_10[32]; /* 10 potences */
-time_t start_time;
+double log_01[32];
+time_t server_start_time;
char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], system_time_zone[30];
char *default_tz_name;
@@ -518,16 +528,18 @@ key_map key_map_full(0); // Will be initialized later
const char *opt_date_time_formats[3];
char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home;
-struct passwd *user_info;
char server_version[SERVER_VERSION_LENGTH];
char *mysqld_unix_port, *opt_mysql_tmpdir;
const char **errmesg; /* Error messages */
const char *myisam_recover_options_str="OFF";
const char *myisam_stats_method_str="nulls_unequal";
+
/* name of reference on left espression in rewritten IN subquery */
const char *in_left_expr_name= "<left expr>";
/* name of additional condition */
const char *in_additional_cond= "<IN COND>";
+const char *in_having_cond= "<IN HAVING>";
+
my_decimal decimal_zero;
/* classes for comparation parsing/processing */
Eq_creator eq_creator;
@@ -537,7 +549,6 @@ Lt_creator lt_creator;
Ge_creator ge_creator;
Le_creator le_creator;
-
FILE *bootstrap_file;
int bootstrap_error;
FILE *stderror_file=0;
@@ -620,9 +631,13 @@ static char **defaults_argv;
static char *opt_bin_logname;
static my_socket unix_sock,ip_sock;
-static pthread_t select_thread;
struct rand_struct sql_rand; // used by sql_class.cc:THD::THD()
+#ifndef EMBEDDED_LIBRARY
+struct passwd *user_info;
+static pthread_t select_thread;
+#endif
+
/* OS specific variables */
#ifdef __WIN__
@@ -675,6 +690,8 @@ my_bool opt_enable_shared_memory;
HANDLE smem_event_connect_request= 0;
#endif
+scheduler_functions thread_scheduler;
+
#define SSL_VARS_NOT_STATIC
#include "sslopt-vars.h"
#ifdef HAVE_OPENSSL
@@ -699,7 +716,6 @@ struct st_VioSSLFd *ssl_acceptor_fd;
/* Function declarations */
-static void start_signal_handler(void);
pthread_handler_t signal_hand(void *arg);
static void mysql_init_variables(void);
static void get_options(int argc,char **argv);
@@ -710,7 +726,6 @@ static void fix_paths(void);
pthread_handler_t handle_connections_sockets(void *arg);
pthread_handler_t kill_server_thread(void *arg);
static void bootstrap(FILE *file);
-static void close_server_sock();
static bool read_init_file(char *file_name);
#ifdef __NT__
pthread_handler_t handle_connections_namedpipes(void *arg);
@@ -721,11 +736,17 @@ pthread_handler_t handle_connections_shared_memory(void *arg);
pthread_handler_t handle_slave(void *arg);
static ulong find_bit_type(const char *x, TYPELIB *bit_lib);
static void clean_up(bool print_message);
+static int test_if_case_insensitive(const char *dir_name);
+
+#ifndef EMBEDDED_LIBRARY
+static void start_signal_handler(void);
+static void close_server_sock();
static void clean_up_mutexes(void);
static void wait_for_signal_thread_to_end(void);
-static int test_if_case_insensitive(const char *dir_name);
static void create_pid_file();
static void end_ssl();
+#endif
+
#ifndef EMBEDDED_LIBRARY
/****************************************************************************
@@ -851,6 +872,7 @@ static void close_connections(void)
continue;
tmp->killed= THD::KILL_CONNECTION;
+ thread_scheduler.post_kill_notification(tmp);
if (tmp->mysys_var)
{
tmp->mysys_var->abort=1;
@@ -915,7 +937,6 @@ static void close_connections(void)
DBUG_PRINT("quit",("close_connections thread"));
DBUG_VOID_RETURN;
}
-#endif /*EMBEDDED_LIBRARY*/
static void close_server_sock()
@@ -958,12 +979,14 @@ static void close_server_sock()
#endif
}
+#endif /*EMBEDDED_LIBRARY*/
+
void kill_mysql(void)
{
DBUG_ENTER("kill_mysql");
-#ifdef SIGNALS_DONT_BREAK_READ
+#if defined(SIGNALS_DONT_BREAK_READ) && !defined(EMBEDDED_LIBRARY)
abort_loop=1; // Break connection loops
close_server_sock(); // Force accept to wake up
#endif
@@ -1041,7 +1064,7 @@ static void __cdecl kill_server(int sig_ptr)
kill_in_progress=TRUE;
abort_loop=1; // This should be set
if (sig != 0) // 0 is not a valid signal number
- my_sigset(sig,SIG_IGN);
+ my_sigset(sig, SIG_IGN); /* purify inspected */
if (sig == MYSQL_KILL_SIGNAL || sig == 0)
sql_print_information(ER(ER_NORMAL_SHUTDOWN),my_progname);
else
@@ -1229,7 +1252,9 @@ void clean_up(bool print_message)
#endif
delete binlog_filter;
delete rpl_filter;
+#ifndef EMBEDDED_LIBRARY
end_ssl();
+#endif
vio_end();
#ifdef USE_REGEX
my_regex_end();
@@ -1241,6 +1266,7 @@ void clean_up(bool print_message)
if (!opt_bootstrap)
(void) my_delete(pidfile_name,MYF(0)); // This may not always exist
#endif
+ thread_scheduler.end();
finish_client_errs();
my_free((gptr) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST),
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
@@ -1262,6 +1288,8 @@ void clean_up(bool print_message)
} /* clean_up */
+#ifndef EMBEDDED_LIBRARY
+
/*
This is mainly needed when running with purify, but it's still nice to
know that all child threads have died when mysqld exits
@@ -1332,6 +1360,9 @@ static void clean_up_mutexes()
(void) pthread_cond_destroy(&COND_manager);
}
+#endif /*EMBEDDED_LIBRARY*/
+
+
/****************************************************************************
** Init IP and UNIX socket
****************************************************************************/
@@ -1366,7 +1397,7 @@ static void set_ports()
static struct passwd *check_user(const char *user)
{
#if !defined(__WIN__) && !defined(__NETWARE__)
- struct passwd *user_info;
+ struct passwd *tmp_user_info;
uid_t user_id= geteuid();
// Don't bother if we aren't superuser
@@ -1374,12 +1405,14 @@ static struct passwd *check_user(const char *user)
{
if (user)
{
- // Don't give a warning, if real user is same as given with --user
- user_info= getpwnam(user);
- if ((!user_info || user_id != user_info->pw_uid) &&
+ /* Don't give a warning, if real user is same as given with --user */
+ /* purecov: begin tested */
+ tmp_user_info= getpwnam(user);
+ if ((!tmp_user_info || user_id != tmp_user_info->pw_uid) &&
global_system_variables.log_warnings)
sql_print_warning(
"One can only use the --user switch if running as root\n");
+ /* purecov: end */
}
return NULL;
}
@@ -1392,23 +1425,22 @@ static struct passwd *check_user(const char *user)
}
return NULL;
}
+ /* purecov: begin tested */
if (!strcmp(user,"root"))
return NULL; // Avoid problem with dynamic libraries
- if (!(user_info= getpwnam(user)))
+ if (!(tmp_user_info= getpwnam(user)))
{
// Allow a numeric uid to be used
const char *pos;
for (pos= user; my_isdigit(mysqld_charset,*pos); pos++) ;
if (*pos) // Not numeric id
goto err;
- if (!(user_info= getpwuid(atoi(user))))
+ if (!(tmp_user_info= getpwuid(atoi(user))))
goto err;
- else
- return user_info;
}
- else
- return user_info;
+ return tmp_user_info;
+ /* purecov: end */
err:
sql_print_error("Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user);
@@ -1417,10 +1449,11 @@ err:
return NULL;
}
-static void set_user(const char *user, struct passwd *user_info)
+static void set_user(const char *user, struct passwd *user_info_arg)
{
+ /* purecov: begin tested */
#if !defined(__WIN__) && !defined(__NETWARE__)
- DBUG_ASSERT(user_info != 0);
+ DBUG_ASSERT(user_info_arg != 0);
#ifdef HAVE_INITGROUPS
/*
We can get a SIGSEGV when calling initgroups() on some systems when NSS
@@ -1429,33 +1462,34 @@ static void set_user(const char *user, struct passwd *user_info)
output a specific message to help the user resolve this problem.
*/
calling_initgroups= TRUE;
- initgroups((char*) user, user_info->pw_gid);
+ initgroups((char*) user, user_info_arg->pw_gid);
calling_initgroups= FALSE;
#endif
- if (setgid(user_info->pw_gid) == -1)
+ if (setgid(user_info_arg->pw_gid) == -1)
{
sql_perror("setgid");
unireg_abort(1);
}
- if (setuid(user_info->pw_uid) == -1)
+ if (setuid(user_info_arg->pw_uid) == -1)
{
sql_perror("setuid");
unireg_abort(1);
}
#endif
+ /* purecov: end */
}
-static void set_effective_user(struct passwd *user_info)
+static void set_effective_user(struct passwd *user_info_arg)
{
#if !defined(__WIN__) && !defined(__NETWARE__)
- DBUG_ASSERT(user_info != 0);
- if (setregid((gid_t)-1, user_info->pw_gid) == -1)
+ DBUG_ASSERT(user_info_arg != 0);
+ if (setregid((gid_t)-1, user_info_arg->pw_gid) == -1)
{
sql_perror("setregid");
unireg_abort(1);
}
- if (setreuid((uid_t)-1, user_info->pw_uid) == -1)
+ if (setreuid((uid_t)-1, user_info_arg->pw_uid) == -1)
{
sql_perror("setreuid");
unireg_abort(1);
@@ -1492,6 +1526,9 @@ static void network_init(void)
DBUG_ENTER("network_init");
LINT_INIT(ret);
+ if (thread_scheduler.init())
+ unireg_abort(1); /* purecov: inspected */
+
set_ports();
if (mysqld_port != 0 && !opt_disable_networking && !opt_bootstrap)
@@ -1649,18 +1686,6 @@ static void network_init(void)
#endif /*!EMBEDDED_LIBRARY*/
-void MYSQLerror(const char *s)
-{
- THD *thd=current_thd;
- char *yytext= (char*) thd->lex->tok_start;
- /* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
- if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
- s=ER(ER_SYNTAX_ERROR);
- my_printf_error(ER_PARSE_ERROR, ER(ER_PARSE_ERROR), MYF(0), s,
- (yytext ? (char*) yytext : ""),
- thd->lex->yylineno);
-}
-
#ifndef EMBEDDED_LIBRARY
/*
@@ -1710,21 +1735,55 @@ extern "C" sig_handler end_thread_signal(int sig __attribute__((unused)))
if (thd && ! thd->bootstrap)
{
statistic_increment(killed_threads, &LOCK_status);
- end_thread(thd,0);
+ thread_scheduler.end_thread(thd,0); /* purecov: inspected */
}
DBUG_VOID_RETURN; /* purecov: deadcode */
}
-void end_thread(THD *thd, bool put_in_cache)
+/*
+ Unlink thd from global list of available connections and free thd
+
+ SYNOPSIS
+ unlink_thd()
+ thd Thread handler
+
+ NOTES
+ LOCK_thread_count is locked and left locked
+*/
+
+void unlink_thd(THD *thd)
{
- DBUG_ENTER("end_thread");
+ DBUG_ENTER("unlink_thd");
+ DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
thd->cleanup();
(void) pthread_mutex_lock(&LOCK_thread_count);
thread_count--;
delete thd;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Store thread in cache for reuse by new connections
- if (put_in_cache && cached_thread_count < thread_cache_size &&
+ SYNOPSIS
+ cache_thread()
+
+ NOTES
+ LOCK_thread_count has to be locked
+
+ RETURN
+ 0 Thread was not put in cache
+ 1 Thread is to be reused by new connection.
+ (ie, caller should return, not abort with pthread_exit())
+*/
+
+
+static bool cache_thread()
+{
+ safe_mutex_assert_owner(&LOCK_thread_count);
+ if (cached_thread_count < thread_cache_size &&
! abort_loop && !kill_cached_threads)
{
/* Don't kill the thread, just put it in cache for reuse */
@@ -1737,31 +1796,56 @@ void end_thread(THD *thd, bool put_in_cache)
pthread_cond_signal(&COND_flush_thread_cache);
if (wake_thread)
{
+ THD *thd;
wake_thread--;
- thd=thread_cache.get();
- thd->real_id=pthread_self();
+ thd= thread_cache.get();
thd->thread_stack= (char*) &thd; // For store_globals
(void) thd->store_globals();
thd->thr_create_time= time(NULL);
threads.append(thd);
- pthread_mutex_unlock(&LOCK_thread_count);
- DBUG_VOID_RETURN;
+ return(1);
}
}
+ return(0);
+}
+
+
+/*
+ End thread for the current connection
+
+ SYNOPSIS
+ one_thread_per_connection_end()
+ thd Thread handler
+ put_in_cache Store thread in cache, if there is room in it
+ Normally this is true in all cases except when we got
+ out of resources initializing the current thread
+
+ NOTES
+ If thread is cached, we will wait until thread is scheduled to be
+ reused and then we will return.
+ If thread is not cached, we end the thread.
+
+ RETURN
+ 0 Signal to handle_one_connection to reuse connection
+*/
+
+bool one_thread_per_connection_end(THD *thd, bool put_in_cache)
+{
+ DBUG_ENTER("one_thread_per_connection_end");
+ unlink_thd(thd);
+ if (put_in_cache)
+ put_in_cache= cache_thread();
+ pthread_mutex_unlock(&LOCK_thread_count);
+ if (put_in_cache)
+ DBUG_RETURN(0); // Thread is reused
- /* Tell main we are ready */
- (void) pthread_mutex_unlock(&LOCK_thread_count);
/* It's safe to broadcast outside a lock (COND... is not deleted here) */
DBUG_PRINT("signal", ("Broadcasting COND_thread_count"));
(void) pthread_cond_broadcast(&COND_thread_count);
-#ifdef ONE_THREAD
- if (!(test_flags & TEST_NO_THREADS)) // For debugging under Linux
-#endif
- {
- my_thread_end();
- pthread_exit(0);
- }
- DBUG_VOID_RETURN;
+
+ my_thread_end();
+ pthread_exit(0);
+ DBUG_RETURN(0); // Impossible
}
@@ -1796,6 +1880,7 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused)))
}
#endif
+
/******************************************************************************
Setup a signal thread with handles all signals.
Because Linux doesn't support schemas use a mutex to check that
@@ -1815,6 +1900,7 @@ static void init_signals(void)
#endif
}
+
static void start_signal_handler(void)
{
// Save vm id of this process
@@ -1822,6 +1908,7 @@ static void start_signal_handler(void)
create_pid_file();
}
+
static void check_data_home(const char *path)
{}
@@ -2042,6 +2129,7 @@ static void init_signals(void)
}
+
static void start_signal_handler(void)
{
// Save vm id of this process
@@ -2098,14 +2186,15 @@ and this may fail.\n\n");
(ulong) dflt_key_cache->key_cache_mem_size);
fprintf(stderr, "read_buffer_size=%ld\n", (long) global_system_variables.read_buff_size);
fprintf(stderr, "max_used_connections=%lu\n", max_used_connections);
- fprintf(stderr, "max_connections=%lu\n", max_connections);
+ fprintf(stderr, "max_threads=%u\n", thread_scheduler.max_threads);
fprintf(stderr, "threads_connected=%u\n", thread_count);
fprintf(stderr, "It is possible that mysqld could use up to \n\
-key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %lu K\n\
+key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = %lu K\n\
bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size +
(global_system_variables.read_buff_size +
global_system_variables.sortbuff_size) *
- max_connections)/ 1024);
+ thread_scheduler.max_threads +
+ max_connections * sizeof(THD)) / 1024);
fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
#if defined(HAVE_LINUXTHREADS)
@@ -2178,6 +2267,8 @@ bugs.\n");
#define SA_NODEFER 0
#endif
+#ifndef EMBEDDED_LIBRARY
+
static void init_signals(void)
{
sigset_t set;
@@ -2250,7 +2341,6 @@ static void init_signals(void)
}
-#ifndef EMBEDDED_LIBRARY
static void start_signal_handler(void)
{
int error;
@@ -2305,7 +2395,7 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
This should actually be '+ max_number_of_slaves' instead of +10,
but the +10 should be quite safe.
*/
- init_thr_alarm(max_connections +
+ init_thr_alarm(thread_scheduler.max_threads +
global_system_variables.max_insert_delayed_threads + 10);
#if SIGINT != THR_KILL_SIGNAL
if (test_flags & TEST_SIGINT)
@@ -2424,11 +2514,11 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
}
return(0); /* purecov: deadcode */
}
-#endif /*!EMBEDDED_LIBRARY*/
static void check_data_home(const char *path)
{}
+#endif /*!EMBEDDED_LIBRARY*/
#endif /* __WIN__*/
@@ -2451,6 +2541,14 @@ static int my_message_sql(uint error, const char *str, myf MyFlags)
*/
if ((thd= current_thd))
{
+ /*
+ TODO: There are two exceptions mechanism (THD and sp_rcontext),
+ this could be improved by having a common stack of handlers.
+ */
+ if (thd->handle_error(error,
+ MYSQL_ERROR::WARN_LEVEL_ERROR))
+ DBUG_RETURN(0);
+
if (thd->spcont &&
thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
{
@@ -2493,6 +2591,7 @@ static int my_message_sql(uint error, const char *str, myf MyFlags)
}
+#ifndef EMBEDDED_LIBRARY
static void *my_str_malloc_mysqld(size_t size)
{
return my_malloc(size, MYF(MY_FAE));
@@ -2503,22 +2602,11 @@ static void my_str_free_mysqld(void *ptr)
{
my_free((gptr)ptr, MYF(MY_FAE));
}
+#endif /* EMBEDDED_LIBRARY */
#ifdef __WIN__
-struct utsname
-{
- char nodename[FN_REFLEN];
-};
-
-
-int uname(struct utsname *a)
-{
- return -1;
-}
-
-
pthread_handler_t handle_shutdown(void *arg)
{
MSG msg;
@@ -2609,7 +2697,15 @@ static int init_common_variables(const char *conf_file_name, int argc,
tzset(); // Set tzname
max_system_variables.pseudo_thread_id= (ulong)~0;
- start_time=time((time_t*) 0);
+ server_start_time= time((time_t*) 0);
+ rpl_filter= new Rpl_filter;
+ binlog_filter= new Rpl_filter;
+ if (!rpl_filter || !binlog_filter)
+ {
+ sql_perror("Could not allocate replication and binlog filters");
+ exit(1);
+ }
+
if (init_thread_environment())
return 1;
mysql_init_variables();
@@ -2617,7 +2713,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
#ifdef HAVE_TZNAME
{
struct tm tm_tmp;
- localtime_r(&start_time,&tm_tmp);
+ localtime_r(&server_start_time,&tm_tmp);
strmake(system_time_zone, tzname[tm_tmp.tm_isdst != 0 ? 1 : 0],
sizeof(system_time_zone)-1);
@@ -3007,6 +3103,8 @@ static void openssl_lock(int mode, openssl_lock_t *lock, const char *file,
#endif /* HAVE_OPENSSL */
+#ifndef EMBEDDED_LIBRARY
+
static void init_ssl()
{
#ifdef HAVE_OPENSSL
@@ -3044,6 +3142,8 @@ static void end_ssl()
#endif /* HAVE_OPENSSL */
}
+#endif /* EMBEDDED_LIBRARY */
+
static int init_server_components()
{
@@ -3059,7 +3159,7 @@ static int init_server_components()
query_cache_set_min_res_unit(query_cache_min_res_unit);
query_cache_init();
query_cache_resize(query_cache_size);
- randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
+ randominit(&sql_rand,(ulong) server_start_time,(ulong) server_start_time/2);
reset_floating_point_exceptions();
init_thr_lock();
#ifdef HAVE_REPLICATION
@@ -3153,17 +3253,24 @@ with --log-bin instead.");
"--log-slave-updates work.");
unireg_abort(1);
}
-
- if (!opt_bin_log && (global_system_variables.binlog_format != BINLOG_FORMAT_UNSPEC))
- {
- sql_print_error("You need to use --log-bin to make "
- "--binlog-format work.");
- unireg_abort(1);
- }
- if (global_system_variables.binlog_format == BINLOG_FORMAT_UNSPEC)
- {
+ if (!opt_bin_log)
+ if (opt_binlog_format_id != BINLOG_FORMAT_UNSPEC)
+ {
+ sql_print_error("You need to use --log-bin to make "
+ "--binlog-format work.");
+ unireg_abort(1);
+ }
+ else
+ {
+ global_system_variables.binlog_format= BINLOG_FORMAT_UNSPEC;
+ }
+ else
+ if (opt_binlog_format_id == BINLOG_FORMAT_UNSPEC)
global_system_variables.binlog_format= BINLOG_FORMAT_MIXED;
- }
+ else
+ {
+ DBUG_ASSERT(global_system_variables.binlog_format != BINLOG_FORMAT_UNSPEC);
+ }
/* Check that we have not let the format to unspecified at this point */
DBUG_ASSERT((uint)global_system_variables.binlog_format <=
@@ -3299,7 +3406,7 @@ server.");
(TC_LOG *) &tc_log_mmap) :
(TC_LOG *) &tc_log_dummy);
- if (tc_log->open(opt_bin_logname))
+ if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
{
sql_print_error("Can't init tc log");
unireg_abort(1);
@@ -3317,7 +3424,7 @@ server.");
#ifdef HAVE_REPLICATION
if (opt_bin_log && expire_logs_days)
{
- long purge_time= time(0) - expire_logs_days*24*60*60;
+ long purge_time= (long) (time(0) - expire_logs_days*24*60*60);
if (purge_time >= 0)
mysql_bin_log.purge_logs_before_date(purge_time);
}
@@ -3362,6 +3469,8 @@ server.");
}
+#ifndef EMBEDDED_LIBRARY
+
static void create_maintenance_thread()
{
if (flush_time && flush_time != ~(ulong) 0L)
@@ -3375,7 +3484,6 @@ static void create_maintenance_thread()
static void create_shutdown_thread()
{
-#if !defined(EMBEDDED_LIBRARY)
#ifdef __WIN__
hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name);
pthread_t hThread;
@@ -3384,10 +3492,11 @@ static void create_shutdown_thread()
// On "Stop Service" we have to do regular shutdown
Service.SetShutdownEvent(hEventShutdown);
-#endif
-#endif // EMBEDDED_LIBRARY
+#endif /* __WIN__ */
}
+#endif /* EMBEDDED_LIBRARY */
+
#if (defined(__NT__) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
static void handle_connections_methods()
@@ -3470,14 +3579,6 @@ int main(int argc, char **argv)
MY_INIT(argv[0]); // init my_sys library & pthreads
/* nothing should come before this line ^^^ */
- rpl_filter= new Rpl_filter;
- binlog_filter= new Rpl_filter;
- if (!rpl_filter || !binlog_filter)
- {
- sql_perror("Could not allocate replication and binlog filters");
- exit(1);
- }
-
/*
Perform basic logger initialization logger. Should be called after
MY_INIT, as it initializes mutexes. Log tables are inited later.
@@ -3975,7 +4076,7 @@ static void bootstrap(FILE *file)
my_net_init(&thd->net,(st_vio*) 0);
thd->max_client_packet_length= thd->net.max_packet;
thd->security_ctx->master_access= ~(ulong)0;
- thd->thread_id=thread_id++;
+ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
thread_count++;
bootstrap_file=file;
@@ -4018,6 +4119,74 @@ static bool read_init_file(char *file_name)
#ifndef EMBEDDED_LIBRARY
+
+/*
+ Simple scheduler that use the main thread to handle the request
+
+ NOTES
+ This is only used for debugging, when starting mysqld with
+ --thread-handling=no-threads or --one-thread
+
+ When we enter this function, LOCK_thread_count is hold!
+*/
+
+void handle_connection_in_main_thread(THD *thd)
+{
+ safe_mutex_assert_owner(&LOCK_thread_count);
+ thread_cache_size=0; // Safety
+ threads.append(thd);
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ handle_one_connection((void*) thd);
+}
+
+
+/*
+ Scheduler that uses one thread per connection
+*/
+
+void create_thread_to_handle_connection(THD *thd)
+{
+ if (cached_thread_count > wake_thread)
+ {
+ /* Get thread from cache */
+ thread_cache.append(thd);
+ wake_thread++;
+ pthread_cond_signal(&COND_thread_cache);
+ }
+ else
+ {
+ /* Create new thread to handle connection */
+ int error;
+ thread_created++;
+ threads.append(thd);
+ DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id));
+ thd->connect_time = time(NULL);
+ if ((error=pthread_create(&thd->real_id,&connection_attrib,
+ handle_one_connection,
+ (void*) thd)))
+ {
+ /* purify: begin inspected */
+ DBUG_PRINT("error",
+ ("Can't create thread to handle request (error %d)",
+ error));
+ thread_count--;
+ thd->killed= THD::KILL_CONNECTION; // Safety
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ statistic_increment(aborted_connects,&LOCK_status);
+ net_printf_error(thd, ER_CANT_CREATE_THREAD, error);
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ close_connection(thd,0,0);
+ delete thd;
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ return;
+ /* purecov: end */
+ }
+ }
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_PRINT("info",("Thread created"));
+}
+
+
/*
Create new thread to handle incoming connection.
@@ -4039,10 +4208,9 @@ static bool read_init_file(char *file_name)
static void create_new_thread(THD *thd)
{
+ NET *net=&thd->net;
DBUG_ENTER("create_new_thread");
- NET *net=&thd->net; // For easy ref
- net->read_timeout = (uint) connect_timeout;
if (protocol_version > 9)
net->return_errno=1;
@@ -4055,64 +4223,15 @@ static void create_new_thread(THD *thd)
DBUG_VOID_RETURN;
}
pthread_mutex_lock(&LOCK_thread_count);
- thd->thread_id=thread_id++;
-
- thd->real_id=pthread_self(); // Keep purify happy
+ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
/* Start a new thread to handle connection */
thread_count++;
-#ifdef ONE_THREAD
- if (test_flags & TEST_NO_THREADS) // For debugging under Linux
- {
- thread_cache_size=0; // Safety
- threads.append(thd);
- thd->real_id=pthread_self();
- (void) pthread_mutex_unlock(&LOCK_thread_count);
- handle_one_connection((void*) thd);
- }
- else
-#endif
- {
- if (thread_count-delayed_insert_threads > max_used_connections)
- max_used_connections=thread_count-delayed_insert_threads;
+ if (thread_count - delayed_insert_threads > max_used_connections)
+ max_used_connections= thread_count - delayed_insert_threads;
- if (cached_thread_count > wake_thread)
- {
- thread_cache.append(thd);
- wake_thread++;
- pthread_cond_signal(&COND_thread_cache);
- }
- else
- {
- int error;
- thread_created++;
- threads.append(thd);
- DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id));
- thd->connect_time = time(NULL);
- if ((error=pthread_create(&thd->real_id,&connection_attrib,
- handle_one_connection,
- (void*) thd)))
- {
- DBUG_PRINT("error",
- ("Can't create thread to handle request (error %d)",
- error));
- thread_count--;
- thd->killed= THD::KILL_CONNECTION; // Safety
- (void) pthread_mutex_unlock(&LOCK_thread_count);
- statistic_increment(aborted_connects,&LOCK_status);
- net_printf_error(thd, ER_CANT_CREATE_THREAD, error);
- (void) pthread_mutex_lock(&LOCK_thread_count);
- close_connection(thd,0,0);
- delete thd;
- (void) pthread_mutex_unlock(&LOCK_thread_count);
- DBUG_VOID_RETURN;
- }
- }
- (void) pthread_mutex_unlock(&LOCK_thread_count);
-
- }
- DBUG_PRINT("info",("Thread created"));
+ thread_scheduler.add_connection(thd);
DBUG_VOID_RETURN;
}
#endif /* EMBEDDED_LIBRARY */
@@ -4336,12 +4455,7 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
}
if (sock == unix_sock)
thd->security_ctx->host=(char*) my_localhost;
-#ifdef __WIN__
- /* Set default wait_timeout */
- ulong wait_timeout= global_system_variables.net_wait_timeout * 1000;
- (void) setsockopt(new_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&wait_timeout,
- sizeof(wait_timeout));
-#endif
+
create_new_thread(thd);
}
@@ -4867,6 +4981,7 @@ enum options_mysqld
OPT_GENERAL_LOG,
OPT_SLOW_LOG,
OPT_MERGE,
+ OPT_THREAD_HANDLING,
OPT_INNODB_ROLLBACK_ON_TIMEOUT
};
@@ -4918,6 +5033,7 @@ struct my_option my_long_options[] =
(gptr*) &my_bind_addr_str, (gptr*) &my_bind_addr_str, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"binlog_format", OPT_BINLOG_FORMAT,
+ "Does not have any effect without '--log-bin'. "
"Tell the master the form of binary logging to use: either 'row' for "
"row-based binary logging, or 'statement' for statement-based binary "
"logging, or 'mixed'. 'mixed' is statement-based binary logging except "
@@ -4925,11 +5041,12 @@ struct my_option my_long_options[] =
"involve user-defined functions (i.e. UDFs) or the UUID() function; for "
"those, row-based binary logging is automatically used. "
#ifdef HAVE_NDB_BINLOG
- "If ndbcluster is enabled, the default is 'row'."
+ "If ndbcluster is enabled and binlog_format is `mixed', the format switches"
+ " to 'row' and back implicitly per each query accessing a NDB table."
#endif
- , 0, 0, 0, GET_STR, REQUIRED_ARG,
- BINLOG_FORMAT_MIXED
- , 0, 0, 0, 0, 0 },
+ ,(gptr*) &opt_binlog_format, (gptr*) &opt_binlog_format,
+ 0, GET_STR, REQUIRED_ARG, BINLOG_FORMAT_MIXED, BINLOG_FORMAT_STMT,
+ BINLOG_FORMAT_MIXED, 0, 0, 0},
{"binlog-do-db", OPT_BINLOG_DO_DB,
"Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -5044,7 +5161,7 @@ struct my_option my_long_options[] =
"Push supported query conditions to the storage engine.",
(gptr*) &global_system_variables.engine_condition_pushdown,
(gptr*) &global_system_variables.engine_condition_pushdown,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
/* See how it's handled in get_one_option() */
{"event-scheduler", OPT_EVENT_SCHEDULER, "Enable/disable the event scheduler.",
NULL, NULL, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
@@ -5474,11 +5591,9 @@ Disable with --skip-ndbcluster (will save memory).",
(gptr*) &global_system_variables.old_passwords,
(gptr*) &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
-#ifdef ONE_THREAD
{"one-thread", OPT_ONE_THREAD,
- "Only use one thread (for debugging under Linux).", 0, 0, 0, GET_NO_ARG,
- NO_ARG, 0, 0, 0, 0, 0, 0},
-#endif
+ "(deprecated): Only use one thread (for debugging under Linux). Use thread-handling=no-threads instead",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"old-style-user-limits", OPT_OLD_STYLE_USER_LIMITS,
"Enable old-style user limits (before 5.0.3 user resources were counted per each user+host vs. per account)",
(gptr*) &opt_old_style_user_limits, (gptr*) &opt_old_style_user_limits,
@@ -5957,7 +6072,7 @@ The minimum value for this variable is 4096.",
// children, to avoid "too many connections" error in a common setup
{"max_connections", OPT_MAX_CONNECTIONS,
"The number of simultaneous clients allowed.", (gptr*) &max_connections,
- (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 151, 1, 16384, 0, 1,
+ (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 151, 1, 100000, 0, 1,
0},
{"max_delayed_threads", OPT_MAX_DELAYED_THREADS,
"Don't start more than this number of threads to handle INSERT DELAYED statements. If set to zero, which means INSERT DELAYED is not used.",
@@ -6248,6 +6363,12 @@ The minimum value for this variable is 4096.",
"Permits the application to give the threads system a hint for the desired number of threads that should be run at the same time.",
(gptr*) &concurrency, (gptr*) &concurrency, 0, GET_ULONG, REQUIRED_ARG,
DEFAULT_CONCURRENCY, 1, 512, 0, 1, 0},
+#if HAVE_POOL_OF_THREADS == 1
+ {"thread_pool_size", OPT_THREAD_CACHE_SIZE,
+ "How many threads we should create to handle query requests in case of 'thread_handling=pool-of-threads'",
+ (gptr*) &thread_pool_size, (gptr*) &thread_pool_size, 0, GET_ULONG,
+ REQUIRED_ARG, 20, 1, 16384, 0, 1, 0},
+#endif
{"thread_stack", OPT_THREAD_STACK,
"The stack size for each thread.", (gptr*) &thread_stack,
(gptr*) &thread_stack, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK,
@@ -6272,6 +6393,10 @@ The minimum value for this variable is 4096.",
(gptr*) &global_system_variables.trans_prealloc_size,
(gptr*) &max_system_variables.trans_prealloc_size, 0, GET_ULONG,
REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0},
+ {"thread_handling", OPT_THREAD_HANDLING,
+ "Define threads usage for handling queries: "
+ "one-thread-per-connection or no-threads", 0, 0,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"updatable_views_with_limit", OPT_UPDATABLE_VIEWS_WITH_LIMIT,
"1 = YES = Don't issue an error message (warning only) if a VIEW without presence of a key of the underlying table is used in queries with a LIMIT clause for updating. 0 = NO = Prohibit update of a VIEW, which does not contain a key of the underlying table and the query uses a LIMIT clause (usually get from GUI tools).",
(gptr*) &global_system_variables.updatable_views_with_limit,
@@ -6304,7 +6429,7 @@ static int show_starttime(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_LONG;
var->value= buff;
- *((long *)buff)= (long) (thd->query_start() - start_time);
+ *((long *)buff)= (long) (thd->query_start() - server_start_time);
return 0;
}
@@ -6987,8 +7112,8 @@ static void mysql_init_variables(void)
OPTION_QUOTE_SHOW_CREATE | OPTION_SQL_NOTES);
protocol_version= PROTOCOL_VERSION;
what_to_log= ~ (1L << (uint) COM_TIME);
- refresh_version= flush_version= 1L; /* Increments on each reload */
- query_id= thread_id= 1L;
+ refresh_version= 1L; /* Increments on each reload */
+ global_query_id= thread_id= 1L;
strmov(server_version, MYSQL_SERVER_VERSION);
myisam_recover_options_str= sql_mode_str= "OFF";
myisam_stats_method_str= "nulls_unequal";
@@ -7213,7 +7338,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
case 'T':
test_flags= argument ? (uint) atoi(argument) : 0;
- test_flags&= ~TEST_NO_THREADS;
opt_endinfo=1;
break;
case (int) OPT_BIG_TABLES:
@@ -7306,7 +7430,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
binlog_format_names[BINLOG_FORMAT_MIXED]);
exit(1);
}
- global_system_variables.binlog_format= id-1;
+ global_system_variables.binlog_format= opt_binlog_format_id= id - 1;
break;
}
case (int)OPT_BINLOG_DO_DB:
@@ -7445,11 +7569,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_skip_show_db=1;
opt_specialflag|=SPECIAL_SKIP_SHOW_DB;
break;
-#ifdef ONE_THREAD
- case (int) OPT_ONE_THREAD:
- test_flags |= TEST_NO_THREADS;
-#endif
- break;
case (int) OPT_WANT_CORE:
test_flags |= TEST_CORE_ON_SIGNAL;
break;
@@ -7490,6 +7609,29 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case (int) OPT_STANDALONE: /* Dummy option for NT */
break;
#endif
+ /*
+ The following change issues a deprecation warning if the slave
+ configuration is specified either in the my.cnf file or on
+ the command-line. See BUG#21490.
+ */
+ case OPT_MASTER_HOST:
+ case OPT_MASTER_USER:
+ case OPT_MASTER_PASSWORD:
+ case OPT_MASTER_PORT:
+ case OPT_MASTER_CONNECT_RETRY:
+ case OPT_MASTER_SSL:
+ case OPT_MASTER_SSL_KEY:
+ case OPT_MASTER_SSL_CERT:
+ case OPT_MASTER_SSL_CAPATH:
+ case OPT_MASTER_SSL_CIPHER:
+ case OPT_MASTER_SSL_CA:
+ if (!slave_warning_issued) //only show the warning once
+ {
+ slave_warning_issued = true;
+ WARN_DEPRECATED(NULL, "5.2", "for replication startup options",
+ "'CHANGE MASTER'");
+ }
+ break;
case OPT_CONSOLE:
if (opt_console)
opt_error_log= 0; // Force logs to stdout
@@ -7695,6 +7837,23 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
sql_mode);
break;
}
+ case OPT_ONE_THREAD:
+ global_system_variables.thread_handling= 2;
+ break;
+ case OPT_THREAD_HANDLING:
+ {
+ if ((global_system_variables.thread_handling=
+ find_type(argument, &thread_handling_typelib, 2)) <= 0 ||
+ (global_system_variables.thread_handling == SCHEDULER_POOL_OF_THREADS
+ && !HAVE_POOL_OF_THREADS))
+ {
+ /* purecov: begin tested */
+ fprintf(stderr,"Unknown/unsupported thread-handling: %s\n",argument);
+ exit(1);
+ /* purecov: end */
+ }
+ break;
+ }
case OPT_FT_BOOLEAN_SYNTAX:
if (ft_boolean_check_syntax_string((byte*) argument))
{
@@ -7815,6 +7974,7 @@ static void get_options(int argc,char **argv)
if (mysqld_chroot)
set_root(mysqld_chroot);
#else
+ global_system_variables.thread_handling = SCHEDULER_NO_THREADS;
max_allowed_packet= global_system_variables.max_allowed_packet;
net_buffer_length= global_system_variables.net_buffer_length;
#endif
@@ -7845,6 +8005,17 @@ static void get_options(int argc,char **argv)
&global_system_variables.datetime_format))
exit(1);
+#ifdef EMBEDDED_LIBRARY
+ one_thread_scheduler(&thread_scheduler);
+#else
+ if (global_system_variables.thread_handling <=
+ SCHEDULER_ONE_THREAD_PER_CONNECTION)
+ one_thread_per_connection_scheduler(&thread_scheduler);
+ else if (global_system_variables.thread_handling == SCHEDULER_NO_THREADS)
+ one_thread_scheduler(&thread_scheduler);
+ else
+ pool_of_threads_scheduler(&thread_scheduler); /* purecov: tested */
+#endif
}
@@ -8062,6 +8233,8 @@ static int test_if_case_insensitive(const char *dir_name)
/* Create file to store pid number */
+#ifndef EMBEDDED_LIBRARY
+
static void create_pid_file()
{
File file;
@@ -8081,7 +8254,7 @@ static void create_pid_file()
sql_perror("Can't start server: can't create PID file");
exit(1);
}
-
+#endif /* EMBEDDED_LIBRARY */
/* Clear most status variables */
void refresh_status(THD *thd)
@@ -8183,5 +8356,3 @@ template class I_List<NAMED_LIST>;
template class I_List<Statement>;
template class I_List_iterator<Statement>;
#endif
-
-
diff --git a/sql/mysqld.cc.rej b/sql/mysqld.cc.rej
deleted file mode 100644
index 62f0357622d..00000000000
--- a/sql/mysqld.cc.rej
+++ /dev/null
@@ -1,17 +0,0 @@
-***************
-*** 5316,5322 ****
- (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \
- --skip-merge.",
-! (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0},
- {"myisam-recover", OPT_MYISAM_RECOVER,
- "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.",
- (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0,
---- 5336,5342 ----
- (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \
- --skip-merge.",
-! (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
- {"myisam-recover", OPT_MYISAM_RECOVER,
- "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.",
- (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0,
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 7c0e40543a8..2156888b8cf 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -47,9 +47,6 @@
#include <violite.h>
#include <signal.h>
#include <errno.h>
-#ifdef __WIN__
-#include <winsock.h>
-#endif
#ifdef __NETWARE__
#include <sys/select.h>
#endif
@@ -220,6 +217,8 @@ my_bool net_realloc(NET *net, ulong length)
-1 Don't know if data is ready or not
*/
+#if !defined(EMBEDDED_LIBRARY)
+
static int net_data_is_ready(my_socket sd)
{
#ifdef HAVE_POLL
@@ -254,9 +253,10 @@ static int net_data_is_ready(my_socket sd)
return 0;
else
return test(res ? FD_ISSET(sd, &sfds) : 0);
-#endif
+#endif /* HAVE_POLL */
}
+#endif /* EMBEDDED_LIBRARY */
/*
Remove unwanted characters from connection
@@ -282,8 +282,11 @@ static int net_data_is_ready(my_socket sd)
void net_clear(NET *net, my_bool clear_buffer)
{
+#if !defined(EMBEDDED_LIBRARY)
int count, ready;
+#endif
DBUG_ENTER("net_clear");
+
#if !defined(EMBEDDED_LIBRARY)
if (clear_buffer)
{
@@ -295,7 +298,7 @@ void net_clear(NET *net, my_bool clear_buffer)
{
DBUG_PRINT("info",("skipped %d bytes from file: %s",
count, vio_description(net->vio)));
-#ifdef EXTRA_DEBUG
+#if defined(EXTRA_DEBUG) && (MYSQL_VERSION_ID < 51000)
fprintf(stderr,"Error: net_clear() skipped %d bytes from file: %s\n",
count, vio_description(net->vio));
#endif
@@ -609,7 +612,7 @@ net_real_write(NET *net,const char *packet,ulong len)
thr_alarm(&alarmed,(uint) net->write_timeout,&alarm_buff);
#else
alarmed=0;
- vio_timeout(net->vio, 1, net->write_timeout);
+ /* Write timeout is set in net_set_write_timeout */
#endif /* NO_ALARM */
pos=(char*) packet; end=pos+len;
@@ -802,7 +805,7 @@ my_real_read(NET *net, ulong *complen)
if (net_blocking)
thr_alarm(&alarmed,net->read_timeout,&alarm_buff);
#else
- vio_timeout(net->vio, 0, net->read_timeout);
+ /* Read timeout is set in net_set_read_timeout */
#endif /* NO_ALARM */
pos = net->buff + net->where_b; /* net->packet -4 */
@@ -1113,3 +1116,26 @@ my_net_read(NET *net)
return len;
}
+
+void net_set_read_timeout(NET *net, uint timeout)
+{
+ DBUG_ENTER("net_set_read_timeout");
+ DBUG_PRINT("enter", ("timeout: %d", timeout));
+ net->read_timeout= timeout;
+#ifdef NO_ALARM
+ vio_timeout(net->vio, 0, timeout);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+
+void net_set_write_timeout(NET *net, uint timeout)
+{
+ DBUG_ENTER("net_set_write_timeout");
+ DBUG_PRINT("enter", ("timeout: %d", timeout));
+ net->write_timeout= timeout;
+#ifdef NO_ALARM
+ vio_timeout(net->vio, 1, timeout);
+#endif
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 628b07631c1..3dc780e1b5f 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -219,6 +219,8 @@ public:
}
inline void merge_flags(SEL_ARG *arg) { maybe_flag|=arg->maybe_flag; }
inline void maybe_smaller() { maybe_flag=1; }
+ /* Return true iff it's a single-point null interval */
+ inline bool is_null_interval() { return maybe_null && max_value[0] == 1; }
inline int cmp_min_to_min(SEL_ARG* arg)
{
return sel_cmp(field,min_value, arg->min_value, min_flag, arg->min_flag);
@@ -560,6 +562,7 @@ public:
bool is_ror_scan;
/* Number of ranges in the last checked tree->key */
uint n_ranges;
+ uint8 first_null_comp; /* first null component if any, 0 - otherwise */
};
class TABLE_READ_PLAN;
@@ -606,9 +609,6 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
double read_time);
static
TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree);
-static int get_index_merge_params(PARAM *param, key_map& needed_reg,
- SEL_IMERGE *imerge, double *read_time,
- ha_rows* imerge_rows);
static double get_index_only_read_time(const PARAM* param, ha_rows records,
int keynr);
@@ -618,7 +618,6 @@ static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map,
static void print_ror_scans_arr(TABLE *table, const char *msg,
struct st_ror_scan_info **start,
struct st_ror_scan_info **end);
-static void print_rowid(byte* val, int len);
static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg);
#endif
@@ -930,7 +929,7 @@ QUICK_SELECT_I::QUICK_SELECT_I()
QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
bool no_alloc, MEM_ROOT *parent_alloc)
- :dont_free(0),error(0),free_file(0),in_range(0),cur_range(NULL),range(0)
+ :dont_free(0),error(0),free_file(0),in_range(0),cur_range(NULL),last_range(0)
{
my_bitmap_map *bitmap;
DBUG_ENTER("QUICK_RANGE_SELECT::QUICK_RANGE_SELECT");
@@ -1390,13 +1389,12 @@ int QUICK_ROR_UNION_SELECT::queue_cmp(void *arg, byte *val1, byte *val2)
int QUICK_ROR_UNION_SELECT::reset()
{
- QUICK_SELECT_I* quick;
+ QUICK_SELECT_I *quick;
int error;
DBUG_ENTER("QUICK_ROR_UNION_SELECT::reset");
have_prev_rowid= FALSE;
if (!scans_inited)
{
- QUICK_SELECT_I *quick;
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
while ((quick= it++))
{
@@ -2425,8 +2423,6 @@ static int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar,
static int find_used_partitions_imerge_list(PART_PRUNE_PARAM *ppar,
List<SEL_IMERGE> &merges);
static void mark_all_partitions_as_used(partition_info *part_info);
-static uint32 part_num_to_part_id_range(PART_PRUNE_PARAM* prune_par,
- uint32 num);
#ifndef DBUG_OFF
static void print_partitioning_index(KEY_PART *parts, KEY_PART *parts_end);
@@ -4687,8 +4683,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
param->table->key_info[keynr].name, found_read_time,
read_time));
- if (read_time > found_read_time && found_records != HA_POS_ERROR
- /*|| read_time == DBL_MAX*/ )
+ if (read_time > found_read_time && found_records != HA_POS_ERROR)
{
read_time= found_read_time;
best_records= found_records;
@@ -4928,8 +4923,8 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func,
type. Tree won't be built for values with different result types,
so we check it here to avoid unnecessary work.
*/
- if (!func->array)
- break;
+ if (!func->arg_types_compatible)
+ break;
if (inv)
{
@@ -5600,7 +5595,22 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
err= value->save_in_field_no_warnings(field, 1);
if (err > 0 && field->cmp_type() != value->result_type())
{
- tree= 0;
+ if ((type == Item_func::EQ_FUNC || type == Item_func::EQUAL_FUNC) &&
+ value->result_type() == item_cmp_type(field->result_type(),
+ value->result_type()))
+
+ {
+ tree= new (alloc) SEL_ARG(field, 0, 0);
+ tree->type= SEL_ARG::IMPOSSIBLE;
+ }
+ else
+ {
+ /*
+ TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE
+ for the cases like int_field > 999999999999999999999999 as well.
+ */
+ tree= 0;
+ }
goto end;
}
if (err < 0)
@@ -7016,6 +7026,7 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree, bool update_tbl_stats)
DBUG_ENTER("check_quick_select");
param->is_ror_scan= FALSE;
+ param->first_null_comp= 0;
if (!tree)
DBUG_RETURN(HA_POS_ERROR); // Can't use it
@@ -7116,6 +7127,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
ha_rows records=0, tmp;
uint tmp_min_flag, tmp_max_flag, keynr, min_key_length, max_key_length;
char *tmp_min_key, *tmp_max_key;
+ uint8 save_first_null_comp= param->first_null_comp;
param->max_key_part=max(param->max_key_part,key_tree->part);
if (key_tree->left != &null_element)
@@ -7153,6 +7165,9 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
param->is_ror_scan= FALSE;
}
+ if (!param->first_null_comp && key_tree->is_null_interval())
+ param->first_null_comp= key_tree->part+1;
+
if (key_tree->next_key_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
@@ -7196,7 +7211,8 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
(param->table->key_info[keynr].flags & (HA_NOSAME | HA_END_SPACE_KEY)) ==
HA_NOSAME &&
min_key_length == max_key_length &&
- !memcmp(param->min_key,param->max_key,min_key_length))
+ !memcmp(param->min_key,param->max_key,min_key_length) &&
+ !param->first_null_comp)
{
tmp=1; // Max one record
param->n_ranges++;
@@ -7271,6 +7287,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
return tmp;
records+=tmp;
}
+ param->first_null_comp= save_first_null_comp;
return records;
}
@@ -7988,7 +8005,7 @@ int QUICK_RANGE_SELECT::reset()
byte *mrange_buff;
DBUG_ENTER("QUICK_RANGE_SELECT::reset");
next=0;
- range= NULL;
+ last_range= NULL;
in_range= FALSE;
cur_range= (QUICK_RANGE**) ranges.buffer;
@@ -8122,23 +8139,23 @@ int QUICK_RANGE_SELECT::get_next()
{
start_key= &mrange_slot->start_key;
end_key= &mrange_slot->end_key;
- range= *(cur_range++);
+ last_range= *(cur_range++);
- start_key->key= (const byte*) range->min_key;
- start_key->length= range->min_length;
- start_key->flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
- (range->flag & EQ_RANGE) ?
+ start_key->key= (const byte*) last_range->min_key;
+ start_key->length= last_range->min_length;
+ start_key->flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
+ (last_range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
- end_key->key= (const byte*) range->max_key;
- end_key->length= range->max_length;
+ end_key->key= (const byte*) last_range->max_key;
+ end_key->length= last_range->max_length;
/*
We use HA_READ_AFTER_KEY here because if we are reading on a key
prefix. We want to find all keys with this prefix.
*/
- end_key->flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
+ end_key->flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
HA_READ_AFTER_KEY);
- mrange_slot->range_flag= range->flag;
+ mrange_slot->range_flag= last_range->flag;
}
result= file->read_multi_range_first(&mrange, multi_range, count,
@@ -8194,7 +8211,7 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
{
int result;
key_range start_key, end_key;
- if (range)
+ if (last_range)
{
/* Read the next record in the same range with prefix after cur_prefix. */
DBUG_ASSERT(cur_prefix != 0);
@@ -8208,35 +8225,35 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
if (count == 0)
{
/* Ranges have already been used up before. None is left for read. */
- range= 0;
+ last_range= 0;
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
- range= *(cur_range++);
+ last_range= *(cur_range++);
- start_key.key= (const byte*) range->min_key;
- start_key.length= min(range->min_length, prefix_length);
- start_key.flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
- (range->flag & EQ_RANGE) ?
+ start_key.key= (const byte*) last_range->min_key;
+ start_key.length= min(last_range->min_length, prefix_length);
+ start_key.flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
+ (last_range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
- end_key.key= (const byte*) range->max_key;
- end_key.length= min(range->max_length, prefix_length);
+ end_key.key= (const byte*) last_range->max_key;
+ end_key.length= min(last_range->max_length, prefix_length);
/*
We use READ_AFTER_KEY here because if we are reading on a key
prefix we want to find all keys with this prefix
*/
- end_key.flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
+ end_key.flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
HA_READ_AFTER_KEY);
- result= file->read_range_first(range->min_length ? &start_key : 0,
- range->max_length ? &end_key : 0,
- test(range->flag & EQ_RANGE),
+ result= file->read_range_first(last_range->min_length ? &start_key : 0,
+ last_range->max_length ? &end_key : 0,
+ test(last_range->flag & EQ_RANGE),
sorted);
- if (range->flag == (UNIQUE_RANGE | EQ_RANGE))
- range=0; // Stop searching
+ if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE))
+ last_range= 0; // Stop searching
if (result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
- range=0; // No matching rows; go to next range
+ last_range= 0; // No matching rows; go to next range
}
}
@@ -8250,11 +8267,11 @@ int QUICK_RANGE_SELECT_GEOM::get_next()
for (;;)
{
int result;
- if (range)
+ if (last_range)
{
// Already read through key
- result= file->index_next_same(record, (byte*) range->min_key,
- range->min_length);
+ result= file->index_next_same(record, (byte*) last_range->min_key,
+ last_range->min_length);
if (result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
}
@@ -8263,18 +8280,18 @@ int QUICK_RANGE_SELECT_GEOM::get_next()
if (count == 0)
{
/* Ranges have already been used up before. None is left for read. */
- range= 0;
+ last_range= 0;
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
- range= *(cur_range++);
+ last_range= *(cur_range++);
result= file->index_read(record,
- (byte*) range->min_key,
- range->min_length,
- (ha_rkey_function)(range->flag ^ GEOM_FLAG));
+ (byte*) last_range->min_key,
+ last_range->min_length,
+ (ha_rkey_function)(last_range->flag ^ GEOM_FLAG));
if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
- range=0; // Not found, to next range
+ last_range= 0; // Not found, to next range
}
}
@@ -8299,7 +8316,7 @@ int QUICK_RANGE_SELECT_GEOM::get_next()
bool QUICK_RANGE_SELECT::row_in_ranges()
{
- QUICK_RANGE *range;
+ QUICK_RANGE *res;
uint min= 0;
uint max= ranges.elements - 1;
uint mid= (max + min)/2;
@@ -8315,8 +8332,8 @@ bool QUICK_RANGE_SELECT::row_in_ranges()
max= mid;
mid= (min + max) / 2;
}
- range= *(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid);
- return (!cmp_next(range) && !cmp_prev(range));
+ res= *(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid);
+ return (!cmp_next(res) && !cmp_prev(res));
}
/*
@@ -8330,14 +8347,14 @@ bool QUICK_RANGE_SELECT::row_in_ranges()
*/
QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q,
- uint used_key_parts)
+ uint used_key_parts_arg)
:QUICK_RANGE_SELECT(*q), rev_it(rev_ranges)
{
QUICK_RANGE *r;
QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer;
- QUICK_RANGE **last_range= pr + ranges.elements;
- for (; pr!=last_range; pr++)
+ QUICK_RANGE **end_range= pr + ranges.elements;
+ for (; pr!=end_range; pr++)
rev_ranges.push_front(*pr);
/* Remove EQ_RANGE flag for keys that are not using the full key */
@@ -8371,11 +8388,11 @@ int QUICK_SELECT_DESC::get_next()
for (;;)
{
int result;
- if (range)
+ if (last_range)
{ // Already read through key
- result = ((range->flag & EQ_RANGE)
- ? file->index_next_same(record, (byte*) range->min_key,
- range->min_length) :
+ result = ((last_range->flag & EQ_RANGE)
+ ? file->index_next_same(record, (byte*) last_range->min_key,
+ last_range->min_length) :
file->index_prev(record));
if (!result)
{
@@ -8386,47 +8403,49 @@ int QUICK_SELECT_DESC::get_next()
DBUG_RETURN(result);
}
- if (!(range=rev_it++))
+ if (!(last_range= rev_it++))
DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
- if (range->flag & NO_MAX_RANGE) // Read last record
+ if (last_range->flag & NO_MAX_RANGE) // Read last record
{
int local_error;
if ((local_error=file->index_last(record)))
DBUG_RETURN(local_error); // Empty table
- if (cmp_prev(range) == 0)
+ if (cmp_prev(last_range) == 0)
DBUG_RETURN(0);
- range=0; // No matching records; go to next range
+ last_range= 0; // No match; go to next range
continue;
}
- if (range->flag & EQ_RANGE)
+ if (last_range->flag & EQ_RANGE)
{
- result = file->index_read(record, (byte*) range->max_key,
- range->max_length, HA_READ_KEY_EXACT);
+ result= file->index_read(record, (byte*) last_range->max_key,
+ last_range->max_length, HA_READ_KEY_EXACT);
}
else
{
- DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range));
- result=file->index_read(record, (byte*) range->max_key,
- range->max_length,
- ((range->flag & NEAR_MAX) ?
- HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV));
+ DBUG_ASSERT(last_range->flag & NEAR_MAX ||
+ range_reads_after_key(last_range));
+ result=file->index_read(record, (byte*) last_range->max_key,
+ last_range->max_length,
+ ((last_range->flag & NEAR_MAX) ?
+ HA_READ_BEFORE_KEY :
+ HA_READ_PREFIX_LAST_OR_PREV));
}
if (result)
{
if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
- range=0; // Not found, to next range
+ last_range= 0; // Not found, to next range
continue;
}
- if (cmp_prev(range) == 0)
+ if (cmp_prev(last_range) == 0)
{
- if (range->flag == (UNIQUE_RANGE | EQ_RANGE))
- range = 0; // Stop searching
+ if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE))
+ last_range= 0; // Stop searching
DBUG_RETURN(0); // Found key is in range
}
- range = 0; // To next range
+ last_range= 0; // To next range
}
}
@@ -10154,14 +10173,13 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(void)
DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::reset");
file->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */
- result= file->ha_index_init(index, 1);
- result= file->index_last(record);
- if (result == HA_ERR_END_OF_FILE)
- DBUG_RETURN(0);
- if (result)
+ if ((result= file->ha_index_init(index,1)))
DBUG_RETURN(result);
if (quick_prefix_select && quick_prefix_select->reset())
DBUG_RETURN(1);
+ result= file->index_last(record);
+ if (result == HA_ERR_END_OF_FILE)
+ DBUG_RETURN(0);
/* Save the prefix of the last group. */
key_copy(last_prefix, record, index_info, group_prefix_len);
@@ -10210,7 +10228,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next()
#else
int result;
#endif
- int is_last_prefix;
+ int is_last_prefix= 0;
DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::get_next");
@@ -10225,13 +10243,18 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next()
Check if this is the last group prefix. Notice that at this point
this->record contains the current prefix in record format.
*/
- is_last_prefix= key_cmp(index_info->key_part, last_prefix,
- group_prefix_len);
- DBUG_ASSERT(is_last_prefix <= 0);
- if (result == HA_ERR_KEY_NOT_FOUND)
- continue;
- if (result)
+ if (!result)
+ {
+ is_last_prefix= key_cmp(index_info->key_part, last_prefix,
+ group_prefix_len);
+ DBUG_ASSERT(is_last_prefix <= 0);
+ }
+ else
+ {
+ if (result == HA_ERR_KEY_NOT_FOUND)
+ continue;
break;
+ }
if (have_min)
{
@@ -10918,23 +10941,9 @@ static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg)
}
-static void print_rowid(byte* val, int len)
-{
- byte *pb;
- DBUG_LOCK_FILE;
- fputc('\"', DBUG_FILE);
- for (pb= val; pb!= val + len; ++pb)
- fprintf(DBUG_FILE, "%c", *pb);
- fprintf(DBUG_FILE, "\", hex: ");
-
- for (pb= val; pb!= val + len; ++pb)
- fprintf(DBUG_FILE, "%x ", *pb);
- fputc('\n', DBUG_FILE);
- DBUG_UNLOCK_FILE;
-}
-
void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose)
{
+ /* purecov: begin inspected */
fprintf(DBUG_FILE, "%*squick range select, key %s, length: %d\n",
indent, "", head->key_info[index].name, max_used_key_length);
@@ -10942,8 +10951,8 @@ void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose)
{
QUICK_RANGE *range;
QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer;
- QUICK_RANGE **last_range= pr + ranges.elements;
- for (; pr!=last_range; ++pr)
+ QUICK_RANGE **end_range= pr + ranges.elements;
+ for (; pr != end_range; ++pr)
{
fprintf(DBUG_FILE, "%*s", indent + 2, "");
range= *pr;
@@ -10968,6 +10977,7 @@ void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose)
fputs("\n",DBUG_FILE);
}
}
+ /* purecov: end */
}
void QUICK_INDEX_MERGE_SELECT::dbug_dump(int indent, bool verbose)
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 525a0adcff7..d82e1dc459e 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -301,7 +301,7 @@ protected:
DYNAMIC_ARRAY ranges; /* ordered array of range ptrs */
QUICK_RANGE **cur_range; /* current element in ranges */
- QUICK_RANGE *range;
+ QUICK_RANGE *last_range;
KEY_PART *key_parts;
KEY_PART_INFO *key_part_info;
int cmp_next(QUICK_RANGE *range);
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 90a3ff66a22..5bd5ec4b42d 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -97,9 +97,9 @@ static ulonglong get_exact_record_count(TABLE_LIST *tables)
GROUP BY part.
RETURN VALUES
- 0 No errors
- 1 if all items were resolved
- -1 on impossible conditions
+ 0 no errors
+ 1 if all items were resolved
+ HA_ERR_KEY_NOT_FOUND on impossible conditions
OR an error number from my_base.h HA_ERR_... if a deadlock or a lock
wait timeout happens, for example
*/
@@ -267,7 +267,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if (error)
{
if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE)
- return -1; // No rows matching WHERE
+ return HA_ERR_KEY_NOT_FOUND; // No rows matching WHERE
/* HA_ERR_LOCK_DEADLOCK or some other error */
table->file->print_error(error, MYF(0));
return(error);
@@ -354,7 +354,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if (error)
{
if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE)
- return -1; // No rows matching WHERE
+ return HA_ERR_KEY_NOT_FOUND; // No rows matching WHERE
/* HA_ERR_LOCK_DEADLOCK or some other error */
table->file->print_error(error, MYF(0));
return(error);
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index c36e16e0553..f5b62e3afe2 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -228,7 +228,7 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
if (dir)
{
- fn_format(path, file_name->str, dir->str, 0, MY_UNPACK_FILENAME);
+ fn_format(path, file_name->str, dir->str, "", MY_UNPACK_FILENAME);
path_end= strlen(path);
}
else
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 76630e8530b..a7f9bd413c6 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -920,7 +920,6 @@ bool partition_info::set_up_charset_field_preps()
if (field_is_partition_charset(field))
{
char *field_buf;
- CHARSET_INFO *cs= ((Field_str*)field)->charset();
size= field->pack_length();
if (!(field_buf= sql_calloc(size)))
goto error;
diff --git a/sql/password.c b/sql/password.c
index 0e4bd6347e2..1ff67888ea4 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -472,7 +472,7 @@ scramble(char *to, const char *message, const char *password)
*/
my_bool
-check_scramble(const char *scramble, const char *message,
+check_scramble(const char *scramble_arg, const char *message,
const uint8 *hash_stage2)
{
SHA1_CONTEXT sha1_context;
@@ -485,7 +485,7 @@ check_scramble(const char *scramble, const char *message,
mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
mysql_sha1_result(&sha1_context, buf);
/* encrypt scramble */
- my_crypt((char *) buf, buf, (const uchar *) scramble, SCRAMBLE_LENGTH);
+ my_crypt((char *) buf, buf, (const uchar *) scramble_arg, SCRAMBLE_LENGTH);
/* now buf supposedly contains hash_stage1: so we can get hash_stage2 */
mysql_sha1_reset(&sha1_context);
mysql_sha1_input(&sha1_context, buf, SHA1_HASH_SIZE);
@@ -495,7 +495,8 @@ check_scramble(const char *scramble, const char *message,
/*
- Convert scrambled password from asciiz hex string to binary form.
+ Convert scrambled password from asciiz hex string to binary form.
+
SYNOPSIS
get_salt_from_password()
res OUT buf to hold password. Must be at least SHA1_HASH_SIZE
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 9d313680582..bc94eb238fd 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -27,8 +27,10 @@
#include <stdarg.h>
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
-static void write_eof_packet(THD *thd, NET *net);
void net_send_error_packet(THD *thd, uint sql_errno, const char *err);
+#ifndef EMBEDDED_LIBRARY
+static void write_eof_packet(THD *thd, NET *net);
+#endif
#ifndef EMBEDDED_LIBRARY
bool Protocol::net_store_data(const char *from, uint length)
@@ -935,15 +937,15 @@ bool Protocol_text::store(Field *field)
char buff[MAX_FIELD_WIDTH];
String str(buff,sizeof(buff), &my_charset_bin);
CHARSET_INFO *tocs= this->thd->variables.character_set_results;
+#ifndef DBUG_OFF
TABLE *table= field->table;
-#ifdef DBUG_OFF
my_bitmap_map *old_map= 0;
if (table->file)
old_map= dbug_tmp_use_all_columns(table, table->read_set);
#endif
field->val_str(&str);
-#ifdef DBUG_OFF
+#ifndef DBUG_OFF
if (old_map)
dbug_tmp_restore_column_map(table->read_set, old_map);
#endif
diff --git a/sql/protocol.h b/sql/protocol.h
index b75ce38dc37..731caeb1a4c 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -58,6 +58,8 @@ public:
String *storage_packet() { return packet; }
inline void free() { packet->free(); }
virtual bool write();
+ inline bool store(int from)
+ { return store_long((longlong) from); }
inline bool store(uint32 from)
{ return store_long((longlong) from); }
inline bool store(longlong from)
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 48bc0f0f5b8..934a6821514 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -57,6 +57,7 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
functions like register_slave()) are working.
*/
+#if NOT_USED
static int init_failsafe_rpl_thread(THD* thd)
{
DBUG_ENTER("init_failsafe_rpl_thread");
@@ -72,23 +73,19 @@ static int init_failsafe_rpl_thread(THD* thd)
thd->net.read_timeout = slave_net_timeout;
thd->max_client_packet_length=thd->net.max_packet;
pthread_mutex_lock(&LOCK_thread_count);
- thd->thread_id = thread_id++;
+ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
pthread_mutex_unlock(&LOCK_thread_count);
if (init_thr_lock() || thd->store_globals())
{
+ /* purecov: begin inspected */
close_connection(thd, ER_OUT_OF_RESOURCES, 1); // is this needed?
statistic_increment(aborted_connects,&LOCK_status);
- end_thread(thd,0);
+ one_thread_per_connection_end(thd,0);
DBUG_RETURN(-1);
+ /* purecov: end */
}
-#if !defined(__WIN__) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
-
thd->mem_root->free= thd->mem_root->used= 0;
if (thd->variables.max_join_size == HA_POS_ERROR)
thd->options|= OPTION_BIG_SELECTS;
@@ -98,7 +95,7 @@ static int init_failsafe_rpl_thread(THD* thd)
thd->set_time();
DBUG_RETURN(0);
}
-
+#endif
void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status)
{
@@ -529,11 +526,11 @@ HOSTS";
while ((row= mysql_fetch_row(res)))
{
- uint32 server_id;
+ uint32 log_server_id;
SLAVE_INFO* si, *old_si;
- server_id = atoi(row[0]);
+ log_server_id = atoi(row[0]);
if ((old_si= (SLAVE_INFO*)hash_search(&slave_list,
- (byte*)&server_id,4)))
+ (byte*)&log_server_id,4)))
si = old_si;
else
{
@@ -543,7 +540,7 @@ HOSTS";
pthread_mutex_unlock(&LOCK_slave_list);
goto err;
}
- si->server_id = server_id;
+ si->server_id = log_server_id;
my_hash_insert(&slave_list, (byte*)si);
}
strmake(si->host, row[1], sizeof(si->host)-1);
@@ -572,12 +569,14 @@ err:
}
+#if NOT_USED
int find_recovery_captain(THD* thd, MYSQL* mysql)
{
return 0;
}
+#endif
-
+#if NOT_USED
pthread_handler_t handle_failsafe_rpl(void *arg)
{
DBUG_ENTER("handle_failsafe_rpl");
@@ -625,7 +624,7 @@ err:
pthread_exit(0);
DBUG_RETURN(0);
}
-
+#endif
bool show_slave_hosts(THD* thd)
{
@@ -915,14 +914,14 @@ bool load_master_data(THD* thd)
setting active_mi, because init_master_info() sets active_mi with
defaults.
*/
- int error;
+ int error_2;
if (init_master_info(active_mi, master_info_file, relay_log_info_file,
0, (SLAVE_IO | SLAVE_SQL)))
my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0));
strmake(active_mi->master_log_name, row[0],
sizeof(active_mi->master_log_name));
- active_mi->master_log_pos= my_strtoll10(row[1], (char**) 0, &error);
+ active_mi->master_log_pos= my_strtoll10(row[1], (char**) 0, &error_2);
/* at least in recent versions, the condition below should be false */
if (active_mi->master_log_pos < BIN_LOG_HEADER_SIZE)
active_mi->master_log_pos = BIN_LOG_HEADER_SIZE;
diff --git a/sql/rpl_injector.h b/sql/rpl_injector.h
index 8b08c0672c9..61c2e0ecebc 100644
--- a/sql/rpl_injector.h
+++ b/sql/rpl_injector.h
@@ -284,12 +284,14 @@ public:
*/
int check_state(enum_state const target_state)
{
+#ifndef DBUG_OFF
static char const *state_name[] = {
"START_STATE", "TABLE_STATE", "ROW_STATE", "STATE_COUNT"
};
DBUG_ASSERT(0 <= target_state && target_state <= STATE_COUNT);
DBUG_PRINT("info", ("In state %s", state_name[m_state]));
+#endif
if (m_state <= target_state && target_state <= m_state + 1 &&
m_state < STATE_COUNT)
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 6a7b22bf23d..8a051195dba 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -18,6 +18,7 @@
#include "rpl_rli.h"
#include <my_dir.h> // For MY_STAT
#include "sql_repl.h" // For check_binlog_magic
+#include "rpl_utility.h"
static int count_relay_log_space(RELAY_LOG_INFO* rli);
@@ -1108,4 +1109,23 @@ void st_relay_log_info::cleanup_context(THD *thd, bool error)
unsafe_to_stop_at= 0;
DBUG_VOID_RETURN;
}
+
+void st_relay_log_info::clear_tables_to_lock()
+{
+ while (tables_to_lock)
+ {
+ gptr to_free= reinterpret_cast<gptr>(tables_to_lock);
+ if (tables_to_lock->m_tabledef_valid)
+ {
+ tables_to_lock->m_tabledef.table_def::~table_def();
+ tables_to_lock->m_tabledef_valid= FALSE;
+ }
+ tables_to_lock=
+ static_cast<RPL_TABLE_LIST*>(tables_to_lock->next_global);
+ tables_to_lock_count--;
+ my_free(to_free, MYF(MY_WME));
+ }
+ DBUG_ASSERT(tables_to_lock == NULL && tables_to_lock_count == 0);
+}
+
#endif
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index cb9894a2125..45c9fb1cf96 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -20,6 +20,8 @@
#include "rpl_tblmap.h"
+struct RPL_TABLE_LIST;
+
/****************************************************************************
@@ -279,7 +281,7 @@ typedef struct st_relay_log_info
group_relay_log_pos);
}
- TABLE_LIST *tables_to_lock; /* RBR: Tables to lock */
+ RPL_TABLE_LIST *tables_to_lock; /* RBR: Tables to lock */
uint tables_to_lock_count; /* RBR: Count of tables to lock */
table_mapping m_table_map; /* RBR: Mapping table-id to table */
@@ -295,16 +297,7 @@ typedef struct st_relay_log_info
void transaction_end(THD*);
void cleanup_context(THD *, bool);
- void clear_tables_to_lock() {
- while (tables_to_lock)
- {
- char *to_free= reinterpret_cast<gptr>(tables_to_lock);
- tables_to_lock= tables_to_lock->next_global;
- tables_to_lock_count--;
- my_free(to_free, MYF(MY_WME));
- }
- DBUG_ASSERT(tables_to_lock == NULL && tables_to_lock_count == 0);
- }
+ void clear_tables_to_lock();
time_t unsafe_to_stop_at;
} RELAY_LOG_INFO;
diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h
index 34cebf93ddb..b1aa642619c 100644
--- a/sql/rpl_utility.h
+++ b/sql/rpl_utility.h
@@ -22,98 +22,100 @@
#include "mysql_priv.h"
+struct st_relay_log_info;
+typedef st_relay_log_info RELAY_LOG_INFO;
+
uint32
-field_length_from_packed(enum_field_types const field_type,
- byte const *const data);
+field_length_from_packed(enum_field_types field_type, byte const *data);
-/*
+/**
A table definition from the master.
- RESPONSIBILITIES
-
+ The responsibilities of this class is:
- Extract and decode table definition data from the table map event
- Check if table definition in table map is compatible with table
definition on slave
- DESCRIPTION
-
- Currently, the only field type data available is an array of the
- type operators that are present in the table map event.
+ Currently, the only field type data available is an array of the
+ type operators that are present in the table map event.
- TODO
-
- Add type operands to this structure to allow detection of
- difference between, e.g., BIT(5) and BIT(10).
+ @todo Add type operands to this structure to allow detection of
+ difference between, e.g., BIT(5) and BIT(10).
*/
class table_def
{
public:
- /*
+ /**
Convenience declaration of the type of the field type data in a
table map event.
*/
typedef unsigned char field_type;
- /*
+ /**
Constructor.
- SYNOPSIS
- table_def()
- types Array of types
- size Number of elements in array 'types'
+ @param types Array of types
+ @param size Number of elements in array 'types'
*/
table_def(field_type *types, my_size_t size)
- : m_type(types), m_size(size)
+ : m_type(new unsigned char [size]), m_size(size)
{
+ if (m_type)
+ memcpy(m_type, types, size);
+ else
+ m_size= 0;
}
- /*
- Return the number of fields there is type data for.
+ ~table_def() {
+ if (m_type)
+ delete [] m_type;
+#ifndef DBUG_OFF
+ m_type= 0;
+ m_size= 0;
+#endif
+ }
- SYNOPSIS
- size()
+ /**
+ Return the number of fields there is type data for.
- RETURN VALUE
- The number of fields that there is type data for.
+ @return The number of fields that there is type data for.
*/
my_size_t size() const { return m_size; }
+
/*
Return a representation of the type data for one field.
- SYNOPSIS
- type()
- i Field index to return data for
+ @param index Field index to return data for
- RETURN VALUE
-
- Will return a representation of the type data for field
- 'i'. Currently, only the type identifier is returned.
+ @return Will return a representation of the type data for field
+ <code>index</code>. Currently, only the type identifier is
+ returned.
*/
- field_type type(my_ptrdiff_t i) const { return m_type[i]; }
+ field_type type(my_ptrdiff_t index) const
+ {
+ DBUG_ASSERT(0 <= index);
+ DBUG_ASSERT(static_cast<my_size_t>(index) < m_size);
+ return m_type[index];
+ }
- /*
+ /**
Decide if the table definition is compatible with a table.
- SYNOPSIS
- compatible_with()
- rli Pointer to relay log info
- table Pointer to table to compare with.
-
- DESCRIPTION
-
- Compare the definition with a table to see if it is compatible
- with it. A table definition is compatible with a table if:
+ Compare the definition with a table to see if it is compatible
+ with it.
+ A table definition is compatible with a table if:
- the columns types of the table definition is a (not
necessarily proper) prefix of the column type of the table, or
-
- the other way around
- RETURN VALUE
- 1 if the table definition is not compatible with 'table'
- 0 if the table definition is compatible with 'table'
+ @param rli Pointer to relay log info
+ @param table Pointer to table to compare with.
+
+ @retval 1 if the table definition is not compatible with @c table
+ @retval 0 if the table definition is compatible with @c table
*/
int compatible_with(RELAY_LOG_INFO *rli, TABLE *table) const;
@@ -122,4 +124,15 @@ private:
field_type *m_type; // Array of type descriptors
};
+/**
+ Extend the normal table list with a few new fields needed by the
+ slave thread, but nowhere else.
+ */
+struct RPL_TABLE_LIST
+ : public st_table_list
+{
+ bool m_tabledef_valid;
+ table_def m_tabledef;
+};
+
#endif /* RPL_UTILITY_H */
diff --git a/sql/scheduler.cc b/sql/scheduler.cc
new file mode 100644
index 00000000000..b05bdf4756f
--- /dev/null
+++ b/sql/scheduler.cc
@@ -0,0 +1,88 @@
+/* Copyright (C) 2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Implementation for the thread scheduler
+*/
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma implementation
+#endif
+
+#include <mysql_priv.h>
+
+/*
+ 'Dummy' functions to be used when we don't need any handling for a scheduler
+ event
+ */
+
+static bool init_dummy(void) {return 0;}
+static void post_kill_dummy(THD* thd) {}
+static void end_dummy(void) {}
+static bool end_thread_dummy(THD *thd, bool cache_thread) { return 0; }
+
+/*
+ Initialize default scheduler with dummy functions so that setup functions
+ only need to declare those that are relvant for their usage
+*/
+
+scheduler_functions::scheduler_functions()
+ :init(init_dummy),
+ init_new_connection_thread(init_new_connection_handler_thread),
+ add_connection(0), // Must be defined
+ post_kill_notification(post_kill_dummy),
+ end_thread(end_thread_dummy), end(end_dummy)
+{}
+
+
+/*
+ End connection, in case when we are using 'no-threads'
+*/
+
+static bool no_threads_end(THD *thd, bool put_in_cache)
+{
+ unlink_thd(thd);
+ pthread_mutex_unlock(&LOCK_thread_count);
+ return 1; // Abort handle_one_connection
+}
+
+
+/*
+ Initailize scheduler for --thread-handling=no-threads
+*/
+
+void one_thread_scheduler(scheduler_functions* func)
+{
+ func->max_threads= 1;
+#ifndef EMBEDDED_LIBRARY
+ func->add_connection= handle_connection_in_main_thread;
+#endif
+ func->init_new_connection_thread= init_dummy;
+ func->end_thread= no_threads_end;
+}
+
+
+/*
+ Initialize scheduler for --thread-handling=one-thread-per-connection
+*/
+
+#ifndef EMBEDDED_LIBRARY
+void one_thread_per_connection_scheduler(scheduler_functions* func)
+{
+ func->max_threads= max_connections;
+ func->add_connection= create_thread_to_handle_connection;
+ func->end_thread= one_thread_per_connection_end;
+}
+#endif /* EMBEDDED_LIBRARY */
diff --git a/sql/scheduler.h b/sql/scheduler.h
new file mode 100644
index 00000000000..8351cefda4c
--- /dev/null
+++ b/sql/scheduler.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Classes for the thread scheduler
+*/
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface
+#endif
+
+class THD;
+
+/* Functions used when manipulating threads */
+
+class scheduler_functions
+{
+public:
+ uint max_threads;
+ bool (*init)(void);
+ bool (*init_new_connection_thread)(void);
+ void (*add_connection)(THD *thd);
+ void (*post_kill_notification)(THD *thd);
+ bool (*end_thread)(THD *thd, bool cache_thread);
+ void (*end)(void);
+ scheduler_functions();
+};
+
+enum scheduler_types
+{
+ SCHEDULER_ONE_THREAD_PER_CONNECTION=1,
+ SCHEDULER_NO_THREADS,
+ SCHEDULER_POOL_OF_THREADS
+};
+
+void one_thread_per_connection_scheduler(scheduler_functions* func);
+void one_thread_scheduler(scheduler_functions* func);
+
+enum pool_command_op
+{
+ NOT_IN_USE_OP= 0, NORMAL_OP= 1, CONNECT_OP, KILL_OP, DIE_OP
+};
+
+#define HAVE_POOL_OF_THREADS 0 /* For easyer tests */
+#define pool_of_threads_scheduler(A) one_thread_per_connection_scheduler(A)
+
+class thd_scheduler
+{};
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 55a3970b54e..a5f01cc92dd 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -116,9 +116,6 @@ TYPELIB delay_key_write_typelib=
delay_key_write_type_names, NULL
};
-static int sys_check_charset(THD *thd, set_var *var);
-static bool sys_update_charset(THD *thd, set_var *var);
-static void sys_set_default_charset(THD *thd, enum_var_type type);
static int sys_check_ftb_syntax(THD *thd, set_var *var);
static bool sys_update_ftb_syntax(THD *thd, set_var * var);
static void sys_default_ftb_syntax(THD *thd, enum_var_type type);
@@ -399,6 +396,10 @@ sys_var_thd_ulong sys_trans_alloc_block_size("transaction_alloc_block_size",
sys_var_thd_ulong sys_trans_prealloc_size("transaction_prealloc_size",
&SV::trans_prealloc_size,
0, fix_trans_mem_root);
+sys_var_thd_enum sys_thread_handling("thread_handling",
+ &SV::thread_handling,
+ &thread_handling_typelib,
+ NULL);
#ifdef HAVE_QUERY_CACHE
sys_var_long_ptr sys_query_cache_limit("query_cache_limit",
@@ -467,6 +468,10 @@ sys_var_long_ptr sys_table_lock_wait_timeout("table_lock_wait_timeout",
&table_lock_wait_timeout);
sys_var_long_ptr sys_thread_cache_size("thread_cache_size",
&thread_cache_size);
+#if HAVE_POOL_OF_THREADS == 1
+sys_var_long_ptr sys_thread_pool_size("thread_pool_size",
+ &thread_pool_size);
+#endif
sys_var_thd_enum sys_tx_isolation("tx_isolation",
&SV::tx_isolation,
&tx_isolation_typelib,
@@ -1010,6 +1015,10 @@ SHOW_VAR init_vars[]= {
#ifdef HAVE_THR_SETCONCURRENCY
{"thread_concurrency", (char*) &concurrency, SHOW_LONG},
#endif
+ {sys_thread_handling.name, (char*) &sys_thread_handling, SHOW_SYS},
+#if HAVE_POOL_OF_THREADS == 1
+ {sys_thread_pool_size.name, (char*) &sys_thread_pool_size, SHOW_SYS},
+#endif
{"thread_stack", (char*) &thread_stack, SHOW_LONG},
{sys_time_format.name, (char*) &sys_time_format, SHOW_SYS},
{"time_zone", (char*) &sys_time_zone, SHOW_SYS},
@@ -1221,14 +1230,14 @@ static int check_completion_type(THD *thd, set_var *var)
static void fix_net_read_timeout(THD *thd, enum_var_type type)
{
if (type != OPT_GLOBAL)
- thd->net.read_timeout=thd->variables.net_read_timeout;
+ net_set_read_timeout(&thd->net, thd->variables.net_read_timeout);
}
static void fix_net_write_timeout(THD *thd, enum_var_type type)
{
if (type != OPT_GLOBAL)
- thd->net.write_timeout=thd->variables.net_write_timeout;
+ net_set_write_timeout(&thd->net, thd->variables.net_write_timeout);
}
static void fix_net_retry_count(THD *thd, enum_var_type type)
@@ -1414,9 +1423,9 @@ static void fix_server_id(THD *thd, enum_var_type type)
sys_var_long_ptr::
-sys_var_long_ptr(const char *name_arg, ulong *value_ptr,
+sys_var_long_ptr(const char *name_arg, ulong *value_ptr_arg,
sys_after_update_func after_update_arg)
- :sys_var_long_ptr_global(name_arg, value_ptr,
+ :sys_var_long_ptr_global(name_arg, value_ptr_arg,
&LOCK_global_system_variables, after_update_arg)
{}
@@ -1766,7 +1775,7 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
/* As there was no local variable, return the global value */
var_type= OPT_GLOBAL;
}
- switch (type()) {
+ switch (show_type()) {
case SHOW_INT:
{
uint value;
@@ -2590,7 +2599,7 @@ bool update_sys_var_str_path(THD *thd, sys_var_str *var_str,
file_log= logger.get_log_file_handler();
break;
default:
- DBUG_ASSERT(0);
+ assert(0); // Impossible
}
if (!old_value)
@@ -2617,7 +2626,7 @@ bool update_sys_var_str_path(THD *thd, sys_var_str *var_str,
{
switch (log_type) {
case QUERY_LOG_SLOW:
- file_log->open_slow_log(sys_var_general_log_path.value);
+ file_log->open_slow_log(sys_var_slow_log_path.value);
break;
case QUERY_LOG_GENERAL:
file_log->open_query_log(sys_var_general_log_path.value);
@@ -3629,7 +3638,7 @@ bool sys_var_thd_table_type::update(THD *thd, set_var *var)
*/
byte *sys_var_thd_sql_mode::symbolic_mode_representation(THD *thd,
- ulong val,
+ ulonglong val,
ulong *len)
{
char buff[256];
@@ -3999,15 +4008,13 @@ sys_var_event_scheduler::update(THD *thd, set_var *var)
DBUG_PRINT("info", ("new_value: %d", (int) var->save_result.ulong_value));
- Item_result var_type= var->value->result_type();
-
if (var->save_result.ulong_value == Events::EVENTS_ON)
res= Events::get_instance()->start_execution_of_events();
else if (var->save_result.ulong_value == Events::EVENTS_OFF)
res= Events::get_instance()->stop_execution_of_events();
else
{
- DBUG_ASSERT(0);
+ assert(0); // Impossible
}
if (res)
my_error(ER_EVENT_SET_VAR_ERROR, MYF(0));
diff --git a/sql/set_var.h b/sql/set_var.h
index b0e9c8fd335..8887d91ec69 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -64,8 +64,8 @@ public:
bool check_enum(THD *thd, set_var *var, TYPELIB *enum_names);
bool check_set(THD *thd, set_var *var, TYPELIB *enum_names);
virtual bool update(THD *thd, set_var *var)=0;
- virtual void set_default(THD *thd, enum_var_type type) {}
- virtual SHOW_TYPE type() { return SHOW_UNDEF; }
+ virtual void set_default(THD *thd_arg, enum_var_type type) {}
+ virtual SHOW_TYPE show_type() { return SHOW_UNDEF; }
virtual byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{ return 0; }
virtual bool check_type(enum_var_type type)
@@ -105,14 +105,16 @@ class sys_var_long_ptr_global: public sys_var_global
{
public:
ulong *value;
- sys_var_long_ptr_global(const char *name_arg, ulong *value_ptr,
+ sys_var_long_ptr_global(const char *name_arg, ulong *value_ptr_arg,
pthread_mutex_t *guard_arg,
sys_after_update_func after_update_arg= NULL)
- :sys_var_global(name_arg, after_update_arg, guard_arg), value(value_ptr) {}
+ :sys_var_global(name_arg, after_update_arg, guard_arg),
+ value(value_ptr_arg)
+ {}
bool check(THD *thd, set_var *var);
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_LONG; }
+ SHOW_TYPE show_type() { return SHOW_LONG; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{ return (byte*) value; }
};
@@ -134,14 +136,14 @@ class sys_var_ulonglong_ptr :public sys_var
{
public:
ulonglong *value;
- sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr)
- :sys_var(name_arg),value(value_ptr) {}
- sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr,
+ sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr_arg)
+ :sys_var(name_arg),value(value_ptr_arg) {}
+ sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr_arg,
sys_after_update_func func)
- :sys_var(name_arg,func), value(value_ptr) {}
+ :sys_var(name_arg,func), value(value_ptr_arg) {}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_LONGLONG; }
+ SHOW_TYPE show_type() { return SHOW_LONGLONG; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{ return (byte*) value; }
};
@@ -160,7 +162,7 @@ public:
}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_MY_BOOL; }
+ SHOW_TYPE show_type() { return SHOW_MY_BOOL; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{ return (byte*) value; }
bool check_update_type(Item_result type) { return 0; }
@@ -192,7 +194,7 @@ public:
{
(*set_default_func)(thd, type);
}
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{ return (byte*) value; }
bool check_update_type(Item_result type)
@@ -218,7 +220,7 @@ public:
{
return 1;
}
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{
return (byte*) value;
@@ -247,7 +249,7 @@ public:
{
return 1;
}
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{
return (byte*) *value;
@@ -275,7 +277,7 @@ public:
return check_enum(thd, var, enum_names);
}
bool update(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
bool check_update_type(Item_result type) { return 0; }
};
@@ -310,7 +312,7 @@ public:
bool check(THD *thd, set_var *var);
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_LONG; }
+ SHOW_TYPE show_type() { return SHOW_LONG; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
@@ -328,7 +330,7 @@ public:
{}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_HA_ROWS; }
+ SHOW_TYPE show_type() { return SHOW_HA_ROWS; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
@@ -348,7 +350,7 @@ public:
{}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_LONGLONG; }
+ SHOW_TYPE show_type() { return SHOW_LONGLONG; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
bool check_default(enum_var_type type)
{
@@ -374,7 +376,7 @@ public:
{}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_MY_BOOL; }
+ SHOW_TYPE show_type() { return SHOW_MY_BOOL; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
bool check(THD *thd, set_var *var)
{
@@ -417,7 +419,7 @@ public:
}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
bool check_update_type(Item_result type) { return 0; }
};
@@ -438,7 +440,7 @@ public:
}
void set_default(THD *thd, enum_var_type type);
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- static byte *symbolic_mode_representation(THD *thd, ulong sql_mode,
+ static byte *symbolic_mode_representation(THD *thd, ulonglong sql_mode,
ulong *length);
};
@@ -452,7 +454,7 @@ public:
:sys_var_thd(name_arg), offset(offset_arg)
{}
bool check(THD *thd, set_var *var);
-SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return type != STRING_RESULT; /* Only accept strings */
@@ -478,11 +480,11 @@ class sys_var_thd_bit :public sys_var_thd
sys_check_func check_func;
sys_update_func update_func;
public:
- ulong bit_flag;
+ ulonglong bit_flag;
bool reverse;
sys_var_thd_bit(const char *name_arg,
sys_check_func c_func, sys_update_func u_func,
- ulong bit, bool reverse_arg=0)
+ ulonglong bit, bool reverse_arg=0)
:sys_var_thd(name_arg), check_func(c_func), update_func(u_func),
bit_flag(bit), reverse(reverse_arg)
{}
@@ -490,7 +492,7 @@ public:
bool update(THD *thd, set_var *var);
bool check_update_type(Item_result type) { return 0; }
bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
- SHOW_TYPE type() { return SHOW_MY_BOOL; }
+ SHOW_TYPE show_type() { return SHOW_MY_BOOL; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
@@ -500,7 +502,7 @@ public:
sys_var_thd_dbug(const char *name_arg) :sys_var_thd(name_arg) {}
bool check_update_type(Item_result type) { return type != STRING_RESULT; }
bool check(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type) { DBUG_POP(); }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *b);
@@ -518,7 +520,7 @@ public:
void set_default(THD *thd, enum_var_type type);
bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
bool check_default(enum_var_type type) { return 0; }
- SHOW_TYPE type() { return SHOW_LONG; }
+ SHOW_TYPE show_type() { return SHOW_LONG; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
@@ -529,7 +531,7 @@ public:
sys_var_last_insert_id(const char *name_arg) :sys_var(name_arg) {}
bool update(THD *thd, set_var *var);
bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
- SHOW_TYPE type() { return SHOW_LONGLONG; }
+ SHOW_TYPE show_type() { return SHOW_LONGLONG; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
@@ -540,7 +542,7 @@ public:
sys_var_insert_id(const char *name_arg) :sys_var(name_arg) {}
bool update(THD *thd, set_var *var);
bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
- SHOW_TYPE type() { return SHOW_LONGLONG; }
+ SHOW_TYPE show_type() { return SHOW_LONGLONG; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
@@ -555,15 +557,15 @@ public:
bool check_type(enum_var_type type) { return type != OPT_GLOBAL; }
/*
We can't retrieve the value of this, so we don't have to define
- type() or value_ptr()
+ show_type() or value_ptr()
*/
};
class sys_var_sync_binlog_period :public sys_var_long_ptr
{
public:
- sys_var_sync_binlog_period(const char *name_arg, ulong *value_ptr)
- :sys_var_long_ptr(name_arg,value_ptr) {}
+ sys_var_sync_binlog_period(const char *name_arg, ulong *value_ptr_arg)
+ :sys_var_long_ptr(name_arg,value_ptr_arg) {}
bool update(THD *thd, set_var *var);
};
#endif
@@ -593,7 +595,7 @@ public:
no_support_one_shot= 0;
}
bool check(THD *thd, set_var *var);
-SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return ((type != STRING_RESULT) && (type != INT_RESULT));
@@ -617,7 +619,7 @@ public:
no_support_one_shot= 0;
}
bool check(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return ((type != STRING_RESULT) && (type != INT_RESULT));
@@ -733,7 +735,7 @@ public:
:sys_var_key_cache_param(name_arg, offsetof(KEY_CACHE, param_buff_size))
{}
bool update(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_LONGLONG; }
+ SHOW_TYPE show_type() { return SHOW_LONGLONG; }
};
@@ -744,7 +746,7 @@ public:
:sys_var_key_cache_param(name_arg, offset_arg)
{}
bool update(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_LONG; }
+ SHOW_TYPE show_type() { return SHOW_LONG; }
};
@@ -759,7 +761,7 @@ public:
:sys_var_thd(name_arg), offset(offset_arg),
date_time_type(date_time_type_arg)
{}
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return type != STRING_RESULT; /* Only accept strings */
@@ -801,7 +803,7 @@ public:
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
bool check_update_type(Item_result type) { return 0; }
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
};
@@ -811,13 +813,13 @@ class sys_var_readonly: public sys_var
{
public:
enum_var_type var_type;
- SHOW_TYPE show_type;
+ SHOW_TYPE show_type_value;
sys_value_ptr_func value_ptr_func;
sys_var_readonly(const char *name_arg, enum_var_type type,
SHOW_TYPE show_type_arg,
sys_value_ptr_func value_ptr_func_arg)
:sys_var(name_arg), var_type(type),
- show_type(show_type_arg), value_ptr_func(value_ptr_func_arg)
+ show_type_value(show_type_arg), value_ptr_func(value_ptr_func_arg)
{}
bool update(THD *thd, set_var *var) { return 1; }
bool check_default(enum_var_type type) { return 1; }
@@ -827,7 +829,7 @@ public:
{
return (*value_ptr_func)(thd);
}
- SHOW_TYPE type() { return show_type; }
+ SHOW_TYPE show_type() { return show_type_value; }
bool is_readonly() const { return 1; }
};
@@ -850,7 +852,7 @@ public:
bool check_default(enum_var_type type) { return 1; }
bool check_type(enum_var_type type) { return type != OPT_GLOBAL; }
bool check_update_type(Item_result type) { return 1; }
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool is_readonly() const { return 1; }
};
@@ -864,7 +866,7 @@ public:
no_support_one_shot= 0;
}
bool check(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return type != STRING_RESULT; /* Only accept strings */
@@ -888,7 +890,7 @@ public:
return type != OPT_GLOBAL || !option_limits;
}
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_INT; }
+ SHOW_TYPE show_type() { return SHOW_INT; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
@@ -929,7 +931,7 @@ public:
#endif
}
bool check(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return ((type != STRING_RESULT) && (type != INT_RESULT));
@@ -949,7 +951,7 @@ public:
sys_var_long_ptr(name_arg, NULL, NULL) {};
bool update(THD *thd, set_var *var);
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check(THD *thd, set_var *var);
bool check_update_type(Item_result type)
{
@@ -1008,8 +1010,8 @@ public:
} save_result;
LEX_STRING base; /* for structs */
- set_var(enum_var_type type_arg, sys_var *var_arg, const LEX_STRING *base_name_arg,
- Item *value_arg)
+ set_var(enum_var_type type_arg, sys_var *var_arg,
+ const LEX_STRING *base_name_arg, Item *value_arg)
:var(var_arg), type(type_arg), base(*base_name_arg)
{
/*
diff --git a/sql/slave.cc b/sql/slave.cc
index c21aec49e88..6f62f74647a 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -53,6 +53,7 @@ ulonglong relay_log_space_limit = 0;
*/
int disconnect_slave_event_count = 0, abort_slave_event_count = 0;
+int events_till_abort = -1;
typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL} SLAVE_THD_TYPE;
@@ -73,6 +74,7 @@ static int request_table_dump(MYSQL* mysql, const char* db, const char* table);
static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
const char* table_name, bool overwrite);
static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi);
+static Log_event* next_event(RELAY_LOG_INFO* rli);
/*
Find out which replications threads are running
@@ -1295,7 +1297,7 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
rpl_filter->get_wild_ignore_table(&tmp);
protocol->store(&tmp);
- protocol->store((uint32) mi->rli.last_slave_errno);
+ protocol->store(mi->rli.last_slave_errno);
protocol->store(mi->rli.last_slave_error, &my_charset_bin);
protocol->store((uint32) mi->rli.slave_skip_counter);
protocol->store((ulonglong) mi->rli.group_master_log_pos);
@@ -1326,12 +1328,12 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
if ((mi->slave_running == MYSQL_SLAVE_RUN_CONNECT) &&
mi->rli.slave_running)
{
- long tmp= (long)((time_t)time((time_t*) 0)
- - mi->rli.last_master_timestamp)
- - mi->clock_diff_with_master;
+ long time_diff= ((long)((time_t)time((time_t*) 0)
+ - mi->rli.last_master_timestamp)
+ - mi->clock_diff_with_master);
/*
- Apparently on some systems tmp can be <0. Here are possible reasons
- related to MySQL:
+ Apparently on some systems time_diff can be <0. Here are possible
+ reasons related to MySQL:
- the master is itself a slave of another master whose time is ahead.
- somebody used an explicit SET TIMESTAMP on the master.
Possible reason related to granularity-to-second of time functions
@@ -1349,8 +1351,8 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
last_master_timestamp == 0 (an "impossible" timestamp 1970) is a
special marker to say "consider we have caught up".
*/
- protocol->store((longlong)(mi->rli.last_master_timestamp ? max(0, tmp)
- : 0));
+ protocol->store((longlong)(mi->rli.last_master_timestamp ?
+ max(0, time_diff) : 0));
}
else
protocol->store_null();
@@ -1421,13 +1423,11 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
*/
thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet
+ MAX_LOG_EVENT_HEADER; /* note, incr over the global not session var */
- thd->net.read_timeout = slave_net_timeout;
thd->slave_thread = 1;
set_slave_thread_options(thd);
thd->client_capabilities = CLIENT_LOCAL_FILES;
- thd->real_id=pthread_self();
pthread_mutex_lock(&LOCK_thread_count);
- thd->thread_id = thread_id++;
+ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
pthread_mutex_unlock(&LOCK_thread_count);
if (init_thr_lock() || thd->store_globals())
@@ -1437,12 +1437,6 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
DBUG_RETURN(-1);
}
-#if !defined(__WIN__) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
-
if (thd_type == SLAVE_THD_SQL)
thd->proc_info= "Waiting for the next event in relay log";
else
@@ -2052,15 +2046,16 @@ after reconnect");
while (!io_slave_killed(thd,mi))
{
- bool suppress_warnings= 0;
+ ulong event_len;
+ suppress_warnings= 0;
/*
We say "waiting" because read_event() will wait if there's nothing to
read. But if there's something to read, it will not wait. The
important thing is to not confuse users by saying "reading" whereas
we're in fact receiving nothing.
*/
- thd->proc_info = "Waiting for master to send event";
- ulong event_len = read_event(mysql, mi, &suppress_warnings);
+ thd->proc_info= "Waiting for master to send event";
+ event_len= read_event(mysql, mi, &suppress_warnings);
if (io_slave_killed(thd,mi))
{
if (global_system_variables.log_warnings)
@@ -2211,11 +2206,16 @@ err:
THD_CHECK_SENTRY(thd);
delete thd;
pthread_mutex_unlock(&LOCK_thread_count);
- mi->abort_slave = 0;
- mi->slave_running = 0;
- mi->io_thd = 0;
- pthread_mutex_unlock(&mi->run_lock);
+ mi->abort_slave= 0;
+ mi->slave_running= 0;
+ mi->io_thd= 0;
+ /*
+ Note: the order of the two following calls (first broadcast, then unlock)
+ is important. Otherwise a killer_thread can execute between the calls and
+ delete the mi structure leading to a crash! (see BUG#25306 for details)
+ */
pthread_cond_broadcast(&mi->stop_cond); // tell the world we are done
+ pthread_mutex_unlock(&mi->run_lock);
my_thread_end();
pthread_exit(0);
DBUG_RETURN(0); // Can't return anything here
@@ -2461,9 +2461,14 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
THD_CHECK_SENTRY(thd);
delete thd;
pthread_mutex_unlock(&LOCK_thread_count);
+ /*
+ Note: the order of the broadcast and unlock calls below (first broadcast, then unlock)
+ is important. Otherwise a killer_thread can execute between the calls and
+ delete the mi structure leading to a crash! (see BUG#25306 for details)
+ */
pthread_cond_broadcast(&rli->stop_cond);
- // tell the world we are done
- pthread_mutex_unlock(&rli->run_lock);
+ pthread_mutex_unlock(&rli->run_lock); // tell the world we are done
+
my_thread_end();
pthread_exit(0);
DBUG_RETURN(0); // Can't return anything here
@@ -2861,6 +2866,8 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
pthread_mutex_t *log_lock= rli->relay_log.get_log_lock();
DBUG_ENTER("queue_event");
+ LINT_INIT(inc_pos);
+
if (mi->rli.relay_log.description_event_for_queue->binlog_version<4 &&
buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT /* a way to escape */)
DBUG_RETURN(queue_old_event(mi,buf,event_len));
@@ -3002,7 +3009,7 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
err:
pthread_mutex_unlock(&mi->data_lock);
- DBUG_PRINT("info", ("error=%d", error));
+ DBUG_PRINT("info", ("error: %d", error));
DBUG_RETURN(error);
}
@@ -3322,7 +3329,13 @@ static Log_event* next_event(RELAY_LOG_INFO* rli)
hot_log=0; // Using old binary log
}
}
-
+ /*
+ As there is no guarantee that the relay is open (for example, an I/O
+ error during a write by the slave I/O thread may have closed it), we
+ have to test it.
+ */
+ if (!my_b_inited(cur_log))
+ goto err;
#ifndef DBUG_OFF
{
/* This is an assertion which sometimes fails, let's try to track it */
@@ -3651,6 +3664,70 @@ end:
}
+/**
+ Detects, based on master's version (as found in the relay log), if master
+ has a certain bug.
+ @param rli RELAY_LOG_INFO which tells the master's version
+ @param bug_id Number of the bug as found in bugs.mysql.com
+ @return TRUE if master has the bug, FALSE if it does not.
+*/
+bool rpl_master_has_bug(RELAY_LOG_INFO *rli, uint bug_id)
+{
+ struct st_version_range_for_one_bug {
+ uint bug_id;
+ const uchar introduced_in[3]; // first version with bug
+ const uchar fixed_in[3]; // first version with fix
+ };
+ static struct st_version_range_for_one_bug versions_for_all_bugs[]=
+ {
+ {24432, { 5, 0, 24 }, { 5, 0, 38 } },
+ {24432, { 5, 1, 12 }, { 5, 1, 17 } }
+ };
+ const uchar *master_ver=
+ rli->relay_log.description_event_for_exec->server_version_split;
+
+ DBUG_ASSERT(sizeof(rli->relay_log.description_event_for_exec->server_version_split) == 3);
+
+ for (uint i= 0;
+ i < sizeof(versions_for_all_bugs)/sizeof(*versions_for_all_bugs);i++)
+ {
+ const uchar *introduced_in= versions_for_all_bugs[i].introduced_in,
+ *fixed_in= versions_for_all_bugs[i].fixed_in;
+ if ((versions_for_all_bugs[i].bug_id == bug_id) &&
+ (memcmp(introduced_in, master_ver, 3) <= 0) &&
+ (memcmp(fixed_in, master_ver, 3) > 0))
+ {
+ // a short message for SHOW SLAVE STATUS (message length constraints)
+ my_printf_error(ER_UNKNOWN_ERROR, "master may suffer from"
+ " http://bugs.mysql.com/bug.php?id=%u"
+ " so slave stops; check error log on slave"
+ " for more info", MYF(0), bug_id);
+ // a verbose message for the error log
+ slave_print_msg(ERROR_LEVEL, rli, ER_UNKNOWN_ERROR,
+ "According to the master's version ('%s'),"
+ " it is probable that master suffers from this bug:"
+ " http://bugs.mysql.com/bug.php?id=%u"
+ " and thus replicating the current binary log event"
+ " may make the slave's data become different from the"
+ " master's data."
+ " To take no risk, slave refuses to replicate"
+ " this event and stops."
+ " We recommend that all updates be stopped on the"
+ " master and slave, that the data of both be"
+ " manually synchronized,"
+ " that master's binary logs be deleted,"
+ " that master be upgraded to a version at least"
+ " equal to '%d.%d.%d'. Then replication can be"
+ " restarted.",
+ rli->relay_log.description_event_for_exec->server_version,
+ bug_id,
+ fixed_in[0], fixed_in[1], fixed_in[2]);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List_iterator<i_string>;
template class I_List_iterator<i_string_pair>;
diff --git a/sql/slave.h b/sql/slave.h
index 43eb71be601..f21266bbee4 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -111,8 +111,6 @@ extern ulonglong relay_log_space_limit;
#define MYSQL_SLAVE_RUN_NOT_CONNECT 1
#define MYSQL_SLAVE_RUN_CONNECT 2
-static Log_event* next_event(RELAY_LOG_INFO* rli);
-
#define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\
"FIRST")
#define IO_RPL_LOG_NAME (mi->master_log_name[0] ? mi->master_log_name :\
@@ -161,6 +159,7 @@ int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
bool show_master_info(THD* thd, MASTER_INFO* mi);
bool show_binlog_info(THD* thd);
+bool rpl_master_has_bug(RELAY_LOG_INFO *rli, uint bug_id);
const char *print_slave_db_safe(const char *db);
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code);
diff --git a/sql/sp.cc b/sql/sp.cc
index 14703e3aa42..0c0bc8e8869 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -494,12 +494,17 @@ db_create_routine(THD *thd, int type, sp_head *sp)
int ret;
TABLE *table;
char definer[USER_HOST_BUFF_SIZE];
- char old_db_buf[NAME_LEN+1];
- LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) };
DBUG_ENTER("db_create_routine");
DBUG_PRINT("enter", ("type: %d name: %.*s",type,sp->m_name.length,
sp->m_name.str));
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
if (!(table= open_proc_table_for_update(thd)))
ret= SP_OPEN_TABLE_FAILED;
else
@@ -636,6 +641,13 @@ db_drop_routine(THD *thd, int type, sp_name *name)
DBUG_PRINT("enter", ("type: %d name: %.*s",
type, name->m_name.length, name->m_name.str));
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
if (!(table= open_proc_table_for_update(thd)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
@@ -668,6 +680,13 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
DBUG_PRINT("enter", ("type: %d name: %.*s",
type, name->m_name.length, name->m_name.str));
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
if (!(table= open_proc_table_for_update(thd)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
@@ -990,7 +1009,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp));
if (sp->m_first_free_instance)
{
- DBUG_PRINT("info", ("first free: 0x%lx, level: %lu, flags %x",
+ DBUG_PRINT("info", ("first free: 0x%lx level: %lu flags %x",
(ulong)sp->m_first_free_instance,
sp->m_first_free_instance->m_recursion_level,
sp->m_first_free_instance->m_flags));
@@ -1839,9 +1858,7 @@ create_string(THD *thd, String *buf,
SYNOPSIS
sp_use_new_db()
thd thread handle
-
new_db new database name (a string and its length)
-
old_db [IN] str points to a buffer where to store the old
database, length contains the size of the buffer
[OUT] if old db was not NULL, its name is copied
@@ -1849,7 +1866,6 @@ create_string(THD *thd, String *buf,
accordingly. Otherwise str[0] is set to '\0' and length
is set to 0. The out parameter should be used only if
the database name has been changed (see dbchangedp).
-
dbchangedp [OUT] is set to TRUE if the current database is changed,
FALSE otherwise. A database is not changed if the old
name is the same as the new one, both names are empty,
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 7c110185a95..b4c4d1bac85 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -36,6 +36,7 @@ Item_result
sp_map_result_type(enum enum_field_types type)
{
switch (type) {
+ case MYSQL_TYPE_BIT:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
@@ -58,6 +59,7 @@ Item::Type
sp_map_item_type(enum enum_field_types type)
{
switch (type) {
+ case MYSQL_TYPE_BIT:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
@@ -94,8 +96,6 @@ sp_map_item_type(enum enum_field_types type)
static String *
sp_get_item_value(THD *thd, Item *item, String *str)
{
- Item_result result_type= item->result_type();
-
switch (item->result_type()) {
case REAL_RESULT:
case INT_RESULT:
@@ -1117,7 +1117,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;
@@ -1369,7 +1369,6 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
MEM_ROOT call_mem_root;
Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP);
Query_arena backup_arena;
-
DBUG_ENTER("sp_head::execute_function");
DBUG_PRINT("info", ("function %s", m_name.str));
@@ -1485,8 +1484,24 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
if (need_binlog_call)
{
+ query_id_t q;
reset_dynamic(&thd->user_var_events);
- mysql_bin_log.start_union_events(thd);
+ /*
+ In case of artificially constructed events for function calls
+ we have separate union for each such event and hence can't use
+ query_id of real calling statement as the start of all these
+ unions (this will break logic of replication of user-defined
+ variables). So we use artifical value which is guaranteed to
+ be greater than all query_id's of all statements belonging
+ to previous events/unions.
+ Possible alternative to this is logging of all function invocations
+ as one select and not resetting THD::user_var_events before
+ each invocation.
+ */
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ q= global_query_id;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ mysql_bin_log.start_union_events(thd, q + 1);
binlog_save_options= thd->options;
thd->options&= ~OPTION_BIN_LOG;
}
@@ -1777,7 +1792,7 @@ sp_head::reset_lex(THD *thd)
DBUG_ENTER("sp_head::reset_lex");
LEX *sublex;
LEX *oldlex= thd->lex;
- my_lex_states state= oldlex->next_state; // Keep original next_state
+ my_lex_states org_next_state= oldlex->next_state;
(void)m_lex.push_front(oldlex);
thd->lex= sublex= new st_lex;
@@ -1786,10 +1801,10 @@ sp_head::reset_lex(THD *thd)
lex_start(thd, oldlex->buf, (ulong) (oldlex->end_of_query - oldlex->ptr));
/*
- * next_state is normally the same (0), but it happens that we swap lex in
- * "mid-sentence", so we must restore it.
+ next_state is normally the same (0), but it happens that we swap lex in
+ "mid-sentence", so we must restore it.
*/
- sublex->next_state= state;
+ sublex->next_state= org_next_state;
/* We must reset ptr and end_of_query again */
sublex->ptr= oldlex->ptr;
sublex->end_of_query= oldlex->end_of_query;
@@ -2429,16 +2444,11 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
m_lex->mark_as_requiring_prelocking(lex_query_tables_own_last);
}
}
-
+
reinit_stmt_before_use(thd, m_lex);
- /*
- If requested check whenever we have access to tables in LEX's table list
- and open and lock them before executing instructtions core function.
- */
- if (open_tables &&
- (check_table_access(thd, SELECT_ACL, m_lex->query_tables, 0) ||
- open_and_lock_tables(thd, m_lex->query_tables)))
- res= -1;
+
+ if (open_tables)
+ res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
if (!res)
{
@@ -2490,6 +2500,29 @@ 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)
+{
+ int result;
+
+ /*
+ Check whenever we have access to tables for this statement
+ and open and lock them before executing instructions core function.
+ */
+ if (check_table_access(thd, SELECT_ACL, tables, 0)
+ || open_and_lock_tables(thd, tables))
+ result= -1;
+ else
+ result= 0;
+
+ return result;
+}
+
+uint sp_instr::get_cont_dest()
+{
+ return (m_ip+1);
+}
+
+
int sp_instr::exec_core(THD *thd, uint *nextp)
{
DBUG_ASSERT(0);
@@ -2675,6 +2708,15 @@ sp_instr_set_trigger_field::print(String *str)
value->print(str);
}
+/*
+ sp_instr_opt_meta
+*/
+
+uint sp_instr_opt_meta::get_cont_dest()
+{
+ return m_cont_dest;
+}
+
/*
sp_instr_jump class functions
@@ -2764,7 +2806,6 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
if (! it)
{
res= -1;
- *nextp = m_cont_dest;
}
else
{
@@ -3333,7 +3374,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 385d90bb5b8..1776d81b248 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -468,15 +468,34 @@ 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;
+ /**
+ Execute <code>open_and_lock_tables()</code> for this statement.
+ 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>.
+ @param thd the current thread
+ @param tables the list of tables to open and lock
+ @return zero on success, non zero on failure.
+ */
+ int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables);
+
+ /**
+ Get the continuation destination of this instruction.
+ @return the continuation destination
+ */
+ virtual uint get_cont_dest();
+
/*
Execute core function of instruction after all preparations (e.g.
setting of proper LEX, saving part of the thread context have been
@@ -653,9 +672,9 @@ class sp_instr_set : public sp_instr
public:
sp_instr_set(uint ip, sp_pcontext *ctx,
- uint offset, Item *val, enum enum_field_types type,
+ uint offset, Item *val, enum enum_field_types type_arg,
LEX *lex, bool lex_resp)
- : sp_instr(ip, ctx), m_offset(offset), m_value(val), m_type(type),
+ : sp_instr(ip, ctx), m_offset(offset), m_value(val), m_type(type_arg),
m_lex_keeper(lex, lex_resp)
{}
@@ -741,6 +760,8 @@ public:
virtual void set_destination(uint old_dest, uint new_dest)
= 0;
+ virtual uint get_cont_dest();
+
protected:
sp_instr *m_optdest; // Used during optimization
@@ -853,8 +874,9 @@ class sp_instr_freturn : public sp_instr
public:
sp_instr_freturn(uint ip, sp_pcontext *ctx,
- Item *val, enum enum_field_types type, LEX *lex)
- : sp_instr(ip, ctx), m_value(val), m_type(type), m_lex_keeper(lex, TRUE)
+ Item *val, enum enum_field_types type_arg, LEX *lex)
+ : sp_instr(ip, ctx), m_value(val), m_type(type_arg),
+ m_lex_keeper(lex, TRUE)
{}
virtual ~sp_instr_freturn()
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 22df69a978b..6cadb0f3aad 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -23,13 +23,13 @@
String Geometry::bad_geometry_data("Bad object", &my_charset_bin);
-Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_end+1]=
+Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_last+1]=
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
static Geometry::Class_info **ci_collection_end=
- Geometry::ci_collection+Geometry::wkb_end + 1;
+ Geometry::ci_collection+Geometry::wkb_last + 1;
Geometry::Class_info::Class_info(const char *name, int type_id,
void(*create_func)(void *)):
@@ -552,7 +552,7 @@ bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const
}
-int Gis_line_string::length(double *len) const
+int Gis_line_string::geom_length(double *len) const
{
uint32 n_points;
double prev_x, prev_y;
@@ -928,6 +928,8 @@ int Gis_polygon::centroid_xy(double *x, double *y) const
n_linear_rings= uint4korr(data);
data+= 4;
+ DBUG_ASSERT(n_linear_rings > 0);
+
while (n_linear_rings--)
{
uint32 n_points, org_n_points;
@@ -947,14 +949,14 @@ int Gis_polygon::centroid_xy(double *x, double *y) const
while (--n_points) // One point is already read
{
- double x, y;
- get_point(&x, &y, data);
+ double tmp_x, tmp_y;
+ get_point(&tmp_x, &tmp_y, data);
data+= (SIZEOF_STORED_DOUBLE*2);
- cur_area+= (prev_x + x) * (prev_y - y);
- cur_cx+= x;
- cur_cy+= y;
- prev_x= x;
- prev_y= y;
+ cur_area+= (prev_x + tmp_x) * (prev_y - tmp_y);
+ cur_cx+= tmp_x;
+ cur_cy+= tmp_y;
+ prev_x= tmp_x;
+ prev_y= tmp_y;
}
cur_area= fabs(cur_area) / 2;
cur_cx= cur_cx / (org_n_points - 1);
@@ -1298,7 +1300,7 @@ int Gis_multi_line_string::geometry_n(uint32 num, String *result) const
}
-int Gis_multi_line_string::length(double *len) const
+int Gis_multi_line_string::geom_length(double *len) const
{
uint32 n_line_strings;
const char *data= m_data;
@@ -1315,7 +1317,7 @@ int Gis_multi_line_string::length(double *len) const
Gis_line_string ls;
data+= WKB_HEADER_SIZE;
ls.set_data_ptr(data, (uint32) (m_data_end - data));
- if (ls.length(&ls_len))
+ if (ls.geom_length(&ls_len))
return 1;
*len+= ls_len;
/*
diff --git a/sql/spatial.h b/sql/spatial.h
index afce9b2d98f..f0c8b7bba28 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -188,7 +188,7 @@ public:
wkb_multilinestring= 5,
wkb_multipolygon= 6,
wkb_geometrycollection= 7,
- wkb_end=7
+ wkb_last=7
};
enum wkbByteOrder
{
@@ -217,7 +217,7 @@ public:
virtual bool dimension(uint32 *dim, const char **end) const=0;
virtual int get_x(double *x) const { return -1; }
virtual int get_y(double *y) const { return -1; }
- virtual int length(double *len) const { return -1; }
+ virtual int geom_length(double *len) const { return -1; }
virtual int area(double *ar, const char **end) const { return -1;}
virtual int is_closed(int *closed) const { return -1; }
virtual int num_interior_ring(uint32 *n_int_rings) const { return -1; }
@@ -273,12 +273,12 @@ public:
}
bool envelope(String *result) const;
- static Class_info *ci_collection[wkb_end+1];
+ static Class_info *ci_collection[wkb_last+1];
protected:
static Class_info *find_class(int type_id)
{
- return ((type_id < wkb_point) || (type_id > wkb_end)) ?
+ return ((type_id < wkb_point) || (type_id > wkb_last)) ?
NULL : ci_collection[type_id];
}
static Class_info *find_class(const char *name, uint32 len);
@@ -359,7 +359,7 @@ public:
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
- int length(double *len) const;
+ int geom_length(double *len) const;
int is_closed(int *closed) const;
int num_points(uint32 *n_points) const;
int start_point(String *point) const;
@@ -441,7 +441,7 @@ public:
bool get_mbr(MBR *mbr, const char **end) const;
int num_geometries(uint32 *num) const;
int geometry_n(uint32 num, String *result) const;
- int length(double *len) const;
+ int geom_length(double *len) const;
int is_closed(int *closed) const;
bool dimension(uint32 *dim, const char **end) const
{
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 0d9653172e0..ee7127fcd8d 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3001,6 +3001,13 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE;
tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
#ifdef HAVE_REPLICATION
/*
GRANT and REVOKE are applied the slave in/exclusion rules as they are
@@ -3218,6 +3225,13 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
tables[0].lock_type=tables[1].lock_type=TL_WRITE;
tables[0].db=tables[1].db=(char*) "mysql";
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
#ifdef HAVE_REPLICATION
/*
GRANT and REVOKE are applied the slave in/exclusion rules as they are
@@ -3357,6 +3371,13 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
tables[0].lock_type=tables[1].lock_type=TL_WRITE;
tables[0].db=tables[1].db=(char*) "mysql";
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
#ifdef HAVE_REPLICATION
/*
GRANT and REVOKE are applied the slave in/exclusion rules as they are
@@ -5169,6 +5190,8 @@ static int handle_grant_struct(uint struct_no, bool drop,
user= grant_name->user;
host= grant_name->host.hostname;
break;
+ default:
+ assert(0);
}
if (! user)
user= "";
@@ -5399,6 +5422,13 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
TABLE_LIST tables[GRANT_TABLES];
DBUG_ENTER("mysql_create_user");
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
/* CREATE USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
@@ -5471,6 +5501,13 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
TABLE_LIST tables[GRANT_TABLES];
DBUG_ENTER("mysql_drop_user");
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
/* DROP USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
@@ -5535,6 +5572,13 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
TABLE_LIST tables[GRANT_TABLES];
DBUG_ENTER("mysql_rename_user");
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
/* RENAME USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
@@ -5610,6 +5654,13 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
TABLE_LIST tables[GRANT_TABLES];
DBUG_ENTER("mysql_revoke_all");
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
@@ -5800,6 +5851,13 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
rw_wrlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
/* Remove procedure access */
do
{
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 54ced074dd3..e7decf4a8fc 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -86,6 +86,11 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
else if (param->next)
{
// first parameter
+ if (!(*param->item)->fixed && (*param->item)->fix_fields(thd, param->item))
+ {
+ DBUG_PRINT("info", ("fix_fields() for the first parameter failed"));
+ goto err;
+ }
if ((*param->item)->type() != Item::INT_ITEM ||
(*param->item)->val_real() < 0)
{
@@ -100,6 +105,11 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
goto err;
}
// second parameter
+ if (!(*param->item)->fixed && (*param->item)->fix_fields(thd, param->item))
+ {
+ DBUG_PRINT("info", ("fix_fields() for the second parameter failed"));
+ goto err;
+ }
if ((*param->item)->type() != Item::INT_ITEM ||
(*param->item)->val_real() < 0)
{
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 930615133da..44325fe7b12 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -28,6 +28,59 @@
#include <io.h>
#endif
+/**
+ This internal handler is used to trap internally
+ errors that can occur when executing open table
+ during the prelocking phase.
+*/
+class Prelock_error_handler : public Internal_error_handler
+{
+public:
+ Prelock_error_handler()
+ : m_handled_errors(0), m_unhandled_errors(0)
+ {}
+
+ virtual ~Prelock_error_handler() {}
+
+ virtual bool handle_error(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd);
+
+ bool safely_trapped_errors();
+
+private:
+ int m_handled_errors;
+ int m_unhandled_errors;
+};
+
+
+bool
+Prelock_error_handler::handle_error(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level /* level */,
+ THD * /* thd */)
+{
+ if (sql_errno == ER_NO_SUCH_TABLE)
+ {
+ m_handled_errors++;
+ return TRUE; // 'TRUE', as per coding style
+ }
+
+ m_unhandled_errors++;
+ return FALSE; // 'FALSE', as per coding style
+}
+
+
+bool Prelock_error_handler::safely_trapped_errors()
+{
+ /*
+ If m_unhandled_errors != 0, something else, unanticipated, happened,
+ so the error is not trapped but returned to the caller.
+ Multiple ER_NO_SUCH_TABLE can be raised in case of views.
+ */
+ return ((m_handled_errors > 0) && (m_unhandled_errors == 0));
+}
+
+
TABLE *unused_tables; /* Used by mysql_test */
HASH open_cache; /* Used by mysql_test */
static HASH table_def_cache;
@@ -1078,7 +1131,6 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
if (!thd->active_transaction())
thd->transaction.xid_state.xid.null();
- /* VOID(pthread_sigmask(SIG_SETMASK,&thd->block_signals,NULL)); */
if (!lock_in_use)
VOID(pthread_mutex_lock(&LOCK_open));
@@ -1142,12 +1194,7 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
}
else
{
- if (table->s->flush_version != flush_version)
- {
- table->s->flush_version= flush_version;
- table->file->extra(HA_EXTRA_FLUSH);
- }
- // Free memory and reset for next loop
+ /* Free memory and reset for next loop */
table->file->ha_reset();
table->in_use=0;
if (unused_tables)
@@ -1208,11 +1255,12 @@ void close_temporary_tables(THD *thd)
const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ";
uint stub_len= sizeof(stub) - 1;
char buf[256];
- memcpy(buf, stub, stub_len);
String s_query= String(buf, sizeof(buf), system_charset_info);
- bool found_user_tables= false;
+ bool found_user_tables= FALSE;
LINT_INIT(next);
+ memcpy(buf, stub, stub_len);
+
/*
insertion sort of temp tables by pseudo_thread_id to build ordered list
of sublists of equal pseudo_thread_id
@@ -1263,10 +1311,13 @@ void close_temporary_tables(THD *thd)
{
if (is_user_table(table))
{
+ my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id;
/* Set pseudo_thread_id to be that of the processed table */
thd->variables.pseudo_thread_id= tmpkeyval(thd, table);
- /* Loop forward through all tables within the sublist of
- common pseudo_thread_id to create single DROP query */
+ /*
+ Loop forward through all tables within the sublist of
+ common pseudo_thread_id to create single DROP query.
+ */
for (s_query.length(stub_len);
table && is_user_table(table) &&
tmpkeyval(thd, table) == thd->variables.pseudo_thread_id;
@@ -1292,16 +1343,18 @@ void close_temporary_tables(THD *thd)
0, FALSE);
thd->variables.character_set_client= cs_save;
/*
- Imagine the thread had created a temp table, then was doing a SELECT, and
- the SELECT was killed. Then it's not clever to mark the statement above as
- "killed", because it's not really a statement updating data, and there
- are 99.99% chances it will succeed on slave.
- If a real update (one updating a persistent table) was killed on the
- master, then this real update will be logged with error_code=killed,
- rightfully causing the slave to stop.
+ Imagine the thread had created a temp table, then was doing a
+ SELECT, and the SELECT was killed. Then it's not clever to
+ mark the statement above as "killed", because it's not really
+ a statement updating data, and there are 99.99% chances it
+ will succeed on slave. If a real update (one updating a
+ persistent table) was killed on the master, then this real
+ update will be logged with error_code=killed, rightfully
+ causing the slave to stop.
*/
qinfo.error_code= 0;
mysql_bin_log.write(&qinfo);
+ thd->variables.pseudo_thread_id= save_pseudo_thread_id;
}
else
{
@@ -1519,9 +1572,15 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list)
{
if (table->s->table_cache_key.length == key_length &&
!memcmp(table->s->table_cache_key.str, key, key_length))
+ {
+ DBUG_PRINT("info",
+ ("Found table. server_id: %u pseudo_thread_id: %lu",
+ (uint) thd->server_id,
+ (ulong) thd->variables.pseudo_thread_id));
DBUG_RETURN(table);
+ }
}
- DBUG_RETURN(0); // Not a temporary table
+ DBUG_RETURN(0); // Not a temporary table
}
@@ -1777,7 +1836,6 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
share= table->s;
share->version=0;
- share->flush_version=0;
table->in_use = thd;
check_unused();
table->next = thd->open_tables;
@@ -1845,6 +1903,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
key_length= (create_table_def_key(thd, key, table_list, 1) -
TMP_TABLE_KEY_EXTRA);
+ /*
+ Unless requested otherwise, try to resolve this table in the list
+ of temporary tables of this thread. In MySQL temporary tables
+ are always thread-local and "shadow" possible base tables with the
+ same name. This block implements the behaviour.
+ TODO: move this block into a separate function.
+ */
if (!table_list->skip_temporary)
{
for (table= thd->temporary_tables; table ; table=table->next)
@@ -1854,9 +1919,19 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
!memcmp(table->s->table_cache_key.str, key,
key_length + TMP_TABLE_KEY_EXTRA))
{
+ /*
+ We're trying to use the same temporary table twice in a query.
+ Right now we don't support this because a temporary table
+ is always represented by only one TABLE object in THD, and
+ it can not be cloned. Emit an error for an unsupported behaviour.
+ */
if (table->query_id == thd->query_id ||
thd->prelocked_mode && table->query_id)
{
+ DBUG_PRINT("error",
+ ("query_id: %lu server_id: %u pseudo_thread_id: %lu",
+ (ulong) table->query_id, (uint) thd->server_id,
+ (ulong) thd->variables.pseudo_thread_id));
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
DBUG_RETURN(0);
}
@@ -1869,6 +1944,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
}
+ /*
+ The table is not temporary - if we're in pre-locked or LOCK TABLES
+ mode, let's try to find the requested table in the list of pre-opened
+ and locked tables. If the table is not there, return an error - we can't
+ open not pre-opened tables in pre-locked/LOCK TABLES mode.
+ TODO: move this block into a separate function.
+ */
if (!(flags & MYSQL_OPEN_IGNORE_LOCKED_TABLES) &&
(thd->locked_tables || thd->prelocked_mode))
{ // Using table locks
@@ -1940,7 +2022,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
goto reset;
}
/*
- is it view?
+ Is this table a view and not a base table?
(it is work around to allow to open view with locked tables,
real fix will be made after definition cache will be made)
*/
@@ -1968,12 +2050,39 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
VOID(pthread_mutex_unlock(&LOCK_open));
}
}
- my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
+ if ((thd->locked_tables) && (thd->locked_tables->lock_count > 0))
+ my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
+ else
+ my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
DBUG_RETURN(0);
}
+ /*
+ Non pre-locked/LOCK TABLES mode, and the table is not temporary:
+ this is the normal use case.
+ Now we should:
+ - try to find the table in the table cache.
+ - if one of the discovered TABLE instances is name-locked
+ (table->s->version == 0) or some thread has started FLUSH TABLES
+ (refresh_version > table->s->version), back off -- we have to wait
+ until no one holds a name lock on the table.
+ - if there is no such TABLE in the name cache, read the table definition
+ and insert it into the cache.
+ We perform all of the above under LOCK_open which currently protects
+ the open cache (also known as table cache) and table definitions stored
+ on disk.
+ */
+
VOID(pthread_mutex_lock(&LOCK_open));
+ /*
+ If it's the first table from a list of tables used in a query,
+ remember refresh_version (the version of open_cache state).
+ If the version changes while we're opening the remaining tables,
+ we will have to back off, close all the tables opened-so-far,
+ and try to reopen them.
+ Note: refresh_version is currently changed only during FLUSH TABLES.
+ */
if (!thd->open_tables)
thd->version=refresh_version;
else if ((thd->version != refresh_version) &&
@@ -1990,6 +2099,16 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (thd->handler_tables)
mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE);
+ /*
+ Actually try to find the table in the open_cache.
+ The cache may contain several "TABLE" instances for the same
+ physical table. The instances that are currently "in use" by
+ some thread have their "in_use" member != NULL.
+ There is no good reason for having more than one entry in the
+ hash for the same physical table, except that we use this as
+ an implicit "pending locks queue" - see
+ wait_for_locked_table_names for details.
+ */
for (table= (TABLE*) hash_first(&open_cache, (byte*) key, key_length,
&state);
table && table->in_use ;
@@ -1999,6 +2118,21 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
/*
Here we flush tables marked for flush. However we never flush log
tables here. They are flushed only on FLUSH LOGS.
+ Normally, table->s->version contains the value of
+ refresh_version from the moment when this table was
+ (re-)opened and added to the cache.
+ If since then we did (or just started) FLUSH TABLES
+ statement, refresh_version has been increased.
+ For "name-locked" TABLE instances, table->s->version is set
+ to 0 (see lock_table_name for details).
+ In case there is a pending FLUSH TABLES or a name lock, we
+ need to back off and re-start opening tables.
+ If we do not back off now, we may dead lock in case of lock
+ order mismatch with some other thread:
+ c1: name lock t1; -- sort of exclusive lock
+ c2: open t2; -- sort of shared lock
+ c1: name lock t2; -- blocks
+ c2: open t1; -- blocks
*/
if (table->s->version != refresh_version && !table->s->log_table)
{
@@ -2014,16 +2148,35 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
/*
- There is a refresh in progress for this table
- Wait until the table is freed or the thread is killed.
+ Back off, part 1: mark the table as "unused" for the
+ purpose of name-locking by setting table->db_stat to 0. Do
+ that only for the tables in this thread that have an old
+ table->s->version (this is an optimization (?)).
+ table->db_stat == 0 signals wait_for_locked_table_names
+ that the tables in question are not used any more. See
+ table_is_used call for details.
*/
close_old_data_files(thd,thd->open_tables,0,0);
+ /*
+ Back-off part 2: try to avoid "busy waiting" on the table:
+ if the table is in use by some other thread, we suspend
+ and wait till the operation is complete: when any
+ operation that juggles with table->s->version completes,
+ it broadcasts COND_refresh condition variable.
+ */
if (table->in_use != thd)
+ {
+ /* wait_for_conditionwill unlock LOCK_open for us */
wait_for_condition(thd, &LOCK_open, &COND_refresh);
+ }
else
{
VOID(pthread_mutex_unlock(&LOCK_open));
}
+ /*
+ There is a refresh in progress for this table.
+ Signal the caller that it has to try again.
+ */
if (refresh)
*refresh=1;
DBUG_RETURN(0);
@@ -2031,6 +2184,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
if (table)
{
+ /* Unlink the table from "unused_tables" list. */
if (table == unused_tables)
{ // First unused
unused_tables=unused_tables->next; // Remove from link
@@ -2043,6 +2197,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
else
{
+ /* Insert a new TABLE instance into the open cache */
int error;
/* Free cache if too big */
while (open_cache.records > table_cache_size && unused_tables)
@@ -2851,6 +3006,8 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
MEM_ROOT new_frm_mem;
/* Also used for indicating that prelocking is need */
TABLE_LIST **query_tables_last_own;
+ bool safe_to_ignore_table;
+
DBUG_ENTER("open_tables");
/*
temporary mem_root for new .frm parsing.
@@ -2897,8 +3054,13 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
}
}
+ /*
+ For every table in the list of tables to open, try to find or open
+ a table.
+ */
for (tables= *start; tables ;tables= tables->next_global)
{
+ safe_to_ignore_table= FALSE; // 'FALSE', as per coding style
/*
Ignore placeholders for derived tables. After derived tables
processing, link to created temporary table will be put here.
@@ -2911,6 +3073,12 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
goto process_view_routines;
continue;
}
+ /*
+ If this TABLE_LIST object is a placeholder for an information_schema
+ table, create a temporary table to represent the information_schema
+ table in the query. Do not fill it yet - will be filled during
+ execution.
+ */
if (tables->schema_table)
{
if (!mysql_schema_table(thd, thd->lex, tables))
@@ -2918,9 +3086,32 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
DBUG_RETURN(-1);
}
(*counter)++;
-
- if (!tables->table &&
- !(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags)))
+
+ /*
+ Not a placeholder: must be a base table or a view, and the table is
+ not opened yet. Try to open the table.
+ */
+ if (!tables->table)
+ {
+ if (tables->prelocking_placeholder)
+ {
+ /*
+ For the tables added by the pre-locking code, attempt to open
+ the table but fail silently if the table does not exist.
+ The real failure will occur when/if a statement attempts to use
+ that table.
+ */
+ Prelock_error_handler prelock_handler;
+ thd->push_internal_handler(& prelock_handler);
+ tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags);
+ thd->pop_internal_handler();
+ safe_to_ignore_table= prelock_handler.safely_trapped_errors();
+ }
+ else
+ tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags);
+ }
+
+ if (!tables->table)
{
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
@@ -2971,6 +3162,14 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
close_tables_for_reopen(thd, start);
goto restart;
}
+
+ if (safe_to_ignore_table)
+ {
+ DBUG_PRINT("info", ("open_table: ignoring table '%s'.'%s'",
+ tables->db, tables->alias));
+ continue;
+ }
+
result= -1; // Fatal error
break;
}
@@ -3025,7 +3224,7 @@ process_view_routines:
{
/*
Serious error during reading stored routines from mysql.proc table.
- Something's wrong with the table or its contents, and an error has
+ Something is wrong with the table or its contents, and an error has
been emitted; we must abort.
*/
result= -1;
@@ -3274,7 +3473,7 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags)
static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
{
for (; table; table= table->next_global)
- if (!table->placeholder() && !table->schema_table)
+ if (!table->placeholder())
table->table->query_id= 0;
}
@@ -3347,7 +3546,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
DBUG_RETURN(-1);
for (table= tables; table; table= table->next_global)
{
- if (!table->placeholder() && !table->schema_table)
+ if (!table->placeholder())
*(ptr++)= table->table;
}
@@ -3400,7 +3599,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
for (table= tables; table != first_not_own; table= table->next_global)
{
- if (!table->placeholder() && !table->schema_table)
+ if (!table->placeholder())
{
table->table->query_id= thd->query_id;
if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
@@ -3427,7 +3626,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
for (table= tables; table != first_not_own; table= table->next_global)
{
- if (!table->placeholder() && !table->schema_table &&
+ if (!table->placeholder() &&
check_lock_and_start_stmt(thd, table->table, table->lock_type))
{
ha_rollback_stmt(thd);
@@ -3507,8 +3706,11 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
uint key_length;
TABLE_LIST table_list;
DBUG_ENTER("open_temporary_table");
- DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'",
- db, table_name, path));
+ DBUG_PRINT("enter",
+ ("table: '%s'.'%s' path: '%s' server_id: %u "
+ "pseudo_thread_id: %lu",
+ db, table_name, path,
+ (uint) thd->server_id, (ulong) thd->variables.pseudo_thread_id));
table_list.db= (char*) db;
table_list.table_name= (char*) table_name;
@@ -3764,7 +3966,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
{
List_iterator_fast<Natural_join_column>
field_it(*(table_ref->join_columns));
- Natural_join_column *nj_col;
+ Natural_join_column *nj_col, *curr_nj_col;
Field *found_field;
Query_arena *arena, backup;
DBUG_ENTER("find_field_in_natural_join");
@@ -3776,18 +3978,26 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
LINT_INIT(arena);
LINT_INIT(found_field);
- for (;;)
+ for (nj_col= NULL, curr_nj_col= field_it++; curr_nj_col;
+ curr_nj_col= field_it++)
{
- if (!(nj_col= field_it++))
- DBUG_RETURN(NULL);
-
- if (!my_strcasecmp(system_charset_info, nj_col->name(), name))
- break;
+ if (!my_strcasecmp(system_charset_info, curr_nj_col->name(), name))
+ {
+ if (nj_col)
+ {
+ my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where);
+ DBUG_RETURN(NULL);
+ }
+ nj_col= curr_nj_col;
+ }
}
+ if (!nj_col)
+ DBUG_RETURN(NULL);
if (nj_col->view_field)
{
Item *item;
+ LINT_INIT(arena);
if (register_tree_change)
arena= thd->activate_stmt_arena_if_needed(&backup);
/*
@@ -3971,6 +4181,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
{
Field *fld;
DBUG_ENTER("find_field_in_table_ref");
+ DBUG_ASSERT(table_list->alias);
+ DBUG_ASSERT(name);
+ DBUG_ASSERT(item_name);
DBUG_PRINT("enter",
("table: '%s' field name: '%s' item name: '%s' ref 0x%lx",
table_list->alias, name, item_name, (ulong) ref));
@@ -4684,9 +4897,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
{
bool found= FALSE;
const char *field_name_1;
+ /* true if field_name_1 is a member of using_fields */
+ bool is_using_column_1;
if (!(nj_col_1= it_1.get_or_create_column_ref(leaf_1)))
goto err;
field_name_1= nj_col_1->name();
+ is_using_column_1= using_fields &&
+ test_if_string_in_list(field_name_1, using_fields);
+ DBUG_PRINT ("info", ("field_name_1=%s.%s",
+ nj_col_1->table_name() ? nj_col_1->table_name() : "",
+ field_name_1));
/*
Find a field with the same name in table_ref_2.
@@ -4703,6 +4923,10 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
if (!(cur_nj_col_2= it_2.get_or_create_column_ref(leaf_2)))
goto err;
cur_field_name_2= cur_nj_col_2->name();
+ DBUG_PRINT ("info", ("cur_field_name_2=%s.%s",
+ cur_nj_col_2->table_name() ?
+ cur_nj_col_2->table_name() : "",
+ cur_field_name_2));
/*
Compare the two columns and check for duplicate common fields.
@@ -4710,10 +4934,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
table_ref_2 (then found == TRUE), or if a field in table_ref_2
was already matched by some previous field in table_ref_1
(then cur_nj_col_2->is_common == TRUE).
+ Note that it is too early to check the columns outside of the
+ USING list for ambiguity because they are not actually "referenced"
+ here. These columns must be checked only on unqualified reference
+ by name (e.g. in SELECT list).
*/
if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2))
{
- if (found || cur_nj_col_2->is_common)
+ DBUG_PRINT ("info", ("match c1.is_common=%d", nj_col_1->is_common));
+ if (cur_nj_col_2->is_common ||
+ (found && (!using_fields || is_using_column_1)))
{
my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where);
goto err;
@@ -4739,9 +4969,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
clause (if present), mark them as common fields, and add a new
equi-join condition to the ON clause.
*/
- if (nj_col_2 &&
- (!using_fields ||
- test_if_string_in_list(field_name_1, using_fields)))
+ if (nj_col_2 && (!using_fields ||is_using_column_1))
{
Item *item_1= nj_col_1->create_item(thd);
Item *item_2= nj_col_2->create_item(thd);
@@ -4796,6 +5024,13 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
eq_cond);
nj_col_1->is_common= nj_col_2->is_common= TRUE;
+ DBUG_PRINT ("info", ("%s.%s and %s.%s are common",
+ nj_col_1->table_name() ?
+ nj_col_1->table_name() : "",
+ nj_col_1->name(),
+ nj_col_2->table_name() ?
+ nj_col_2->table_name() : "",
+ nj_col_2->name()));
if (field_1)
{
@@ -5321,6 +5556,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
bzero(ref_pointer_array, sizeof(Item *) * fields.elements);
Item **ref= ref_pointer_array;
+ thd->lex->current_select->cur_pos_in_select_list= 0;
while ((item= it++))
{
if (!item->fixed && item->fix_fields(thd, it.ref()) ||
@@ -5337,7 +5573,10 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
sum_func_list)
item->split_sum_func(thd, ref_pointer_array, *sum_func_list);
thd->used_tables|= item->used_tables();
+ thd->lex->current_select->cur_pos_in_select_list++;
}
+ thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
+
thd->lex->allow_sum_func= save_allow_sum_func;
thd->mark_used_columns= save_mark_used_columns;
DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
@@ -5410,21 +5649,8 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
uint tablenr= 0;
DBUG_ENTER("setup_tables");
- /*
- Due to the various call paths that lead to setup_tables() it may happen
- that context->table_list and context->first_name_resolution_table can be
- NULL (this is typically done when creating TABLE_LISTs internally).
- TODO:
- Investigate all cases when this my happen, initialize the name resolution
- context correctly in all those places, and remove the context reset below.
- */
- if (!context->table_list || !context->first_name_resolution_table)
- {
- /* Test whether the context is in a consistent state. */
- DBUG_ASSERT(!context->first_name_resolution_table && !context->table_list);
- context->table_list= context->first_name_resolution_table= tables;
- }
-
+ DBUG_ASSERT ((select_insert && !tables->next_name_resolution_table) || !tables ||
+ (context->table_list && context->first_name_resolution_table));
/*
this is used for INSERT ... SELECT.
For select we setup tables except first (and its underlying tables)
@@ -5458,7 +5684,12 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
get_key_map_from_key_list(&map, table, table_list->use_index);
if (map.is_set_all())
DBUG_RETURN(1);
- table->keys_in_use_for_query=map;
+ /*
+ Don't introduce keys in keys_in_use_for_query that weren't there
+ before. FORCE/USE INDEX should not add keys, it should only remove
+ all keys except the key(s) specified in the hint.
+ */
+ table->keys_in_use_for_query.intersect(map);
}
if (table_list->ignore_index)
{
diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc
index d8f12375258..b0a54bec664 100644
--- a/sql/sql_binlog.cc
+++ b/sql/sql_binlog.cc
@@ -163,7 +163,7 @@ void mysql_client_binlog_statement(THD* thd)
(ulong) uint4korr(bufptr+EVENT_LEN_OFFSET)));
#endif
ev->thd= thd;
- if (int err= ev->exec_event(thd->rli_fake))
+ if (IF_DBUG(int err= ) ev->exec_event(thd->rli_fake))
{
DBUG_PRINT("error", ("exec_event() returned: %d", err));
/*
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index 0fbc06ce919..bc00f7ea629 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -127,7 +127,7 @@ struct Query_cache_query
inline void tables_type(uint8 type) { tbls_type= type; }
inline ulong length() { return len; }
inline ulong add(ulong packet_len) { return(len+= packet_len); }
- inline void length(ulong length) { len= length; }
+ inline void length(ulong length_arg) { len= length_arg; }
inline gptr query()
{
return (gptr)(((byte*)this)+
@@ -155,7 +155,7 @@ struct Query_cache_table
inline char *db() { return (char *) data(); }
inline char *table() { return tbl; }
- inline void table(char *table) { tbl= table; }
+ inline void table(char *table_arg) { tbl= table_arg; }
inline uint32 key_length() { return key_len; }
inline void key_length(uint32 len) { key_len= len; }
inline uint8 type() { return table_type; }
@@ -163,7 +163,7 @@ struct Query_cache_table
inline qc_engine_callback callback() { return callback_func; }
inline void callback(qc_engine_callback fn){ callback_func= fn; }
inline ulonglong engine_data() { return engine_data_buff; }
- inline void engine_data(ulonglong data) { engine_data_buff= data; }
+ inline void engine_data(ulonglong data_arg){ engine_data_buff= data_arg; }
inline gptr data()
{
return (gptr)(((byte*)this)+
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index fc078640a96..e8e39972020 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -192,14 +192,10 @@ void **thd_ha_data(const THD *thd, const struct handlerton *hton)
}
-/*
- Pass nominal parameters to Statement constructor only to ensure that
- the destructor works OK in case of error. The main_mem_root will be
- re-initialized in init().
-*/
THD::THD()
- :Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0),
+ :Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION,
+ /* statement id */ 0),
Open_tables_state(refresh_version), rli_fake(0),
lock_id(&main_lock_id),
user_time(0), in_sub_stmt(0),
@@ -214,6 +210,14 @@ THD::THD()
stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE),
spcont(NULL)
{
+ ulong tmp;
+
+ /*
+ Pass nominal parameters to init_alloc_root only to ensure that
+ the destructor works OK in case of an error. The main_mem_root
+ will be re-initialized in init_for_queries().
+ */
+ init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
stmt_arena= this;
thread_stack= 0;
db= 0;
@@ -241,7 +245,7 @@ THD::THD()
time_after_lock=(time_t) 0;
current_linfo = 0;
slave_thread = 0;
- variables.pseudo_thread_id= 0;
+ thread_id= variables.pseudo_thread_id= 0;
one_shot_set= 0;
file_id = 0;
query_id= 0;
@@ -265,9 +269,6 @@ THD::THD()
cleanup_done= abort_on_warning= no_warnings_for_error= 0;
peer_port= 0; // For SHOW PROCESSLIST
transaction.m_pending_rows_event= 0;
-#ifdef __WIN__
- real_id = 0;
-#endif
#ifdef SIGNAL_WITH_VIO_CLOSE
active_vio = 0;
#endif
@@ -305,11 +306,43 @@ THD::THD()
protocol_binary.init(this);
tablespace_op=FALSE;
- ulong tmp=sql_rnd_with_mutex();
- randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
+ tmp= sql_rnd_with_mutex();
+ randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id);
substitute_null_with_insert_id = FALSE;
thr_lock_info_init(&lock_info); /* safety: will be reset after start */
thr_lock_owner_init(&main_lock_id, &lock_info);
+
+ m_internal_handler= NULL;
+}
+
+
+void THD::push_internal_handler(Internal_error_handler *handler)
+{
+ /*
+ TODO: The current implementation is limited to 1 handler at a time only.
+ THD and sp_rcontext need to be modified to use a common handler stack.
+ */
+ DBUG_ASSERT(m_internal_handler == NULL);
+ m_internal_handler= handler;
+}
+
+
+bool THD::handle_error(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level level)
+{
+ if (m_internal_handler)
+ {
+ return m_internal_handler->handle_error(sql_errno, level, this);
+ }
+
+ return FALSE; // 'FALSE', as per coding style
+}
+
+
+void THD::pop_internal_handler()
+{
+ DBUG_ASSERT(m_internal_handler != NULL);
+ m_internal_handler= NULL;
}
@@ -355,6 +388,7 @@ void THD::init(void)
void THD::init_for_queries()
{
+ set_time();
ha_enable_transaction(this,TRUE);
reset_root_defaults(mem_root, variables.query_alloc_block_size,
@@ -399,6 +433,8 @@ void THD::change_user(void)
void THD::cleanup(void)
{
DBUG_ENTER("THD::cleanup");
+ DBUG_ASSERT(cleanup_done == 0);
+
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
if (transaction.xid_state.xa_state == XA_PREPARED)
{
@@ -434,7 +470,6 @@ void THD::cleanup(void)
pthread_mutex_lock(&LOCK_user_locks);
item_user_lock_release(ull);
pthread_mutex_unlock(&LOCK_user_locks);
- ull= 0;
}
cleanup_done=1;
@@ -483,6 +518,7 @@ THD::~THD()
delete rli_fake;
#endif
+ free_root(&main_mem_root, MYF(0));
DBUG_VOID_RETURN;
}
@@ -548,7 +584,9 @@ void THD::awake(THD::killed_state state_to_set)
killed= state_to_set;
if (state_to_set != THD::KILL_QUERY)
{
- thr_alarm_kill(real_id);
+ thr_alarm_kill(thread_id);
+ if (!slave_thread)
+ thread_scheduler.post_kill_notification(this);
#ifdef SIGNAL_WITH_VIO_CLOSE
close_active_vio();
#endif
@@ -599,18 +637,19 @@ bool THD::store_globals()
Assert that thread_stack is initialized: it's necessary to be able
to track stack overrun.
*/
- DBUG_ASSERT(this->thread_stack);
+ DBUG_ASSERT(thread_stack);
if (my_pthread_setspecific_ptr(THR_THD, this) ||
my_pthread_setspecific_ptr(THR_MALLOC, &mem_root))
return 1;
mysys_var=my_thread_var;
- dbug_thread_id=my_thread_id();
/*
- By default 'slave_proxy_id' is 'thread_id'. They may later become different
- if this is the slave SQL thread.
+ Let mysqld define the thread id (not mysys)
+ This allows us to move THD to different threads if needed.
*/
- variables.pseudo_thread_id= thread_id;
+ mysys_var->id= thread_id;
+ real_id= pthread_self(); // For debugging
+
/*
We have to call thr_lock_info_init() again here as THD may have been
created in another thread
@@ -993,6 +1032,7 @@ sql_exchange::sql_exchange(char *name,bool flag)
enclosed= line_start= &my_empty_string;
line_term= &default_line_term;
escaped= &default_escaped;
+ cs= NULL;
}
bool select_send::send_fields(List<Item> &list, uint flags)
@@ -1532,7 +1572,7 @@ bool select_max_min_finder_subselect::send_data(List<Item> &items)
bool select_max_min_finder_subselect::cmp_real()
{
- Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
+ Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
double val1= cache->val_real(), val2= maxmin->val_real();
if (fmax)
return (cache->null_value && !maxmin->null_value) ||
@@ -1545,7 +1585,7 @@ bool select_max_min_finder_subselect::cmp_real()
bool select_max_min_finder_subselect::cmp_int()
{
- Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
+ Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
longlong val1= cache->val_int(), val2= maxmin->val_int();
if (fmax)
return (cache->null_value && !maxmin->null_value) ||
@@ -1558,7 +1598,7 @@ bool select_max_min_finder_subselect::cmp_int()
bool select_max_min_finder_subselect::cmp_decimal()
{
- Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
+ Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
my_decimal cval, *cvalue= cache->val_decimal(&cval);
my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
if (fmax)
@@ -1573,7 +1613,7 @@ bool select_max_min_finder_subselect::cmp_decimal()
bool select_max_min_finder_subselect::cmp_str()
{
String *val1, *val2, buf1, buf2;
- Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
+ Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
/*
as far as both operand is Item_cache buf1 & buf2 will not be used,
but added for safety
@@ -1674,18 +1714,17 @@ void Query_arena::cleanup_stmt()
Statement functions
*/
-Statement::Statement(enum enum_state state_arg, ulong id_arg,
- ulong alloc_block_size, ulong prealloc_size)
- :Query_arena(&main_mem_root, state_arg),
+Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg,
+ enum enum_state state_arg, ulong id_arg)
+ :Query_arena(mem_root_arg, state_arg),
id(id_arg),
mark_used_columns(MARK_COLUMNS_READ),
- lex(&main_lex),
+ lex(lex_arg),
query(0),
query_length(0),
cursor(0)
{
name.str= NULL;
- init_sql_alloc(&main_mem_root, alloc_block_size, prealloc_size);
}
@@ -1727,7 +1766,7 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
void THD::end_statement()
{
- /* Cleanup SQL processing state to resuse this statement in next query. */
+ /* Cleanup SQL processing state to reuse this statement in next query. */
lex_end(lex);
delete lex->result;
lex->result= 0;
@@ -1768,12 +1807,6 @@ void THD::restore_active_arena(Query_arena *set, Query_arena *backup)
Statement::~Statement()
{
- /*
- We must free `main_mem_root', not `mem_root' (pointer), to work
- correctly if this statement is used as a backup statement,
- for which `mem_root' may point to some other statement.
- */
- free_root(&main_mem_root, MYF(0));
}
C_MODE_START
@@ -2154,7 +2187,12 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup,
!current_stmt_binlog_row_based)
{
options&= ~OPTION_BIN_LOG;
- }
+ }
+
+ if ((backup->options & OPTION_BIN_LOG) && is_update_query(lex->sql_command)&&
+ !current_stmt_binlog_row_based)
+ mysql_bin_log.start_union_events(this, this->query_id);
+
/* Disable result sets */
client_capabilities &= ~CLIENT_MULTI_RESULTS;
in_sub_stmt|= new_state;
@@ -2198,6 +2236,10 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
sent_row_count= backup->sent_row_count;
client_capabilities= backup->client_capabilities;
+ if ((options & OPTION_BIN_LOG) && is_update_query(lex->sql_command) &&
+ !current_stmt_binlog_row_based)
+ mysql_bin_log.stop_union_events(this);
+
/*
The following is added to the old values as we are interested in the
total complexity of the query
@@ -2407,11 +2449,12 @@ THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
my_size_t colcnt, my_size_t, bool,
Update_rows_log_event *);
#endif
+
+#ifdef NOT_USED
static char const*
field_type_name(enum_field_types type)
{
- switch (type)
- {
+ switch (type) {
case MYSQL_TYPE_DECIMAL:
return "MYSQL_TYPE_DECIMAL";
case MYSQL_TYPE_TINY:
@@ -2469,6 +2512,7 @@ field_type_name(enum_field_types type)
}
return "Unknown";
}
+#endif
my_size_t THD::max_row_length_blob(TABLE *table, const byte *data) const
@@ -2507,7 +2551,7 @@ my_size_t THD::pack_row(TABLE *table, MY_BITMAP const* cols, byte *row_data,
if (bitmap_is_set(cols,i))
{
my_ptrdiff_t const offset=
- field->is_null(rec_offset) ? def_offset : rec_offset;
+ field->is_null((uint) rec_offset) ? def_offset : rec_offset;
field->move_field_offset(offset);
ptr= (byte*)field->pack((char *) ptr, field->ptr);
field->move_field_offset(-offset);
@@ -2549,7 +2593,7 @@ namespace {
: m_memory(0)
{
#ifndef DBUG_OFF
- m_alloc_checked= false;
+ m_alloc_checked= FALSE;
#endif
allocate_memory(table, len1);
m_ptr[0]= has_memory() ? m_memory : 0;
@@ -2560,7 +2604,7 @@ namespace {
: m_memory(0)
{
#ifndef DBUG_OFF
- m_alloc_checked= false;
+ m_alloc_checked= FALSE;
#endif
allocate_memory(table, len1 + len2);
m_ptr[0]= has_memory() ? m_memory : 0;
@@ -2581,7 +2625,7 @@ namespace {
*/
bool has_memory() const {
#ifndef DBUG_OFF
- m_alloc_checked= true;
+ m_alloc_checked= TRUE;
#endif
return m_memory != 0;
}
@@ -2590,7 +2634,7 @@ namespace {
{
DBUG_ASSERT(s < sizeof(m_ptr)/sizeof(*m_ptr));
DBUG_ASSERT(m_ptr[s] != 0);
- DBUG_ASSERT(m_alloc_checked == true);
+ DBUG_ASSERT(m_alloc_checked == TRUE);
return m_ptr[s];
}
@@ -2620,12 +2664,12 @@ namespace {
table->write_row_record=
(byte *) alloc_root(&table->mem_root, 2 * maxlen);
m_memory= table->write_row_record;
- m_release_memory_on_destruction= false;
+ m_release_memory_on_destruction= FALSE;
}
else
{
m_memory= (byte *) my_malloc(total_length, MYF(MY_WME));
- m_release_memory_on_destruction= true;
+ m_release_memory_on_destruction= TRUE;
}
}
@@ -2649,8 +2693,6 @@ int THD::binlog_write_row(TABLE* table, bool is_trans,
Pack records into format for transfer. We are allocating more
memory than needed, but that doesn't matter.
*/
- int error= 0;
-
Row_data_memory memory(table, max_row_length(table, record));
if (!memory.has_memory())
return HA_ERR_OUT_OF_MEM;
@@ -2677,7 +2719,6 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
{
DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
- int error= 0;
my_size_t const before_maxlen = max_row_length(table, before_record);
my_size_t const after_maxlen = max_row_length(table, after_record);
@@ -2727,8 +2768,6 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
Pack records into format for transfer. We are allocating more
memory than needed, but that doesn't matter.
*/
- int error= 0;
-
Row_data_memory memory(table, max_row_length(table, record));
if (unlikely(!memory.has_memory()))
return HA_ERR_OUT_OF_MEM;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index e73806d75fa..f492db82ec7 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -214,7 +214,7 @@ struct system_variables
ulong read_rnd_buff_size;
ulong div_precincrement;
ulong sortbuff_size;
- handlerton *table_type;
+ ulong thread_handling;
ulong tx_isolation;
ulong completion_type;
/* Determines which non-standard SQL behaviour should be enabled */
@@ -231,11 +231,15 @@ struct system_variables
ulong trans_prealloc_size;
ulong log_warnings;
ulong group_concat_max_len;
+ ulong ndb_autoincrement_prefetch_sz;
+ ulong ndb_index_stat_cache_entries;
+ ulong ndb_index_stat_update_freq;
+ ulong binlog_format; // binlog format for this thd (see enum_binlog_format)
/*
In slave thread we need to know in behalf of which
thread the query is being run to replicate temp tables properly
*/
- ulong pseudo_thread_id;
+ my_thread_id pseudo_thread_id;
my_bool low_priority_updates;
my_bool new_mode;
@@ -248,14 +252,12 @@ struct system_variables
my_bool ndb_use_exact_count;
my_bool ndb_use_transactions;
my_bool ndb_index_stat_enable;
- ulong ndb_autoincrement_prefetch_sz;
- ulong ndb_index_stat_cache_entries;
- ulong ndb_index_stat_update_freq;
- ulong binlog_format; // binlog format for this thd (see enum_binlog_format)
my_bool old_alter_table;
my_bool old_passwords;
+ handlerton *table_type;
+
/* Only charset part of these variables is sensible */
CHARSET_INFO *character_set_filesystem;
CHARSET_INFO *character_set_client;
@@ -450,8 +452,10 @@ public:
class Server_side_cursor;
-/*
- State of a single command executed against this connection.
+/**
+ @class Statement
+ @brief State of a single command executed against this connection.
+
One connection can contain a lot of simultaneously running statements,
some of which could be:
- prepared, that is, contain placeholders,
@@ -469,10 +473,6 @@ class Statement: public ilink, public Query_arena
Statement(const Statement &rhs); /* not implemented: */
Statement &operator=(const Statement &rhs); /* non-copyable */
public:
- /* FIXME: these must be protected */
- MEM_ROOT main_mem_root;
- LEX main_lex;
-
/*
Uniquely identifies each statement object in thread scope; change during
statement lifetime. FIXME: must be const
@@ -523,10 +523,10 @@ public:
public:
/* This constructor is called for backup statements */
- Statement() { clear_alloc_root(&main_mem_root); }
+ Statement() {}
- Statement(enum enum_state state_arg, ulong id_arg,
- ulong alloc_block_size, ulong prealloc_size);
+ Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg,
+ enum enum_state state_arg, ulong id_arg);
virtual ~Statement();
/* Assign execution context (note: not all members) of given stmt to self */
@@ -538,7 +538,7 @@ public:
};
-/*
+/**
Container for all statements created/used in a connection.
Statements in Statement_map have unique Statement::id (guaranteed by id
assignment in Statement::Statement)
@@ -618,6 +618,10 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state);
bool xid_cache_insert(XID_STATE *xid_state);
void xid_cache_delete(XID_STATE *xid_state);
+/**
+ @class Security_context
+ @brief A set of THD members describing the current authenticated user.
+*/
class Security_context {
public:
@@ -649,7 +653,7 @@ public:
};
-/*
+/**
A registry for item tree transformations performed during
query optimization. We register only those changes which require
a rollback to re-execute a prepared statement or stored procedure
@@ -660,7 +664,7 @@ struct Item_change_record;
typedef I_List<Item_change_record> Item_change_list;
-/*
+/**
Type of prelocked mode.
See comment for THD::prelocked_mode for complete description.
*/
@@ -669,7 +673,7 @@ enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
PRELOCKED_UNDER_LOCK_TABLES= 2};
-/*
+/**
Class that holds information about tables which were opened and locked
by the thread. It is also used to save/restore this information in
push_open_tables_state()/pop_open_tables_state().
@@ -772,14 +776,17 @@ public:
}
};
-
-/* class to save context when executing a function or trigger */
+/**
+ @class Sub_statement_state
+ @brief Used to save context when executing a function or trigger
+*/
/* Defines used for Sub_statement_state::in_sub_stmt */
#define SUB_STMT_TRIGGER 1
#define SUB_STMT_FUNCTION 2
+
class Sub_statement_state
{
public:
@@ -811,7 +818,51 @@ enum enum_thread_type
};
-/*
+/**
+ This class represents the interface for internal error handlers.
+ Internal error handlers are exception handlers used by the server
+ implementation.
+*/
+class Internal_error_handler
+{
+protected:
+ Internal_error_handler() {}
+ virtual ~Internal_error_handler() {}
+
+public:
+ /**
+ Handle an error condition.
+ This method can be implemented by a subclass to achieve any of the
+ following:
+ - mask an error internally, prevent exposing it to the user,
+ - mask an error and throw another one instead.
+ When this method returns true, the error condition is considered
+ 'handled', and will not be propagated to upper layers.
+ It is the responsability of the code installing an internal handler
+ to then check for trapped conditions, and implement logic to recover
+ from the anticipated conditions trapped during runtime.
+
+ This mechanism is similar to C++ try/throw/catch:
+ - 'try' correspond to <code>THD::push_internal_handler()</code>,
+ - 'throw' correspond to <code>my_error()</code>,
+ which invokes <code>my_message_sql()</code>,
+ - 'catch' correspond to checking how/if an internal handler was invoked,
+ before removing it from the exception stack with
+ <code>THD::pop_internal_handler()</code>.
+
+ @param sql_errno the error number
+ @param level the error level
+ @param thd the calling thread
+ @return true if the error is handled
+ */
+ virtual bool handle_error(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd) = 0;
+};
+
+
+/**
+ @class THD
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
*/
@@ -1064,7 +1115,7 @@ public:
} transaction;
Field *dup_field;
#ifndef __WIN__
- sigset_t signals,block_signals;
+ sigset_t signals;
#endif
#ifdef SIGNAL_WITH_VIO_CLOSE
Vio* active_vio;
@@ -1255,7 +1306,7 @@ public:
update auto-updatable fields (like auto_increment and timestamp).
*/
query_id_t query_id, warn_id;
- ulong thread_id, col_access;
+ ulong col_access;
#ifdef ERROR_INJECT_SUPPORT
ulong error_inject_value;
@@ -1264,8 +1315,8 @@ public:
ulong statement_id_counter;
ulong rand_saved_seed1, rand_saved_seed2;
ulong row_count; // Row counter, mainly for errors and warnings
- long dbug_thread_id;
- pthread_t real_id;
+ pthread_t real_id; /* For debugging */
+ my_thread_id thread_id;
uint tmp_table, global_read_lock;
uint server_status,open_options;
enum enum_thread_type system_thread;
@@ -1629,6 +1680,48 @@ public:
*p_db_length= db_length;
return FALSE;
}
+ thd_scheduler scheduler;
+
+public:
+ /**
+ Add an internal error handler to the thread execution context.
+ @param handler the exception handler to add
+ */
+ void push_internal_handler(Internal_error_handler *handler);
+
+ /**
+ Handle an error condition.
+ @param sql_errno the error number
+ @param level the error level
+ @return true if the error is handled
+ */
+ virtual bool handle_error(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level level);
+
+ /**
+ Remove the error handler last pushed.
+ */
+ void pop_internal_handler();
+
+private:
+ /** The current internal error handler for this thread, or NULL. */
+ Internal_error_handler *m_internal_handler;
+ /**
+ The lex to hold the parsed tree of conventional (non-prepared) queries.
+ Whereas for prepared and stored procedure statements we use an own lex
+ instance for each new query, for conventional statements we reuse
+ the same lex. (@see mysql_parse for details).
+ */
+ LEX main_lex;
+ /**
+ This memory root is used for two purposes:
+ - for conventional queries, to allocate structures stored in main_lex
+ during parsing, and allocate runtime data (execution plan, etc.)
+ during execution.
+ - for prepared queries, only to allocate runtime data. The parsed
+ tree itself is reused between executions and thus is stored elsewhere.
+ */
+ MEM_ROOT main_mem_root;
};
@@ -1653,6 +1746,7 @@ public:
bool opt_enclosed;
bool dumpfile;
ulong skip_lines;
+ CHARSET_INFO *cs;
sql_exchange(char *name,bool dumpfile_flag);
};
@@ -1811,13 +1905,13 @@ class select_create: public select_insert {
HA_CREATE_INFO *create_info;
Field **field;
public:
- select_create (TABLE_LIST *table,
+ select_create (TABLE_LIST *table_arg,
HA_CREATE_INFO *create_info_par,
List<create_field> &fields_par,
List<Key> &keys_par,
List<Item> &select_fields,enum_duplicates duplic, bool ignore)
:select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore),
- create_table(table), extra_fields(&fields_par),keys(&keys_par),
+ create_table(table_arg), extra_fields(&fields_par),keys(&keys_par),
create_info(create_info_par)
{}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
@@ -1929,7 +2023,9 @@ public:
class select_singlerow_subselect :public select_subselect
{
public:
- select_singlerow_subselect(Item_subselect *item):select_subselect(item){}
+ select_singlerow_subselect(Item_subselect *item_arg)
+ :select_subselect(item_arg)
+ {}
bool send_data(List<Item> &items);
};
@@ -1940,8 +2036,8 @@ class select_max_min_finder_subselect :public select_subselect
bool (select_max_min_finder_subselect::*op)();
bool fmax;
public:
- select_max_min_finder_subselect(Item_subselect *item, bool mx)
- :select_subselect(item), cache(0), fmax(mx)
+ select_max_min_finder_subselect(Item_subselect *item_arg, bool mx)
+ :select_subselect(item_arg), cache(0), fmax(mx)
{}
void cleanup();
bool send_data(List<Item> &items);
@@ -1955,7 +2051,8 @@ public:
class select_exists_subselect :public select_subselect
{
public:
- select_exists_subselect(Item_subselect *item):select_subselect(item){}
+ select_exists_subselect(Item_subselect *item_arg)
+ :select_subselect(item_arg){}
bool send_data(List<Item> &items);
};
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
new file mode 100644
index 00000000000..09ee4962235
--- /dev/null
+++ b/sql/sql_connect.cc
@@ -0,0 +1,1108 @@
+/* Copyright (C) 2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/*
+ Functions to autenticate and handle reqests for a connection
+*/
+
+#include "mysql_priv.h"
+
+#ifdef HAVE_OPENSSL
+/*
+ Without SSL the handshake consists of one packet. This packet
+ has both client capabilites and scrambled password.
+ With SSL the handshake might consist of two packets. If the first
+ packet (client capabilities) has CLIENT_SSL flag set, we have to
+ switch to SSL and read the second packet. The scrambled password
+ is in the second packet and client_capabilites field will be ignored.
+ Maybe it is better to accept flags other than CLIENT_SSL from the
+ second packet?
+*/
+#define SSL_HANDSHAKE_SIZE 2
+#define NORMAL_HANDSHAKE_SIZE 6
+#define MIN_HANDSHAKE_SIZE 2
+#else
+#define MIN_HANDSHAKE_SIZE 6
+#endif /* HAVE_OPENSSL */
+
+#ifdef __WIN__
+static void test_signal(int sig_ptr)
+{
+#if !defined( DBUG_OFF)
+ MessageBox(NULL,"Test signal","DBUG",MB_OK);
+#endif
+#if defined(OS2)
+ fprintf(stderr, "Test signal %d\n", sig_ptr);
+ fflush(stderr);
+#endif
+}
+static void init_signals(void)
+{
+ int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
+ for (int i=0 ; i < 7 ; i++)
+ signal( signals[i], test_signal) ;
+}
+#endif
+
+/*
+ Get structure for logging connection data for the current user
+*/
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+static HASH hash_user_connections;
+
+static int get_or_create_user_conn(THD *thd, const char *user,
+ const char *host,
+ USER_RESOURCES *mqh)
+{
+ int return_val= 0;
+ uint temp_len, user_len;
+ char temp_user[USER_HOST_BUFF_SIZE];
+ struct user_conn *uc;
+
+ DBUG_ASSERT(user != 0);
+ DBUG_ASSERT(host != 0);
+
+ user_len= strlen(user);
+ temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ if (!(uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (byte*) temp_user, temp_len)))
+ {
+ /* First connection for user; Create a user connection object */
+ if (!(uc= ((struct user_conn*)
+ my_malloc(sizeof(struct user_conn) + temp_len+1,
+ MYF(MY_WME)))))
+ {
+ net_send_error(thd, 0, NullS); // Out of memory
+ return_val= 1;
+ goto end;
+ }
+ uc->user=(char*) (uc+1);
+ memcpy(uc->user,temp_user,temp_len+1);
+ uc->host= uc->user + user_len + 1;
+ uc->len= temp_len;
+ uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
+ uc->user_resources= *mqh;
+ uc->intime= thd->thr_create_time;
+ if (my_hash_insert(&hash_user_connections, (byte*) uc))
+ {
+ my_free((char*) uc,0);
+ net_send_error(thd, 0, NullS); // Out of memory
+ return_val= 1;
+ goto end;
+ }
+ }
+ thd->user_connect=uc;
+ uc->connections++;
+end:
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ return return_val;
+
+}
+
+
+/*
+ check if user has already too many connections
+
+ SYNOPSIS
+ check_for_max_user_connections()
+ thd Thread handle
+ uc User connect object
+
+ NOTES
+ If check fails, we decrease user connection count, which means one
+ shouldn't call decrease_user_connections() after this function.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+int check_for_max_user_connections(THD *thd, USER_CONN *uc)
+{
+ int error=0;
+ DBUG_ENTER("check_for_max_user_connections");
+
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ if (max_user_connections && !uc->user_resources.user_conn &&
+ max_user_connections < (uint) uc->connections)
+ {
+ net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
+ error=1;
+ goto end;
+ }
+ time_out_user_resource_limits(thd, uc);
+ if (uc->user_resources.user_conn &&
+ uc->user_resources.user_conn < uc->connections)
+ {
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
+ "max_user_connections",
+ (long) uc->user_resources.user_conn);
+ error= 1;
+ goto end;
+ }
+ if (uc->user_resources.conn_per_hour &&
+ uc->user_resources.conn_per_hour <= uc->conn_per_hour)
+ {
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
+ "max_connections_per_hour",
+ (long) uc->user_resources.conn_per_hour);
+ error=1;
+ goto end;
+ }
+ uc->conn_per_hour++;
+
+ end:
+ if (error)
+ uc->connections--; // no need for decrease_user_connections() here
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Decrease user connection count
+
+ SYNOPSIS
+ decrease_user_connections()
+ uc User connection object
+
+ NOTES
+ If there is a n user connection object for a connection
+ (which only happens if 'max_user_connections' is defined or
+ if someone has created a resource grant for a user), then
+ the connection count is always incremented on connect.
+
+ The user connect object is not freed if some users has
+ 'max connections per hour' defined as we need to be able to hold
+ count over the lifetime of the connection.
+*/
+
+void decrease_user_connections(USER_CONN *uc)
+{
+ DBUG_ENTER("decrease_user_connections");
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ DBUG_ASSERT(uc->connections);
+ if (!--uc->connections && !mqh_used)
+ {
+ /* Last connection for user; Delete it */
+ (void) hash_delete(&hash_user_connections,(byte*) uc);
+ }
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Reset per-hour user resource limits when it has been more than
+ an hour since they were last checked
+
+ SYNOPSIS:
+ time_out_user_resource_limits()
+ thd Thread handler
+ uc User connection details
+
+ NOTE:
+ This assumes that the LOCK_user_conn mutex has been acquired, so it is
+ safe to test and modify members of the USER_CONN structure.
+*/
+
+void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
+{
+ time_t check_time = thd->start_time ? thd->start_time : time(NULL);
+ DBUG_ENTER("time_out_user_resource_limits");
+
+ /* If more than a hour since last check, reset resource checking */
+ if (check_time - uc->intime >= 3600)
+ {
+ uc->questions=1;
+ uc->updates=0;
+ uc->conn_per_hour=0;
+ uc->intime=check_time;
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Check if maximum queries per hour limit has been reached
+ returns 0 if OK.
+*/
+
+bool check_mqh(THD *thd, uint check_command)
+{
+ bool error= 0;
+ USER_CONN *uc=thd->user_connect;
+ DBUG_ENTER("check_mqh");
+ DBUG_ASSERT(uc != 0);
+
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+
+ time_out_user_resource_limits(thd, uc);
+
+ /* Check that we have not done too many questions / hour */
+ if (uc->user_resources.questions &&
+ uc->questions++ >= uc->user_resources.questions)
+ {
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
+ (long) uc->user_resources.questions);
+ error=1;
+ goto end;
+ }
+ if (check_command < (uint) SQLCOM_END)
+ {
+ /* Check that we have not done too many updates / hour */
+ if (uc->user_resources.updates &&
+ (sql_command_flags[check_command] & CF_CHANGES_DATA) &&
+ uc->updates++ >= uc->user_resources.updates)
+ {
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
+ (long) uc->user_resources.updates);
+ error=1;
+ goto end;
+ }
+ }
+end:
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ DBUG_RETURN(error);
+}
+
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+
+
+/*
+ Check if user exist and password supplied is correct.
+
+ SYNOPSIS
+ check_user()
+ thd thread handle, thd->security_ctx->{host,user,ip} are used
+ command originator of the check: now check_user is called
+ during connect and change user procedures; used for
+ logging.
+ passwd scrambled password received from client
+ passwd_len length of scrambled password
+ db database name to connect to, may be NULL
+ check_count dont know exactly
+
+ Note, that host, user and passwd may point to communication buffer.
+ Current implementation does not depend on that, but future changes
+ should be done with this in mind; 'thd' is INOUT, all other params
+ are 'IN'.
+
+ RETURN VALUE
+ 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and
+ thd->db are updated; OK is sent to client;
+ -1 access denied or handshake error; error is sent to client;
+ >0 error, not sent to client
+*/
+
+int check_user(THD *thd, enum enum_server_command command,
+ const char *passwd, uint passwd_len, const char *db,
+ bool check_count)
+{
+ DBUG_ENTER("check_user");
+
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+ thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights
+ /* Change database if necessary */
+ if (db && db[0])
+ {
+ /*
+ thd->db is saved in caller and needs to be freed by caller if this
+ function returns 0
+ */
+ thd->reset_db(NULL, 0);
+ if (mysql_change_db(thd, db, FALSE))
+ {
+ /* Send the error to the client */
+ net_send_error(thd);
+ DBUG_RETURN(-1);
+ }
+ }
+ send_ok(thd);
+ DBUG_RETURN(0);
+#else
+
+ my_bool opt_secure_auth_local;
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ opt_secure_auth_local= opt_secure_auth;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+
+ /*
+ If the server is running in secure auth mode, short scrambles are
+ forbidden.
+ */
+ if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
+ {
+ net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ DBUG_RETURN(-1);
+ }
+ if (passwd_len != 0 &&
+ passwd_len != SCRAMBLE_LENGTH &&
+ passwd_len != SCRAMBLE_LENGTH_323)
+ DBUG_RETURN(ER_HANDSHAKE_ERROR);
+
+ /*
+ Clear thd->db as it points to something, that will be freed when
+ connection is closed. We don't want to accidentally free a wrong pointer
+ if connect failed. Also in case of 'CHANGE USER' failure, current
+ database will be switched to 'no database selected'.
+ */
+ thd->reset_db(NULL, 0);
+
+ USER_RESOURCES ur;
+ int res= acl_getroot(thd, &ur, passwd, passwd_len);
+#ifndef EMBEDDED_LIBRARY
+ if (res == -1)
+ {
+ /*
+ This happens when client (new) sends password scrambled with
+ scramble(), but database holds old value (scrambled with
+ scramble_323()). Here we please client to send scrambled_password
+ in old format.
+ */
+ NET *net= &thd->net;
+ if (opt_secure_auth_local)
+ {
+ net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip);
+ general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip);
+ DBUG_RETURN(-1);
+ }
+ /* We have to read very specific packet size */
+ if (send_old_password_request(thd) ||
+ my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ DBUG_RETURN(ER_HANDSHAKE_ERROR);
+ }
+ /* Final attempt to check the user based on reply */
+ /* So as passwd is short, errcode is always >= 0 */
+ res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
+ }
+#endif /*EMBEDDED_LIBRARY*/
+ /* here res is always >= 0 */
+ if (res == 0)
+ {
+ if (!(thd->main_security_ctx.master_access &
+ NO_ACCESS)) // authentication is OK
+ {
+ DBUG_PRINT("info",
+ ("Capabilities: %lu packet_length: %ld Host: '%s' "
+ "Login user: '%s' Priv_user: '%s' Using password: %s "
+ "Access: %lu db: '%s'",
+ thd->client_capabilities,
+ thd->max_client_packet_length,
+ thd->main_security_ctx.host_or_ip,
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.priv_user,
+ passwd_len ? "yes": "no",
+ thd->main_security_ctx.master_access,
+ (thd->db ? thd->db : "*none*")));
+
+ if (check_count)
+ {
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ bool count_ok= thread_count <= max_connections + delayed_insert_threads
+ || (thd->main_security_ctx.master_access & SUPER_ACL);
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ if (!count_ok)
+ { // too many connections
+ net_send_error(thd, ER_CON_COUNT_ERROR);
+ DBUG_RETURN(-1);
+ }
+ }
+
+ /*
+ Log the command before authentication checks, so that the user can
+ check the log for the tried login tried and also to detect
+ break-in attempts.
+ */
+ general_log_print(thd, command,
+ (thd->main_security_ctx.priv_user ==
+ thd->main_security_ctx.user ?
+ (char*) "%s@%s on %s" :
+ (char*) "%s@%s as anonymous on %s"),
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip,
+ db ? db : (char*) "");
+
+ /*
+ This is the default access rights for the current database. It's
+ set to 0 here because we don't have an active database yet (and we
+ may not have an active database to set.
+ */
+ thd->main_security_ctx.db_access=0;
+
+ /* Don't allow user to connect if he has done too many queries */
+ if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
+ max_user_connections) &&
+ get_or_create_user_conn(thd,
+ (opt_old_style_user_limits ? thd->main_security_ctx.user :
+ thd->main_security_ctx.priv_user),
+ (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
+ thd->main_security_ctx.priv_host),
+ &ur))
+ DBUG_RETURN(-1);
+ if (thd->user_connect &&
+ (thd->user_connect->user_resources.conn_per_hour ||
+ thd->user_connect->user_resources.user_conn ||
+ max_user_connections) &&
+ check_for_max_user_connections(thd, thd->user_connect))
+ DBUG_RETURN(-1);
+
+ /* Change database if necessary */
+ if (db && db[0])
+ {
+ if (mysql_change_db(thd, db, FALSE))
+ {
+ /* Send error to the client */
+ net_send_error(thd);
+ if (thd->user_connect)
+ decrease_user_connections(thd->user_connect);
+ DBUG_RETURN(-1);
+ }
+ }
+ send_ok(thd);
+ thd->password= test(passwd_len); // remember for error messages
+ /* Ready to handle queries */
+ DBUG_RETURN(0);
+ }
+ }
+ else if (res == 2) // client gave short hash, server has long hash
+ {
+ net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ DBUG_RETURN(-1);
+ }
+ net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip,
+ passwd_len ? ER(ER_YES) : ER(ER_NO));
+ general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip,
+ passwd_len ? ER(ER_YES) : ER(ER_NO));
+ DBUG_RETURN(-1);
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+}
+
+
+/*
+ Check for maximum allowable user connections, if the mysqld server is
+ started with corresponding variable that is greater then 0.
+*/
+
+extern "C" byte *get_key_conn(user_conn *buff, uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=buff->len;
+ return (byte*) buff->user;
+}
+
+
+extern "C" void free_user(struct user_conn *uc)
+{
+ my_free((char*) uc,MYF(0));
+}
+
+
+void init_max_user_conn(void)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
+ 0,0,
+ (hash_get_key) get_key_conn, (hash_free_key) free_user,
+ 0);
+#endif
+}
+
+
+void free_max_user_conn(void)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ hash_free(&hash_user_connections);
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+}
+
+
+void reset_mqh(LEX_USER *lu, bool get_them= 0)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ if (lu) // for GRANT
+ {
+ USER_CONN *uc;
+ uint temp_len=lu->user.length+lu->host.length+2;
+ char temp_user[USER_HOST_BUFF_SIZE];
+
+ memcpy(temp_user,lu->user.str,lu->user.length);
+ memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
+ temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
+ if ((uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (byte*) temp_user, temp_len)))
+ {
+ uc->questions=0;
+ get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
+ uc->updates=0;
+ uc->conn_per_hour=0;
+ }
+ }
+ else
+ {
+ /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
+ for (uint idx=0;idx < hash_user_connections.records; idx++)
+ {
+ USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
+ idx);
+ if (get_them)
+ get_mqh(uc->user,uc->host,uc);
+ uc->questions=0;
+ uc->updates=0;
+ uc->conn_per_hour=0;
+ }
+ }
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+}
+
+
+void thd_init_client_charset(THD *thd, uint cs_number)
+{
+ /*
+ Use server character set and collation if
+ - opt_character_set_client_handshake is not set
+ - client has not specified a character set
+ - client character set is the same as the servers
+ - client character set doesn't exists in server
+ */
+ if (!opt_character_set_client_handshake ||
+ !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
+ !my_strcasecmp(&my_charset_latin1,
+ global_system_variables.character_set_client->name,
+ thd->variables.character_set_client->name))
+ {
+ thd->variables.character_set_client=
+ global_system_variables.character_set_client;
+ thd->variables.collation_connection=
+ global_system_variables.collation_connection;
+ thd->variables.character_set_results=
+ global_system_variables.character_set_results;
+ }
+ else
+ {
+ thd->variables.character_set_results=
+ thd->variables.collation_connection=
+ thd->variables.character_set_client;
+ }
+}
+
+
+/*
+ Initialize connection threads
+*/
+
+bool init_new_connection_handler_thread()
+{
+ pthread_detach_this_thread();
+#if defined(__WIN__)
+ init_signals();
+#else
+ /* Win32 calls this in pthread_create */
+ if (my_thread_init())
+ return 1;
+#endif /* __WIN__ */
+ return 0;
+}
+
+/*
+ Perform handshake, authorize client and update thd ACL variables.
+
+ SYNOPSIS
+ check_connection()
+ thd thread handle
+
+ RETURN
+ 0 success, OK is sent to user, thd is updated.
+ -1 error, which is sent to user
+ > 0 error code (not sent to user)
+*/
+
+#ifndef EMBEDDED_LIBRARY
+static int check_connection(THD *thd)
+{
+ uint connect_errors= 0;
+ NET *net= &thd->net;
+ ulong pkt_len= 0;
+ char *end;
+
+ DBUG_PRINT("info",
+ ("New connection received on %s", vio_description(net->vio)));
+#ifdef SIGNAL_WITH_VIO_CLOSE
+ thd->set_active_vio(net->vio);
+#endif
+
+ if (!thd->main_security_ctx.host) // If TCP/IP connection
+ {
+ char ip[30];
+
+ if (vio_peer_addr(net->vio, ip, &thd->peer_port))
+ return (ER_BAD_HOST_ERROR);
+ if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
+ return (ER_OUT_OF_RESOURCES);
+ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
+ vio_in_addr(net->vio,&thd->remote.sin_addr);
+ if (!(specialflag & SPECIAL_NO_RESOLVE))
+ {
+ vio_in_addr(net->vio,&thd->remote.sin_addr);
+ thd->main_security_ctx.host=
+ ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
+ /* Cut very long hostnames to avoid possible overflows */
+ if (thd->main_security_ctx.host)
+ {
+ if (thd->main_security_ctx.host != my_localhost)
+ thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
+ HOSTNAME_LENGTH)]= 0;
+ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
+ }
+ if (connect_errors > max_connect_errors)
+ return(ER_HOST_IS_BLOCKED);
+ }
+ DBUG_PRINT("info",("Host: %s ip: %s",
+ (thd->main_security_ctx.host ?
+ thd->main_security_ctx.host : "unknown host"),
+ (thd->main_security_ctx.ip ?
+ thd->main_security_ctx.ip : "unknown ip")));
+ if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
+ return(ER_HOST_NOT_PRIVILEGED);
+ }
+ else /* Hostname given means that the connection was on a socket */
+ {
+ DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
+ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
+ thd->main_security_ctx.ip= 0;
+ /* Reset sin_addr */
+ bzero((char*) &thd->remote, sizeof(thd->remote));
+ }
+ vio_keepalive(net->vio, TRUE);
+ {
+ /* buff[] needs to big enough to hold the server_version variable */
+ char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
+ ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
+ CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
+
+ if (opt_using_transactions)
+ client_flags|=CLIENT_TRANSACTIONS;
+#ifdef HAVE_COMPRESS
+ client_flags |= CLIENT_COMPRESS;
+#endif /* HAVE_COMPRESS */
+#ifdef HAVE_OPENSSL
+ if (ssl_acceptor_fd)
+ client_flags |= CLIENT_SSL; /* Wow, SSL is available! */
+#endif /* HAVE_OPENSSL */
+
+ end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
+ int4store((uchar*) end, thd->thread_id);
+ end+= 4;
+ /*
+ So as check_connection is the only entry point to authorization
+ procedure, scramble is set here. This gives us new scramble for
+ each handshake.
+ */
+ create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
+ /*
+ Old clients does not understand long scrambles, but can ignore packet
+ tail: that's why first part of the scramble is placed here, and second
+ part at the end of packet.
+ */
+ end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
+
+ int2store(end, client_flags);
+ /* write server characteristics: up to 16 bytes allowed */
+ end[2]=(char) default_charset_info->number;
+ int2store(end+3, thd->server_status);
+ bzero(end+5, 13);
+ end+= 18;
+ /* write scramble tail */
+ end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323,
+ SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
+
+ /* At this point we write connection message and read reply */
+ if (net_write_command(net, (uchar) protocol_version, "", 0, buff,
+ (uint) (end-buff)) ||
+ (pkt_len= my_net_read(net)) == packet_error ||
+ pkt_len < MIN_HANDSHAKE_SIZE)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+ }
+#ifdef _CUSTOMCONFIG_
+#include "_cust_sql_parse.h"
+#endif
+ if (connect_errors)
+ reset_host_errors(&thd->remote.sin_addr);
+ if (thd->packet.alloc(thd->variables.net_buffer_length))
+ return(ER_OUT_OF_RESOURCES);
+
+ thd->client_capabilities=uint2korr(net->read_pos);
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
+ {
+ thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
+ thd->max_client_packet_length= uint4korr(net->read_pos+4);
+ DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
+ thd_init_client_charset(thd, (uint) net->read_pos[8]);
+ thd->update_charset();
+ end= (char*) net->read_pos+32;
+ }
+ else
+ {
+ thd->max_client_packet_length= uint3korr(net->read_pos+2);
+ end= (char*) net->read_pos+5;
+ }
+
+ if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
+ thd->variables.sql_mode|= MODE_IGNORE_SPACE;
+#ifdef HAVE_OPENSSL
+ DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
+ if (thd->client_capabilities & CLIENT_SSL)
+ {
+ /* Do the SSL layering. */
+ if (!ssl_acceptor_fd)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+ DBUG_PRINT("info", ("IO layer change in progress..."));
+ if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout))
+ {
+ DBUG_PRINT("error", ("Failed to accept new SSL connection"));
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+ DBUG_PRINT("info", ("Reading user information over SSL layer"));
+ if ((pkt_len= my_net_read(net)) == packet_error ||
+ pkt_len < NORMAL_HANDSHAKE_SIZE)
+ {
+ DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
+ pkt_len));
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+ }
+#endif /* HAVE_OPENSSL */
+
+ if (end >= (char*) net->read_pos+ pkt_len +2)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+
+ if (thd->client_capabilities & CLIENT_INTERACTIVE)
+ thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
+ if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
+ opt_using_transactions)
+ net->return_status= &thd->server_status;
+
+ char *user= end;
+ char *passwd= strend(user)+1;
+ uint user_len= passwd - user - 1;
+ char *db= passwd;
+ char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
+ char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
+ uint dummy_errors;
+
+ /*
+ Old clients send null-terminated string as password; new clients send
+ the size (1 byte) + string (not null-terminated). Hence in case of empty
+ password both send '\0'.
+
+ This strlen() can't be easily deleted without changing protocol.
+ */
+ uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
+ *passwd++ : strlen(passwd);
+ db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
+ db + passwd_len + 1 : 0;
+ /* strlen() can't be easily deleted without changing protocol */
+ uint db_len= db ? strlen(db) : 0;
+
+ if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return ER_HANDSHAKE_ERROR;
+ }
+
+ /* Since 4.1 all database names are stored in utf8 */
+ if (db)
+ {
+ db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
+ system_charset_info,
+ db, db_len,
+ thd->charset(), &dummy_errors)]= 0;
+ db= db_buff;
+ }
+
+ user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
+ system_charset_info, user, user_len,
+ thd->charset(), &dummy_errors)]= '\0';
+ user= user_buff;
+
+ /* If username starts and ends in "'", chop them off */
+ if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
+ {
+ user[user_len-1]= 0;
+ user++;
+ user_len-= 2;
+ }
+
+ if (thd->main_security_ctx.user)
+ x_free(thd->main_security_ctx.user);
+ if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0))))
+ return (ER_OUT_OF_RESOURCES);
+ return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
+}
+
+
+/*
+ Setup thread to be used with the current thread
+
+ SYNOPSIS
+ bool setup_connection_thread_globals()
+ thd Thread/connection handler
+
+ RETURN
+ 0 ok
+ 1 Error (out of memory)
+ In this case we will close the connection and increment status
+*/
+
+bool setup_connection_thread_globals(THD *thd)
+{
+ if (thd->store_globals())
+ {
+ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
+ statistic_increment(aborted_connects,&LOCK_status);
+ thread_scheduler.end_thread(thd, 0);
+ return 1; // Error
+ }
+ return 0;
+}
+
+
+/*
+ Autenticate user, with error reporting
+
+ SYNOPSIS
+ login_connection()
+ thd Thread handler
+
+ NOTES
+ Connection is not closed in case of errors
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+
+bool login_connection(THD *thd)
+{
+ int error;
+ NET *net= &thd->net;
+ Security_context *sctx= thd->security_ctx;
+ DBUG_ENTER("login_connection");
+ DBUG_PRINT("info", ("handle_one_connection called by thread %lu",
+ thd->thread_id));
+
+ net->no_send_error= 0;
+
+ /* Use "connect_timeout" value during connection phase */
+ net_set_read_timeout(net, connect_timeout);
+ net_set_write_timeout(net, connect_timeout);
+
+ if ((error=check_connection(thd)))
+ { // Wrong permissions
+ if (error > 0)
+ net_printf_error(thd, error, sctx->host_or_ip);
+#ifdef __NT__
+ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
+ my_sleep(1000); /* must wait after eof() */
+#endif
+ statistic_increment(aborted_connects,&LOCK_status);
+ DBUG_RETURN(1);
+ }
+ /* Connect completed, set read/write timeouts back to default */
+ net_set_read_timeout(net, thd->variables.net_read_timeout);
+ net_set_write_timeout(net, thd->variables.net_write_timeout);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Close an established connection
+
+ NOTES
+ This mainly updates status variables
+*/
+
+void end_connection(THD *thd)
+{
+ NET *net= &thd->net;
+ if (thd->user_connect)
+ decrease_user_connections(thd->user_connect);
+ if (net->error && net->vio != 0 && net->report_error)
+ {
+ Security_context *sctx= thd->security_ctx;
+ if (!thd->killed && thd->variables.log_warnings > 1)
+ sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
+ thd->thread_id,(thd->db ? thd->db : "unconnected"),
+ sctx->user ? sctx->user : "unauthenticated",
+ sctx->host_or_ip,
+ (net->last_errno ? ER(net->last_errno) :
+ ER(ER_UNKNOWN_ERROR)));
+ net_send_error(thd, net->last_errno, NullS);
+ statistic_increment(aborted_threads,&LOCK_status);
+ }
+ else if (thd->killed)
+ statistic_increment(aborted_threads,&LOCK_status);
+}
+
+
+/*
+ Initialize THD to handle queries
+*/
+
+void prepare_new_connection_state(THD* thd)
+{
+ Security_context *sctx= thd->security_ctx;
+
+#ifdef __NETWARE__
+ netware_reg_user(sctx->ip, sctx->user, "MySQL");
+#endif
+
+ if (thd->variables.max_join_size == HA_POS_ERROR)
+ thd->options |= OPTION_BIG_SELECTS;
+ if (thd->client_capabilities & CLIENT_COMPRESS)
+ thd->net.compress=1; // Use compression
+
+ thd->version= refresh_version;
+ thd->proc_info= 0;
+ thd->command= COM_SLEEP;
+ thd->set_time();
+ thd->init_for_queries();
+
+ if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
+ {
+ execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
+ if (thd->query_error)
+ {
+ thd->killed= THD::KILL_CONNECTION;
+ sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
+ thd->thread_id,(thd->db ? thd->db : "unconnected"),
+ sctx->user ? sctx->user : "unauthenticated",
+ sctx->host_or_ip, "init_connect command failed");
+ sql_print_warning("%s", thd->net.last_error);
+ }
+ thd->proc_info=0;
+ thd->set_time();
+ thd->init_for_queries();
+ }
+}
+
+
+/*
+ Thread handler for a connection
+
+ SYNOPSIS
+ handle_one_connection()
+ arg Connection object (THD)
+
+ IMPLEMENTATION
+ This function (normally) does the following:
+ - Initialize thread
+ - Initialize THD to be used with this thread
+ - Authenticate user
+ - Execute all queries sent on the connection
+ - Take connection down
+ - End thread / Handle next connection using thread from thread cache
+*/
+
+pthread_handler_t handle_one_connection(void *arg)
+{
+ THD *thd= (THD*) arg;
+ uint launch_time =
+ (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
+
+ if (thread_scheduler.init_new_connection_thread())
+ {
+ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
+ statistic_increment(aborted_connects,&LOCK_status);
+ thread_scheduler.end_thread(thd,0);
+ return 0;
+ }
+ if (launch_time >= slow_launch_time)
+ statistic_increment(slow_launch_threads,&LOCK_status);
+
+ /*
+ handle_one_connection() is normally the only way a thread would
+ start and would always be on the very high end of the stack ,
+ therefore, the thread stack always starts at the address of the
+ first local variable of handle_one_connection, which is thd. We
+ need to know the start of the stack so that we could check for
+ stack overruns.
+ */
+ thd->thread_stack= (char*) &thd;
+ if (setup_connection_thread_globals(thd))
+ return 0;
+
+ for (;;)
+ {
+ NET *net= &thd->net;
+
+ if (login_connection(thd))
+ goto end_thread;
+
+ prepare_new_connection_state(thd);
+
+ while (!net->error && net->vio != 0 &&
+ !(thd->killed == THD::KILL_CONNECTION))
+ {
+ net->no_send_error= 0;
+ if (do_command(thd))
+ break;
+ }
+ end_connection(thd);
+
+end_thread:
+ close_connection(thd, 0, 1);
+ if (thread_scheduler.end_thread(thd,1))
+ return 0; // Probably no-threads
+
+ /*
+ If end_thread() returns, we are either running with
+ thread-handler=no-threads or this thread has been schedule to
+ handle the next connection.
+ */
+ thd= current_thd;
+ thd->thread_stack= (char*) &thd;
+ }
+}
+#endif /* EMBEDDED_LIBRARY */
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index df313d8040c..3ab053d1741 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -69,13 +69,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
Test if the user wants to delete all rows and deletion doesn't have
any side-effects (because of triggers), so we can use optimized
handler::delete_all_rows() method.
-
- If row-based replication is used, we also delete the table row by
- row.
+ We implement fast TRUNCATE for InnoDB even if triggers are present.
+ TRUNCATE ignores triggers.
*/
if (!using_limit && const_cond && (!conds || conds->val_int()) &&
!(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
- !(table->triggers && table->triggers->has_delete_triggers()) &&
+ (thd->lex->sql_command == SQLCOM_TRUNCATE ||
+ !(table->triggers && table->triggers->has_delete_triggers())) &&
!thd->current_stmt_binlog_row_based)
{
/* Update the table->file->stats.records number */
@@ -153,7 +153,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (order && order->elements)
{
- uint length;
+ uint length= 0;
SORT_FIELD *sortorder;
TABLE_LIST tables;
List<Item> fields;
@@ -173,7 +173,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
DBUG_RETURN(TRUE);
}
- if (!select && limit != HA_POS_ERROR)
+ if ((!select || table->quick_keys.is_clear_all()) && limit != HA_POS_ERROR)
usable_index= get_index_for_order(table, (ORDER*)(order->first), limit);
if (usable_index == MAX_KEY)
@@ -377,6 +377,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
Item *fake_conds= 0;
SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_delete");
+ List<Item> all_fields;
thd->lex->allow_sum_func= 0;
if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
@@ -400,6 +401,11 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
DBUG_RETURN(TRUE);
}
}
+
+ if (select_lex->inner_refs_list.elements &&
+ fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
+ DBUG_RETURN(-1);
+
select_lex->fix_prepare_information(thd, conds, &fake_conds);
DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 92a6e24bc80..5712fbceac8 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -109,8 +109,6 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
SELECT_LEX *first_select= unit->first_select();
TABLE *table= 0;
select_union *derived_result;
- bool is_union= first_select->next_select() &&
- first_select->next_select()->linkage == UNION_TYPE;
/* prevent name resolving out of derived table */
for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select())
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 7b7f7602163..b8a904b0c6e 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -662,6 +662,8 @@ bool mysqld_help(THD *thd, const char *mask)
Init tables and fields to be usable from items
tables do not contain VIEWs => we can pass 0 as conds
*/
+ thd->lex->select_lex.context.table_list=
+ thd->lex->select_lex.context.first_name_resolution_table= &tables[0];
if (setup_tables(thd, &thd->lex->select_lex.context,
&thd->lex->select_lex.top_join_list,
tables, &leaves, FALSE))
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 989b78f3517..f58d08b8dea 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -59,8 +59,8 @@
#include "sql_trigger.h"
#include "sql_select.h"
#include "sql_show.h"
+#include "slave.h"
-static int check_null_fields(THD *thd,TABLE *entry);
#ifndef EMBEDDED_LIBRARY
static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list);
static int write_delayed(THD *thd, TABLE *table, enum_duplicates dup,
@@ -81,6 +81,65 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view);
#define my_safe_afree(ptr, size, min_length) if (size > min_length) my_free(ptr,MYF(0))
#endif
+/*
+ Check that insert/update fields are from the same single table of a view.
+
+ SYNOPSIS
+ check_view_single_update()
+ fields The insert/update fields to be checked.
+ view The view for insert.
+ map [in/out] The insert table map.
+
+ DESCRIPTION
+ This function is called in 2 cases:
+ 1. to check insert fields. In this case *map will be set to 0.
+ Insert fields are checked to be all from the same single underlying
+ table of the given view. Otherwise the error is thrown. Found table
+ map is returned in the map parameter.
+ 2. to check update fields of the ON DUPLICATE KEY UPDATE clause.
+ In this case *map contains table_map found on the previous call of
+ the function to check insert fields. Update fields are checked to be
+ from the same table as the insert fields.
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+bool check_view_single_update(List<Item> &fields, TABLE_LIST *view,
+ table_map *map)
+{
+ /* it is join view => we need to find the table for update */
+ List_iterator_fast<Item> it(fields);
+ Item *item;
+ TABLE_LIST *tbl= 0; // reset for call to check_single_table()
+ table_map tables= 0;
+
+ while ((item= it++))
+ tables|= item->used_tables();
+
+ /* Check found map against provided map */
+ if (*map)
+ {
+ if (tables != *map)
+ goto error;
+ return FALSE;
+ }
+
+ if (view->check_single_table(&tbl, tables, view) || tbl == 0)
+ goto error;
+
+ view->table= tbl->table;
+ *map= tables;
+
+ return FALSE;
+
+error:
+ my_error(ER_VIEW_MULTIUPDATE, MYF(0),
+ view->view_db.str, view->view_name.str);
+ return TRUE;
+}
+
/*
Check if insert fields are correct.
@@ -105,7 +164,7 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view);
static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
List<Item> &fields, List<Item> &values,
- bool check_unique)
+ bool check_unique, table_map *map)
{
TABLE *table= table_list->table;
@@ -131,11 +190,11 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (grant_option)
{
- Field_iterator_table fields;
- fields.set_table(table);
+ Field_iterator_table field_it;
+ field_it.set_table(table);
if (check_grant_all_columns(thd, INSERT_ACL, &table->grant,
table->s->db.str, table->s->table_name.str,
- &fields))
+ &field_it))
return -1;
}
#endif
@@ -183,21 +242,9 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE)
{
- /* it is join view => we need to find table for update */
- List_iterator_fast<Item> it(fields);
- Item *item;
- TABLE_LIST *tbl= 0; // reset for call to check_single_table()
- table_map map= 0;
-
- while ((item= it++))
- map|= item->used_tables();
- if (table_list->check_single_table(&tbl, map, table_list) || tbl == 0)
- {
- my_error(ER_VIEW_MULTIUPDATE, MYF(0),
- table_list->view_db.str, table_list->view_name.str);
+ if (check_view_single_update(fields, table_list, map))
return -1;
- }
- table_list->table= table= tbl->table;
+ table= table_list->table;
}
if (check_unique && thd->dup_field)
@@ -255,7 +302,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
*/
static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
- List<Item> &update_fields)
+ List<Item> &update_fields, table_map *map)
{
TABLE *table= insert_table_list->table;
my_bool timestamp_mark;
@@ -276,6 +323,10 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, 0))
return -1;
+ if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE &&
+ check_view_single_update(update_fields, insert_table_list, map))
+ return -1;
+
if (table->timestamp_field)
{
/* Don't set timestamp column if this is modified. */
@@ -300,13 +351,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
bool ignore)
{
int error, res;
- /*
- log_on is about delayed inserts only.
- By default, both logs are enabled (this won't cause problems if the server
- runs without --log-update or --log-bin).
- */
- bool log_on= ((thd->options & OPTION_BIN_LOG) ||
- (!(thd->security_ctx->master_access & SUPER_ACL)));
bool transactional_table, joins_freed= FALSE;
bool changed;
uint value_count;
@@ -321,6 +365,13 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
#ifndef EMBEDDED_LIBRARY
char *query= thd->query;
#endif
+ /*
+ log_on is about delayed inserts only.
+ By default, both logs are enabled (this won't cause problems if the server
+ runs without --log-update or --log-bin).
+ */
+ bool log_on= ((thd->options & OPTION_BIN_LOG) ||
+ (!(thd->security_ctx->master_access & SUPER_ACL)));
thr_lock_type lock_type = table_list->lock_type;
Item *unused_conds= 0;
DBUG_ENTER("mysql_insert");
@@ -341,11 +392,42 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
(duplic == DUP_UPDATE))
lock_type=TL_WRITE;
#endif
+ if ((lock_type == TL_WRITE_DELAYED) &&
+ (global_system_variables.binlog_format == BINLOG_FORMAT_STMT) &&
+ log_on && mysql_bin_log.is_open() &&
+ (values_list.elements > 1))
+ {
+ /*
+ Statement-based binary logging does not work in this case, because:
+ a) two concurrent statements may have their rows intermixed in the
+ queue, leading to autoincrement replication problems on slave (because
+ the values generated used for one statement don't depend only on the
+ value generated for the first row of this statement, so are not
+ replicable)
+ b) if first row of the statement has an error the full statement is
+ not binlogged, while next rows of the statement may be inserted.
+ c) if first row succeeds, statement is binlogged immediately with a
+ zero error code (i.e. "no error"), if then second row fails, query
+ will fail on slave too and slave will stop (wrongly believing that the
+ master got no error).
+ So we fallback to non-delayed INSERT.
+ Note that to be fully correct, we should test the "binlog format which
+ the delayed thread is going to use for this row". But in the common case
+ where the global binlog format is not changed and the session binlog
+ format may be changed, that is equal to the global binlog format.
+ We test it without mutex for speed reasons (condition rarely true), and
+ in the common case (global not changed) it is as good as without mutex;
+ if global value is changed, anyway there is uncertainty as the delayed
+ thread may be old and use the before-the-change value.
+ */
+ lock_type= TL_WRITE;
+ }
table_list->lock_type= lock_type;
#ifndef EMBEDDED_LIBRARY
if (lock_type == TL_WRITE_DELAYED)
{
+ res= 1;
if (thd->locked_tables)
{
DBUG_ASSERT(table_list->db); /* Must be set in the parser */
@@ -454,6 +536,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->cuted_fields = 0L;
table->next_number_field=table->found_next_number_field;
+#ifdef HAVE_REPLICATION
+ if (thd->slave_thread &&
+ (info.handle_duplicates == DUP_UPDATE) &&
+ (table->next_number_field != NULL) &&
+ rpl_master_has_bug(&active_mi->rli, 24432))
+ goto abort;
+#endif
+
error=0;
thd->proc_info="update";
if (duplic != DUP_ERROR || ignore)
@@ -740,7 +830,6 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view)
Field_translator *trans_start= view->field_translation,
*trans_end= trans_start + num;
Field_translator *trans;
- Field **field_ptr= table->field;
uint used_fields_buff_size= bitmap_buffer_size(table->s->fields);
uint32 *used_fields_buff= (uint32*)thd->alloc(used_fields_buff_size);
MY_BITMAP used_fields;
@@ -892,10 +981,13 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
Name_resolution_context_state ctx_state;
bool insert_into_view= (table_list->view != 0);
bool res= 0;
+ table_map map= 0;
DBUG_ENTER("mysql_prepare_insert");
DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d",
(ulong)table_list, (ulong)table,
(int)insert_into_view));
+ /* INSERT should have a SELECT or VALUES clause */
+ DBUG_ASSERT (!select_insert || !values);
/*
For subqueries in VALUES() we should not see the table in which we are
@@ -927,44 +1019,40 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
if (mysql_prepare_insert_check_table(thd, table_list, fields, select_insert))
DBUG_RETURN(TRUE);
- /* Save the state of the current name resolution context. */
- ctx_state.save_state(context, table_list);
-
- /*
- Perform name resolution only in the first table - 'table_list',
- which is the table that is inserted into.
- */
- table_list->next_local= 0;
- context->resolve_in_table_list_only(table_list);
/* Prepare the fields in the statement. */
- if (values &&
- !(res= check_insert_fields(thd, context->table_list, fields, *values,
- !insert_into_view) ||
- setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0)) &&
- duplic == DUP_UPDATE)
+ if (values)
{
- select_lex->no_wrap_view_item= TRUE;
- res= check_update_fields(thd, context->table_list, update_fields);
- select_lex->no_wrap_view_item= FALSE;
+ /* if we have INSERT ... VALUES () we cannot have a GROUP BY clause */
+ DBUG_ASSERT (!select_lex->group_list.elements);
+
+ /* Save the state of the current name resolution context. */
+ ctx_state.save_state(context, table_list);
+
/*
- When we are not using GROUP BY we can refer to other tables in the
- ON DUPLICATE KEY part.
- */
- if (select_lex->group_list.elements == 0)
+ Perform name resolution only in the first table - 'table_list',
+ which is the table that is inserted into.
+ */
+ 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, MARK_COLUMNS_READ, 0, 0))
+ && duplic == DUP_UPDATE)
{
- context->table_list->next_local= ctx_state.save_next_local;
- /* first_name_resolution_table was set by resolve_in_table_list_only() */
- context->first_name_resolution_table->
- next_name_resolution_table= ctx_state.save_next_local;
+ select_lex->no_wrap_view_item= TRUE;
+ res= check_update_fields(thd, context->table_list, update_fields, &map);
+ select_lex->no_wrap_view_item= FALSE;
}
+
+ /* Restore the current context. */
+ ctx_state.restore_state(context, table_list);
+
if (!res)
res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0);
}
- /* Restore the current context. */
- ctx_state.restore_state(context, table_list);
-
if (res)
DBUG_RETURN(res);
@@ -1146,32 +1234,36 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
if (res == VIEW_CHECK_ERROR)
goto before_trg_err;
+ table->file->restore_auto_increment(prev_insert_id);
if ((error=table->file->ha_update_row(table->record[1],
table->record[0])))
{
if (info->ignore &&
!table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
{
- table->file->restore_auto_increment(prev_insert_id);
goto ok_or_after_trg_err;
}
goto err;
- }
- info->updated++;
- /*
- If ON DUP KEY UPDATE updates a row instead of inserting one, it's
- like a regular UPDATE statement: it should not affect the value of a
- next SELECT LAST_INSERT_ID() or mysql_insert_id().
- Except if LAST_INSERT_ID(#) was in the INSERT query, which is
- handled separately by THD::arg_of_last_insert_id_function.
- */
- insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0;
- 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++;
+ }
+ if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) ||
+ compare_record(table))
+ {
+ info->updated++;
+ /*
+ If ON DUP KEY UPDATE updates a row instead of inserting one, it's
+ like a regular UPDATE statement: it should not affect the value of a
+ next SELECT LAST_INSERT_ID() or mysql_insert_id().
+ Except if LAST_INSERT_ID(#) was in the INSERT query, which is
+ handled separately by THD::arg_of_last_insert_id_function.
+ */
+ insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0;
+ 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 */
@@ -1842,7 +1934,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
pthread_detach_this_thread();
/* Add thread to THD list so that's it's visible in 'show processlist' */
pthread_mutex_lock(&LOCK_thread_count);
- thd->thread_id=thread_id++;
+ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
thd->end_time();
threads.append(thd);
thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED;
@@ -1873,14 +1965,8 @@ pthread_handler_t handle_delayed_insert(void *arg)
strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES));
goto err;
}
-#if !defined(__WIN__) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
/* open table */
-
if (!(di->table=open_ltable(thd,&di->table_list,TL_WRITE_DELAYED)))
{
thd->fatal_error(); // Abort waiting inserts
@@ -2404,6 +2490,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
LEX *lex= thd->lex;
int res;
+ table_map map= 0;
SELECT_LEX *lex_current_select_save= lex->current_select;
DBUG_ENTER("select_insert::prepare");
@@ -2416,12 +2503,11 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
lex->current_select= &lex->select_lex;
res= check_insert_fields(thd, table_list, *fields, values,
- !insert_into_view) ||
+ !insert_into_view, &map) ||
setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0);
if (info.handle_duplicates == DUP_UPDATE)
{
- /* Save the state of the current name resolution context. */
Name_resolution_context *context= &lex->select_lex.context;
Name_resolution_context_state ctx_state;
@@ -2434,21 +2520,43 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
lex->select_lex.no_wrap_view_item= TRUE;
res= res || check_update_fields(thd, context->table_list,
- *info.update_fields);
+ *info.update_fields, &map);
lex->select_lex.no_wrap_view_item= FALSE;
/*
- When we are not using GROUP BY we can refer to other tables in the
- ON DUPLICATE KEY part
- */
- if (lex->select_lex.group_list.elements == 0)
+ When we are not using GROUP BY and there are no ungrouped aggregate functions
+ we can refer to other tables in the ON DUPLICATE KEY part.
+ We use next_name_resolution_table descructively, so check it first (views?)
+ */
+ DBUG_ASSERT (!table_list->next_name_resolution_table);
+ if (lex->select_lex.group_list.elements == 0 &&
+ !lex->select_lex.with_sum_func)
+ /*
+ We must make a single context out of the two separate name resolution contexts :
+ the INSERT table and the tables in the SELECT part of INSERT ... SELECT.
+ To do that we must concatenate the two lists
+ */
+ table_list->next_name_resolution_table=
+ ctx_state.get_first_name_resolution_table();
+
+ res= res || setup_fields(thd, 0, *info.update_values,
+ MARK_COLUMNS_READ, 0, 0);
+ if (!res)
{
- context->table_list->next_local= ctx_state.save_next_local;
- /* first_name_resolution_table was set by resolve_in_table_list_only() */
- context->first_name_resolution_table->
- next_name_resolution_table= ctx_state.save_next_local;
+ /*
+ Traverse the update values list and substitute fields from the
+ select for references (Item_ref objects) to them. This is done in
+ order to get correct values from those fields when the select
+ employs a temporary table.
+ */
+ List_iterator<Item> li(*info.update_values);
+ Item *item;
+
+ while ((item= li++))
+ {
+ item->transform(&Item::update_value_transformer,
+ (byte*)lex->current_select);
+ }
}
- res= res || setup_fields(thd, 0, *info.update_values, MARK_COLUMNS_READ,
- 0, 0);
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
@@ -2489,6 +2597,15 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
}
restore_record(table,s->default_values); // Get empty record
table->next_number_field=table->found_next_number_field;
+
+#ifdef HAVE_REPLICATION
+ if (thd->slave_thread &&
+ (info.handle_duplicates == DUP_UPDATE) &&
+ (table->next_number_field != NULL) &&
+ rpl_master_has_bug(&active_mi->rli, 24432))
+ DBUG_RETURN(1);
+#endif
+
thd->cuted_fields=0;
if (info.ignore || info.handle_duplicates != DUP_ERROR)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
@@ -3093,7 +3210,7 @@ void select_create::send_error(uint errcode,const char *err)
thd->current_stmt_binlog_row_based ? "is" : "is NOT"));
DBUG_PRINT("info",
("Current table (at 0x%lu) %s a temporary (or non-existant) table",
- table,
+ (ulong) table,
table && !table->s->tmp_table ? "is NOT" : "is"));
DBUG_PRINT("info",
("Table %s prior to executing this statement",
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 97b5df241f7..ef1f0592051 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -100,6 +100,16 @@ void lex_free(void)
}
+void
+st_parsing_options::reset()
+{
+ allows_variable= TRUE;
+ allows_select_into= TRUE;
+ allows_select_procedure= TRUE;
+ allows_derived= TRUE;
+}
+
+
/*
This is called before every query that is to be parsed.
Because of this, it's critical to not do too much things here.
@@ -150,6 +160,7 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->safe_to_cache_query= 1;
lex->time_zone_tables_used= 0;
lex->leaf_tables_insert= 0;
+ lex->parsing_options.reset();
lex->empty_field_list_on_rset= 0;
lex->select_lex.select_number= 1;
lex->next_state=MY_LEX_START;
@@ -317,13 +328,15 @@ static char *get_text(LEX *lex)
{
c = yyGet();
#ifdef USE_MB
- int l;
- if (use_mb(cs) &&
- (l = my_ismbchar(cs,
- (const char *)lex->ptr-1,
- (const char *)lex->end_of_query))) {
+ {
+ int l;
+ if (use_mb(cs) &&
+ (l = my_ismbchar(cs,
+ (const char *)lex->ptr-1,
+ (const char *)lex->end_of_query))) {
lex->ptr += l-1;
continue;
+ }
}
#endif
if (c == '\\' &&
@@ -791,8 +804,8 @@ int MYSQLlex(void *arg, void *yythd)
lex->tok_start=lex->ptr; // Skip first `
while ((c=yyGet()))
{
- int length;
- if ((length= my_mbcharlen(cs, c)) == 1)
+ int var_length;
+ if ((var_length= my_mbcharlen(cs, c)) == 1)
{
if (c == quote_char)
{
@@ -804,9 +817,9 @@ int MYSQLlex(void *arg, void *yythd)
}
}
#ifdef USE_MB
- else if (length < 1)
+ else if (var_length < 1)
break; // Error
- lex->ptr+= length-1;
+ lex->ptr+= var_length-1;
#endif
}
if (double_quotes)
@@ -1170,6 +1183,7 @@ void st_select_lex::init_query()
cond_count= between_count= with_wild= 0;
conds_processed_with_permanent_arena= 0;
ref_pointer_array= 0;
+ select_n_where_fields= 0;
select_n_having_items= 0;
subquery_in_having= explicit_limit= 0;
is_item_list_lookup= 0;
@@ -1208,6 +1222,9 @@ void st_select_lex::init_select()
offset_limit= 0; /* denotes the default offset = 0 */
with_sum_func= 0;
is_correlated= 0;
+ cur_pos_in_select_list= UNDEF_POS;
+ non_agg_fields.empty();
+ inner_refs_list.empty();
}
/*
@@ -1397,9 +1414,17 @@ void st_select_lex::mark_as_dependent(SELECT_LEX *last)
if (!(s->uncacheable & UNCACHEABLE_DEPENDENT))
{
// Select is dependent of outer select
- s->uncacheable|= UNCACHEABLE_DEPENDENT;
+ s->uncacheable= (s->uncacheable & ~UNCACHEABLE_UNITED) |
+ UNCACHEABLE_DEPENDENT;
SELECT_LEX_UNIT *munit= s->master_unit();
- munit->uncacheable|= UNCACHEABLE_DEPENDENT;
+ munit->uncacheable= (munit->uncacheable & ~UNCACHEABLE_UNITED) |
+ UNCACHEABLE_DEPENDENT;
+ for (SELECT_LEX *sl= munit->first_select(); sl ; sl= sl->next_select())
+ {
+ if (sl != s &&
+ !(sl->uncacheable & (UNCACHEABLE_DEPENDENT | UNCACHEABLE_UNITED)))
+ sl->uncacheable|= UNCACHEABLE_UNITED;
+ }
}
is_correlated= TRUE;
this->master_unit()->item->is_correlated= TRUE;
@@ -1557,6 +1582,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
(Item **)arena->alloc(sizeof(Item*) * (n_child_sum_items +
item_list.elements +
select_n_having_items +
+ select_n_where_fields +
order_group_num)*5)) == 0;
}
@@ -1640,6 +1666,36 @@ void st_select_lex::print_limit(THD *thd, String *str)
}
}
+/**
+ @brief Restore the LEX and THD in case of a parse error.
+
+ This is a clean up call that is invoked by the Bison generated
+ parser before returning an error from MYSQLparse. If your
+ semantic actions manipulate with the global thread state (which
+ is a very bad practice and should not normally be employed) and
+ need a clean-up in case of error, and you can not use %destructor
+ rule in the grammar file itself, this function should be used
+ to implement the clean up.
+*/
+
+void st_lex::cleanup_lex_after_parse_error(THD *thd)
+{
+ /*
+ Delete sphead for the side effect of restoring of the original
+ LEX state, thd->lex, thd->mem_root and thd->free_list if they
+ were replaced when parsing stored procedure statements. We
+ will never use sphead object after a parse error, so it's okay
+ to delete it only for the sake of the side effect.
+ TODO: make this functionality explicit in sp_head class.
+ Sic: we must nullify the member of the main lex, not the
+ current one that will be thrown away
+ */
+ if (thd->lex->sphead)
+ {
+ delete thd->lex->sphead;
+ thd->lex->sphead= NULL;
+ }
+}
/*
Initialize (or reset) Query_tables_list object.
@@ -1745,13 +1801,14 @@ bool st_lex::can_be_merged()
bool selects_allow_merge= select_lex.next_select() == 0;
if (selects_allow_merge)
{
- for (SELECT_LEX_UNIT *unit= select_lex.first_inner_unit();
- unit;
- unit= unit->next_unit())
+ for (SELECT_LEX_UNIT *tmp_unit= select_lex.first_inner_unit();
+ tmp_unit;
+ tmp_unit= tmp_unit->next_unit())
{
- if (unit->first_select()->parent_lex == this &&
- (unit->item == 0 ||
- (unit->item->place() != IN_WHERE && unit->item->place() != IN_ON)))
+ if (tmp_unit->first_select()->parent_lex == this &&
+ (tmp_unit->item == 0 ||
+ (tmp_unit->item->place() != IN_WHERE &&
+ tmp_unit->item->place() != IN_ON)))
{
selects_allow_merge= 0;
break;
@@ -1760,7 +1817,6 @@ bool st_lex::can_be_merged()
}
return (selects_allow_merge &&
- select_lex.order_list.elements == 0 &&
select_lex.group_list.elements == 0 &&
select_lex.having == 0 &&
select_lex.with_sum_func == 0 &&
@@ -2049,12 +2105,12 @@ void st_lex::first_lists_tables_same()
FALSE - success
*/
-bool st_lex::add_time_zone_tables_to_query_tables(THD *thd)
+bool st_lex::add_time_zone_tables_to_query_tables(THD *thd_arg)
{
/* We should not add these tables twice */
if (!time_zone_tables_used)
{
- time_zone_tables_used= my_tz_get_table_list(thd, &query_tables_last);
+ time_zone_tables_used= my_tz_get_table_list(thd_arg, &query_tables_last);
if (time_zone_tables_used == &fake_time_zone_tables_list)
return TRUE;
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 8e9eb578911..33d028c829e 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -432,7 +432,8 @@ protected:
select_result *result;
ulonglong found_rows_for_union;
- bool res;
+ bool saved_error;
+
public:
bool prepared, // prepare phase already performed for UNION (unit)
optimized, // optimize phase already performed for UNION (unit)
@@ -504,7 +505,7 @@ public:
void set_thd(THD *thd_arg) { thd= thd_arg; }
friend void lex_start(THD *thd, const uchar *buf, uint length);
- friend int subselect_union_engine::exec(bool);
+ friend int subselect_union_engine::exec();
List<Item> *get_unit_column_types();
};
@@ -565,6 +566,11 @@ public:
uint select_n_having_items;
uint cond_count; /* number of arguments of and/or/xor in where/having/on */
uint between_count; /* number of between predicates in where/having/on */
+ /*
+ Number of fields used in select list or where clause of current select
+ and all inner subselects.
+ */
+ uint select_n_where_fields;
enum_parsing_place parsing_place; /* where we are parsing expression */
bool with_sum_func; /* sum function indicator */
/*
@@ -582,7 +588,8 @@ public:
bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */
/* TRUE when having fix field called in processing of this SELECT */
bool having_fix_field;
-
+ /* List of references to fields referenced from inner selects */
+ List<Item_outer_ref> inner_refs_list;
/* Number of Item_sum-derived objects in this SELECT */
uint n_sum_items;
/* Number of Item_sum-derived objects in children and descendant SELECTs */
@@ -615,7 +622,26 @@ public:
bool no_wrap_view_item;
/* exclude this select from check of unique_table() */
bool exclude_from_table_unique_test;
+ /* List of fields that aren't under an aggregate function */
+ List<Item_field> non_agg_fields;
+ /* index in the select list of the expression currently being fixed */
+ int cur_pos_in_select_list;
+ List<udf_func> udf_list; /* udf function calls stack */
+ /*
+ This is a copy of the original JOIN USING list that comes from
+ the parser. The parser :
+ 1. Sets the natural_join of the second TABLE_LIST in the join
+ and the st_select_lex::prev_join_using.
+ 2. Makes a parent TABLE_LIST and sets its is_natural_join/
+ join_using_fields members.
+ 3. Uses the wrapper TABLE_LIST as a table in the upper level.
+ We cannot assign directly to join_using_fields in the parser because
+ at stage (1.) the parent TABLE_LIST is not constructed yet and
+ the assignment will override the JOIN USING fields of the lower level
+ joins on the right.
+ */
+ List<String> *prev_join_using;
void init_query();
void init_select();
st_select_lex_unit* master_unit();
@@ -890,10 +916,8 @@ struct st_parsing_options
bool allows_select_procedure;
bool allows_derived;
- st_parsing_options()
- : allows_variable(TRUE), allows_select_into(TRUE),
- allows_select_procedure(TRUE), allows_derived(TRUE)
- {}
+ st_parsing_options() { reset(); }
+ void reset();
};
@@ -1209,6 +1233,10 @@ typedef struct st_lex : public Query_tables_list
{
return context_stack.head();
}
+ /*
+ Restore the LEX and THD in case of a parse error.
+ */
+ static void cleanup_lex_after_parse_error(THD *thd);
void reset_n_backup_query_tables_list(Query_tables_list *backup);
void restore_backup_query_tables_list(Query_tables_list *backup);
diff --git a/sql/sql_list.h b/sql/sql_list.h
index d16fbaf2e50..af30cbe0d6a 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -38,6 +38,8 @@ public:
static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root)
{ /* never called */ }
+ static void operator delete[](void *ptr, MEM_ROOT *mem_root)
+ { /* never called */ }
static void operator delete[](void *ptr, size_t size) { TRASH(ptr, size); }
#ifdef HAVE_purify
bool dummy;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index c1c775f95b7..802eed5116e 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -82,10 +82,11 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
List<Item> &set_values, READ_INFO &read_info,
String &enclosed, ulong skip_lines,
bool ignore_check_option_errors);
+#ifndef EMBEDDED_LIBRARY
static bool write_execute_load_query_log_event(THD *thd,
bool duplicates, bool ignore,
bool transactional_table);
-
+#endif /* EMBEDDED_LIBRARY */
/*
Execute LOAD DATA query
@@ -315,7 +316,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
info.handle_duplicates=handle_duplicates;
info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
- READ_INFO read_info(file,tot_length,thd->variables.collation_database,
+ READ_INFO read_info(file,tot_length,
+ ex->cs ? ex->cs : thd->variables.collation_database,
*field_term,*ex->line_start, *ex->line_term, *enclosed,
info.escape_char, read_file_from_client, is_fifo);
if (read_info.error)
@@ -457,7 +459,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
}
sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
(ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
- send_ok(thd,info.copied+info.deleted,0L,name);
if (!transactional_table)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
@@ -493,6 +494,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (transactional_table)
error=ha_autocommit_or_rollback(thd,error);
+ /* ok to client sent only after binlog write and engine commit */
+ send_ok(thd, info.copied + info.deleted, 0L, name);
err:
table->file->ha_release_auto_increment();
if (thd->lock)
@@ -505,6 +508,8 @@ err:
}
+#ifndef EMBEDDED_LIBRARY
+
/* Not a very useful function; just to avoid duplication of code */
static bool write_execute_load_query_log_event(THD *thd,
bool duplicates, bool ignore,
@@ -521,6 +526,7 @@ static bool write_execute_load_query_log_event(THD *thd,
return mysql_bin_log.write(&e);
}
+#endif
/****************************************************************************
** Read of rows of fixed size + optional garage + optonal newline
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 9307836731a..88c27415d5c 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -27,24 +27,7 @@
#include "sp_cache.h"
#include "events.h"
#include "event_data_objects.h"
-
-#ifdef HAVE_OPENSSL
-/*
- Without SSL the handshake consists of one packet. This packet
- has both client capabilites and scrambled password.
- With SSL the handshake might consist of two packets. If the first
- packet (client capabilities) has CLIENT_SSL flag set, we have to
- switch to SSL and read the second packet. The scrambled password
- is in the second packet and client_capabilites field will be ignored.
- Maybe it is better to accept flags other than CLIENT_SSL from the
- second packet?
-*/
-#define SSL_HANDSHAKE_SIZE 2
-#define NORMAL_HANDSHAKE_SIZE 6
-#define MIN_HANDSHAKE_SIZE 2
-#else
-#define MIN_HANDSHAKE_SIZE 6
-#endif /* HAVE_OPENSSL */
+#include "sql_trigger.h"
/* Used in error handling only */
#define SP_TYPE_STRING(LP) \
@@ -56,12 +39,6 @@
(LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
"FUNCTION" : "PROCEDURE")
-static void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
-static void decrease_user_connections(USER_CONN *uc);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-static bool check_multi_update_lock(THD *thd);
static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
const char *any_db="*any*"; // Special symbol for check_access
@@ -104,20 +81,6 @@ const char *xa_state_names[]={
"NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
};
-#ifdef __WIN__
-static void test_signal(int sig_ptr)
-{
-#if !defined( DBUG_OFF)
- MessageBox(NULL,"Test signal","DBUG",MB_OK);
-#endif
-}
-static void init_signals(void)
-{
- int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
- for (int i=0 ; i < 7 ; i++)
- signal( signals[i], test_signal) ;
-}
-#endif
static void unlock_locked_tables(THD *thd)
{
@@ -161,6 +124,7 @@ bool end_active_trans(THD *thd)
DBUG_RETURN(error);
}
+
bool begin_trans(THD *thd)
{
int error=0;
@@ -212,409 +176,6 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables)
return 0;
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-static HASH hash_user_connections;
-
-static int get_or_create_user_conn(THD *thd, const char *user,
- const char *host,
- USER_RESOURCES *mqh)
-{
- int return_val= 0;
- uint temp_len, user_len;
- char temp_user[USER_HOST_BUFF_SIZE];
- struct user_conn *uc;
-
- DBUG_ASSERT(user != 0);
- DBUG_ASSERT(host != 0);
-
- user_len= strlen(user);
- temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
- (void) pthread_mutex_lock(&LOCK_user_conn);
- if (!(uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len)))
- {
- /* First connection for user; Create a user connection object */
- if (!(uc= ((struct user_conn*)
- my_malloc(sizeof(struct user_conn) + temp_len+1,
- MYF(MY_WME)))))
- {
- net_send_error(thd, 0, NullS); // Out of memory
- return_val= 1;
- goto end;
- }
- uc->user=(char*) (uc+1);
- memcpy(uc->user,temp_user,temp_len+1);
- uc->host= uc->user + user_len + 1;
- uc->len= temp_len;
- uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
- uc->user_resources= *mqh;
- uc->intime= thd->thr_create_time;
- if (my_hash_insert(&hash_user_connections, (byte*) uc))
- {
- my_free((char*) uc,0);
- net_send_error(thd, 0, NullS); // Out of memory
- return_val= 1;
- goto end;
- }
- }
- thd->user_connect=uc;
- uc->connections++;
-end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- return return_val;
-
-}
-#endif /* !NO_EMBEDDED_ACCESS_CHECKS */
-
-
-/*
- Check if user exist and password supplied is correct.
-
- SYNOPSIS
- check_user()
- thd thread handle, thd->security_ctx->{host,user,ip} are used
- command originator of the check: now check_user is called
- during connect and change user procedures; used for
- logging.
- passwd scrambled password received from client
- passwd_len length of scrambled password
- db database name to connect to, may be NULL
- check_count dont know exactly
-
- Note, that host, user and passwd may point to communication buffer.
- Current implementation does not depend on that, but future changes
- should be done with this in mind; 'thd' is INOUT, all other params
- are 'IN'.
-
- RETURN VALUE
- 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and
- thd->db are updated; OK is sent to client;
- -1 access denied or handshake error; error is sent to client;
- >0 error, not sent to client
-*/
-
-int check_user(THD *thd, enum enum_server_command command,
- const char *passwd, uint passwd_len, const char *db,
- bool check_count)
-{
- DBUG_ENTER("check_user");
-
-#ifdef NO_EMBEDDED_ACCESS_CHECKS
- thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights
- /* Change database if necessary */
- if (db && db[0])
- {
- /*
- thd->db is saved in caller and needs to be freed by caller if this
- function returns 0
- */
- thd->reset_db(NULL, 0);
- if (mysql_change_db(thd, db, FALSE))
- {
- /* Send the error to the client */
- net_send_error(thd);
- DBUG_RETURN(-1);
- }
- }
- send_ok(thd);
- DBUG_RETURN(0);
-#else
-
- my_bool opt_secure_auth_local;
- pthread_mutex_lock(&LOCK_global_system_variables);
- opt_secure_auth_local= opt_secure_auth;
- pthread_mutex_unlock(&LOCK_global_system_variables);
-
- /*
- If the server is running in secure auth mode, short scrambles are
- forbidden.
- */
- if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
- {
- net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
- general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
- DBUG_RETURN(-1);
- }
- if (passwd_len != 0 &&
- passwd_len != SCRAMBLE_LENGTH &&
- passwd_len != SCRAMBLE_LENGTH_323)
- DBUG_RETURN(ER_HANDSHAKE_ERROR);
-
- /*
- Clear thd->db as it points to something, that will be freed when
- connection is closed. We don't want to accidentally free a wrong pointer
- if connect failed. Also in case of 'CHANGE USER' failure, current
- database will be switched to 'no database selected'.
- */
- thd->reset_db(NULL, 0);
-
- USER_RESOURCES ur;
- int res= acl_getroot(thd, &ur, passwd, passwd_len);
-#ifndef EMBEDDED_LIBRARY
- if (res == -1)
- {
- /*
- This happens when client (new) sends password scrambled with
- scramble(), but database holds old value (scrambled with
- scramble_323()). Here we please client to send scrambled_password
- in old format.
- */
- NET *net= &thd->net;
- if (opt_secure_auth_local)
- {
- net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip);
- general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip);
- DBUG_RETURN(-1);
- }
- /* We have to read very specific packet size */
- if (send_old_password_request(thd) ||
- my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
- {
- inc_host_errors(&thd->remote.sin_addr);
- DBUG_RETURN(ER_HANDSHAKE_ERROR);
- }
- /* Final attempt to check the user based on reply */
- /* So as passwd is short, errcode is always >= 0 */
- res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
- }
-#endif /*EMBEDDED_LIBRARY*/
- /* here res is always >= 0 */
- if (res == 0)
- {
- if (!(thd->main_security_ctx.master_access &
- NO_ACCESS)) // authentication is OK
- {
- DBUG_PRINT("info",
- ("Capabilities: %lu packet_length: %ld Host: '%s' "
- "Login user: '%s' Priv_user: '%s' Using password: %s "
- "Access: %lu db: '%s'",
- thd->client_capabilities,
- thd->max_client_packet_length,
- thd->main_security_ctx.host_or_ip,
- thd->main_security_ctx.user,
- thd->main_security_ctx.priv_user,
- passwd_len ? "yes": "no",
- thd->main_security_ctx.master_access,
- (thd->db ? thd->db : "*none*")));
-
- if (check_count)
- {
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- bool count_ok= thread_count <= max_connections + delayed_insert_threads
- || (thd->main_security_ctx.master_access & SUPER_ACL);
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- if (!count_ok)
- { // too many connections
- net_send_error(thd, ER_CON_COUNT_ERROR);
- DBUG_RETURN(-1);
- }
- }
-
- /* Why logging is performed before all checks've passed? */
- general_log_print(thd, command,
- (thd->main_security_ctx.priv_user ==
- thd->main_security_ctx.user ?
- (char*) "%s@%s on %s" :
- (char*) "%s@%s as anonymous on %s"),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- db ? db : (char*) "");
-
- /*
- This is the default access rights for the current database. It's
- set to 0 here because we don't have an active database yet (and we
- may not have an active database to set.
- */
- thd->main_security_ctx.db_access=0;
-
- /* Don't allow user to connect if he has done too many queries */
- if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
- max_user_connections) &&
- get_or_create_user_conn(thd,
- (opt_old_style_user_limits ? thd->main_security_ctx.user :
- thd->main_security_ctx.priv_user),
- (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
- thd->main_security_ctx.priv_host),
- &ur))
- DBUG_RETURN(-1);
- if (thd->user_connect &&
- (thd->user_connect->user_resources.conn_per_hour ||
- thd->user_connect->user_resources.user_conn ||
- max_user_connections) &&
- check_for_max_user_connections(thd, thd->user_connect))
- DBUG_RETURN(-1);
-
- /* Change database if necessary */
- if (db && db[0])
- {
- if (mysql_change_db(thd, db, FALSE))
- {
- /* Send error to the client */
- net_send_error(thd);
- if (thd->user_connect)
- decrease_user_connections(thd->user_connect);
- DBUG_RETURN(-1);
- }
- }
- send_ok(thd);
- thd->password= test(passwd_len); // remember for error messages
- /* Ready to handle queries */
- DBUG_RETURN(0);
- }
- }
- else if (res == 2) // client gave short hash, server has long hash
- {
- net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
- general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
- DBUG_RETURN(-1);
- }
- net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- passwd_len ? ER(ER_YES) : ER(ER_NO));
- general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- passwd_len ? ER(ER_YES) : ER(ER_NO));
- DBUG_RETURN(-1);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-/*
- Check for maximum allowable user connections, if the mysqld server is
- started with corresponding variable that is greater then 0.
-*/
-
-extern "C" byte *get_key_conn(user_conn *buff, uint *length,
- my_bool not_used __attribute__((unused)))
-{
- *length=buff->len;
- return (byte*) buff->user;
-}
-
-extern "C" void free_user(struct user_conn *uc)
-{
- my_free((char*) uc,MYF(0));
-}
-
-void init_max_user_conn(void)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
- 0,0,
- (hash_get_key) get_key_conn, (hash_free_key) free_user,
- 0);
-#endif
-}
-
-
-/*
- check if user has already too many connections
-
- SYNOPSIS
- check_for_max_user_connections()
- thd Thread handle
- uc User connect object
-
- NOTES
- If check fails, we decrease user connection count, which means one
- shouldn't call decrease_user_connections() after this function.
-
- RETURN
- 0 ok
- 1 error
-*/
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-
-static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
-{
- int error=0;
- DBUG_ENTER("check_for_max_user_connections");
-
- (void) pthread_mutex_lock(&LOCK_user_conn);
- if (max_user_connections && !uc->user_resources.user_conn &&
- max_user_connections < (uint) uc->connections)
- {
- net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
- error=1;
- goto end;
- }
- time_out_user_resource_limits(thd, uc);
- if (uc->user_resources.user_conn &&
- uc->user_resources.user_conn < uc->connections)
- {
- net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
- "max_user_connections",
- (long) uc->user_resources.user_conn);
- error= 1;
- goto end;
- }
- if (uc->user_resources.conn_per_hour &&
- uc->user_resources.conn_per_hour <= uc->conn_per_hour)
- {
- net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
- "max_connections_per_hour",
- (long) uc->user_resources.conn_per_hour);
- error=1;
- goto end;
- }
- uc->conn_per_hour++;
-
- end:
- if (error)
- uc->connections--; // no need for decrease_user_connections() here
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- DBUG_RETURN(error);
-}
-
-/*
- Decrease user connection count
-
- SYNOPSIS
- decrease_user_connections()
- uc User connection object
-
- NOTES
- If there is a n user connection object for a connection
- (which only happens if 'max_user_connections' is defined or
- if someone has created a resource grant for a user), then
- the connection count is always incremented on connect.
-
- The user connect object is not freed if some users has
- 'max connections per hour' defined as we need to be able to hold
- count over the lifetime of the connection.
-*/
-
-static void decrease_user_connections(USER_CONN *uc)
-{
- DBUG_ENTER("decrease_user_connections");
- (void) pthread_mutex_lock(&LOCK_user_conn);
- DBUG_ASSERT(uc->connections);
- if (!--uc->connections && !mqh_used)
- {
- /* Last connection for user; Delete it */
- (void) hash_delete(&hash_user_connections,(byte*) uc);
- }
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- DBUG_VOID_RETURN;
-}
-
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-
-
-void free_max_user_conn(void)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- hash_free(&hash_user_connections);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-
/*
Mark all commands that somehow changes a table
@@ -698,404 +259,6 @@ bool is_update_query(enum enum_sql_command command)
return (sql_command_flags[command] & CF_CHANGES_DATA) != 0;
}
-/*
- Reset per-hour user resource limits when it has been more than
- an hour since they were last checked
-
- SYNOPSIS:
- time_out_user_resource_limits()
- thd Thread handler
- uc User connection details
-
- NOTE:
- This assumes that the LOCK_user_conn mutex has been acquired, so it is
- safe to test and modify members of the USER_CONN structure.
-*/
-
-static void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
-{
- time_t check_time = thd->start_time ? thd->start_time : time(NULL);
- DBUG_ENTER("time_out_user_resource_limits");
-
- /* If more than a hour since last check, reset resource checking */
- if (check_time - uc->intime >= 3600)
- {
- uc->questions=1;
- uc->updates=0;
- uc->conn_per_hour=0;
- uc->intime=check_time;
- }
-
- DBUG_VOID_RETURN;
-}
-
-
-/*
- Check if maximum queries per hour limit has been reached
- returns 0 if OK.
-*/
-
-static bool check_mqh(THD *thd, uint check_command)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- bool error= 0;
- USER_CONN *uc=thd->user_connect;
- DBUG_ENTER("check_mqh");
- DBUG_ASSERT(uc != 0);
-
- (void) pthread_mutex_lock(&LOCK_user_conn);
-
- time_out_user_resource_limits(thd, uc);
-
- /* Check that we have not done too many questions / hour */
- if (uc->user_resources.questions &&
- uc->questions++ >= uc->user_resources.questions)
- {
- net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
- (long) uc->user_resources.questions);
- error=1;
- goto end;
- }
- if (check_command < (uint) SQLCOM_END)
- {
- /* Check that we have not done too many updates / hour */
- if (uc->user_resources.updates &&
- (sql_command_flags[check_command] & CF_CHANGES_DATA) &&
- uc->updates++ >= uc->user_resources.updates)
- {
- net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
- (long) uc->user_resources.updates);
- error=1;
- goto end;
- }
- }
-end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- DBUG_RETURN(error);
-#else
- return (0);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-
-static void reset_mqh(LEX_USER *lu, bool get_them= 0)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- (void) pthread_mutex_lock(&LOCK_user_conn);
- if (lu) // for GRANT
- {
- USER_CONN *uc;
- uint temp_len=lu->user.length+lu->host.length+2;
- char temp_user[USER_HOST_BUFF_SIZE];
-
- memcpy(temp_user,lu->user.str,lu->user.length);
- memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
- temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
- if ((uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len)))
- {
- uc->questions=0;
- get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
- uc->updates=0;
- uc->conn_per_hour=0;
- }
- }
- else
- {
- /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
- for (uint idx=0;idx < hash_user_connections.records; idx++)
- {
- USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
- idx);
- if (get_them)
- get_mqh(uc->user,uc->host,uc);
- uc->questions=0;
- uc->updates=0;
- uc->conn_per_hour=0;
- }
- }
- (void) pthread_mutex_unlock(&LOCK_user_conn);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-void thd_init_client_charset(THD *thd, uint cs_number)
-{
- /*
- Use server character set and collation if
- - opt_character_set_client_handshake is not set
- - client has not specified a character set
- - client character set is the same as the servers
- - client character set doesn't exists in server
- */
- if (!opt_character_set_client_handshake ||
- !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
- !my_strcasecmp(&my_charset_latin1,
- global_system_variables.character_set_client->name,
- thd->variables.character_set_client->name))
- {
- thd->variables.character_set_client=
- global_system_variables.character_set_client;
- thd->variables.collation_connection=
- global_system_variables.collation_connection;
- thd->variables.character_set_results=
- global_system_variables.character_set_results;
- }
- else
- {
- thd->variables.character_set_results=
- thd->variables.collation_connection=
- thd->variables.character_set_client;
- }
-}
-
-
-/*
- Perform handshake, authorize client and update thd ACL variables.
- SYNOPSIS
- check_connection()
- thd thread handle
-
- RETURN
- 0 success, OK is sent to user, thd is updated.
- -1 error, which is sent to user
- > 0 error code (not sent to user)
-*/
-
-#ifndef EMBEDDED_LIBRARY
-static int check_connection(THD *thd)
-{
- uint connect_errors= 0;
- NET *net= &thd->net;
- ulong pkt_len= 0;
- char *end;
-
- DBUG_PRINT("info",
- ("New connection received on %s", vio_description(net->vio)));
-#ifdef SIGNAL_WITH_VIO_CLOSE
- thd->set_active_vio(net->vio);
-#endif
-
- if (!thd->main_security_ctx.host) // If TCP/IP connection
- {
- char ip[30];
-
- if (vio_peer_addr(net->vio, ip, &thd->peer_port))
- return (ER_BAD_HOST_ERROR);
- if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
- return (ER_OUT_OF_RESOURCES);
- thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
- vio_in_addr(net->vio,&thd->remote.sin_addr);
- if (!(specialflag & SPECIAL_NO_RESOLVE))
- {
- vio_in_addr(net->vio,&thd->remote.sin_addr);
- thd->main_security_ctx.host=
- ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
- /* Cut very long hostnames to avoid possible overflows */
- if (thd->main_security_ctx.host)
- {
- if (thd->main_security_ctx.host != my_localhost)
- thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
- HOSTNAME_LENGTH)]= 0;
- thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
- }
- if (connect_errors > max_connect_errors)
- return(ER_HOST_IS_BLOCKED);
- }
- DBUG_PRINT("info",("Host: %s ip: %s",
- (thd->main_security_ctx.host ?
- thd->main_security_ctx.host : "unknown host"),
- (thd->main_security_ctx.ip ?
- thd->main_security_ctx.ip : "unknown ip")));
- if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
- return(ER_HOST_NOT_PRIVILEGED);
- }
- else /* Hostname given means that the connection was on a socket */
- {
- DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
- thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
- thd->main_security_ctx.ip= 0;
- /* Reset sin_addr */
- bzero((char*) &thd->remote, sizeof(thd->remote));
- }
- vio_keepalive(net->vio, TRUE);
- {
- /* buff[] needs to big enough to hold the server_version variable */
- char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
- ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
- CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
-
- if (opt_using_transactions)
- client_flags|=CLIENT_TRANSACTIONS;
-#ifdef HAVE_COMPRESS
- client_flags |= CLIENT_COMPRESS;
-#endif /* HAVE_COMPRESS */
-#ifdef HAVE_OPENSSL
- if (ssl_acceptor_fd)
- client_flags |= CLIENT_SSL; /* Wow, SSL is available! */
-#endif /* HAVE_OPENSSL */
-
- end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
- int4store((uchar*) end, thd->thread_id);
- end+= 4;
- /*
- So as check_connection is the only entry point to authorization
- procedure, scramble is set here. This gives us new scramble for
- each handshake.
- */
- create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
- /*
- Old clients does not understand long scrambles, but can ignore packet
- tail: that's why first part of the scramble is placed here, and second
- part at the end of packet.
- */
- end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
-
- int2store(end, client_flags);
- /* write server characteristics: up to 16 bytes allowed */
- end[2]=(char) default_charset_info->number;
- int2store(end+3, thd->server_status);
- bzero(end+5, 13);
- end+= 18;
- /* write scramble tail */
- end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323,
- SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
-
- /* At this point we write connection message and read reply */
- if (net_write_command(net, (uchar) protocol_version, "", 0, buff,
- (uint) (end-buff)) ||
- (pkt_len= my_net_read(net)) == packet_error ||
- pkt_len < MIN_HANDSHAKE_SIZE)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
- }
-#ifdef _CUSTOMCONFIG_
-#include "_cust_sql_parse.h"
-#endif
- if (connect_errors)
- reset_host_errors(&thd->remote.sin_addr);
- if (thd->packet.alloc(thd->variables.net_buffer_length))
- return(ER_OUT_OF_RESOURCES);
-
- thd->client_capabilities=uint2korr(net->read_pos);
- if (thd->client_capabilities & CLIENT_PROTOCOL_41)
- {
- thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
- thd->max_client_packet_length= uint4korr(net->read_pos+4);
- DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
- thd_init_client_charset(thd, (uint) net->read_pos[8]);
- thd->update_charset();
- end= (char*) net->read_pos+32;
- }
- else
- {
- thd->max_client_packet_length= uint3korr(net->read_pos+2);
- end= (char*) net->read_pos+5;
- }
-
- if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
- thd->variables.sql_mode|= MODE_IGNORE_SPACE;
-#ifdef HAVE_OPENSSL
- DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
- if (thd->client_capabilities & CLIENT_SSL)
- {
- /* Do the SSL layering. */
- if (!ssl_acceptor_fd)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
- DBUG_PRINT("info", ("IO layer change in progress..."));
- if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
- {
- DBUG_PRINT("error", ("Failed to accept new SSL connection"));
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
- DBUG_PRINT("info", ("Reading user information over SSL layer"));
- if ((pkt_len= my_net_read(net)) == packet_error ||
- pkt_len < NORMAL_HANDSHAKE_SIZE)
- {
- DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
- pkt_len));
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
- }
-#endif
-
- if (end >= (char*) net->read_pos+ pkt_len +2)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
-
- if (thd->client_capabilities & CLIENT_INTERACTIVE)
- thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
- if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
- opt_using_transactions)
- net->return_status= &thd->server_status;
- net->read_timeout=(uint) thd->variables.net_read_timeout;
-
- char *user= end;
- char *passwd= strend(user)+1;
- uint user_len= passwd - user - 1;
- char *db= passwd;
- char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
- char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
- uint dummy_errors;
-
- /*
- Old clients send null-terminated string as password; new clients send
- the size (1 byte) + string (not null-terminated). Hence in case of empty
- password both send '\0'.
-
- This strlen() can't be easily deleted without changing protocol.
- */
- uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
- *passwd++ : strlen(passwd);
- db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
- db + passwd_len + 1 : 0;
- /* strlen() can't be easily deleted without changing protocol */
- uint db_len= db ? strlen(db) : 0;
-
- if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return ER_HANDSHAKE_ERROR;
- }
-
- /* Since 4.1 all database names are stored in utf8 */
- if (db)
- {
- db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
- system_charset_info,
- db, db_len,
- thd->charset(), &dummy_errors)]= 0;
- db= db_buff;
- }
-
- user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
- system_charset_info, user, user_len,
- thd->charset(), &dummy_errors)]= '\0';
- user= user_buff;
-
- /* If username starts and ends in "'", chop them off */
- if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
- {
- user[user_len-1]= 0;
- user++;
- user_len-= 2;
- }
-
- if (thd->main_security_ctx.user)
- x_free(thd->main_security_ctx.user);
- if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0))))
- return (ER_OUT_OF_RESOURCES);
- return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
-}
-
void execute_init_command(THD *thd, sys_var_str *init_command_var,
rw_lock_t *var_mutex)
@@ -1128,145 +291,6 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var,
}
-pthread_handler_t handle_one_connection(void *arg)
-{
- THD *thd=(THD*) arg;
- uint launch_time =
- (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
- if (launch_time >= slow_launch_time)
- statistic_increment(slow_launch_threads,&LOCK_status );
-
- pthread_detach_this_thread();
-
-#if !defined( __WIN__) // Win32 calls this in pthread_create
- /* The following calls needs to be done before we call DBUG_ macros */
- if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
- {
- close_connection(thd, ER_OUT_OF_RESOURCES, 1);
- statistic_increment(aborted_connects,&LOCK_status);
- end_thread(thd,0);
- return 0;
- }
-#endif
-
- /*
- handle_one_connection() is the only way a thread would start
- and would always be on top of the stack, therefore, the thread
- stack always starts at the address of the first local variable
- of handle_one_connection, which is thd. We need to know the
- start of the stack so that we could check for stack overruns.
- */
- DBUG_PRINT("info", ("handle_one_connection called by thread %lu\n",
- thd->thread_id));
- /* now that we've called my_thread_init(), it is safe to call DBUG_* */
-
-#if defined(__WIN__)
- init_signals();
-#elif !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
- thd->thread_stack= (char*) &thd;
- if (thd->store_globals())
- {
- close_connection(thd, ER_OUT_OF_RESOURCES, 1);
- statistic_increment(aborted_connects,&LOCK_status);
- end_thread(thd,0);
- return 0;
- }
-
- do
- {
- int error;
- NET *net= &thd->net;
- Security_context *sctx= thd->security_ctx;
- net->no_send_error= 0;
-
- if ((error=check_connection(thd)))
- { // Wrong permissions
- if (error > 0)
- net_printf_error(thd, error, sctx->host_or_ip);
-#ifdef __NT__
- if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
- my_sleep(1000); /* must wait after eof() */
-#endif
- statistic_increment(aborted_connects,&LOCK_status);
- goto end_thread;
- }
-#ifdef __NETWARE__
- netware_reg_user(sctx->ip, sctx->user, "MySQL");
-#endif
- if (thd->variables.max_join_size == HA_POS_ERROR)
- thd->options |= OPTION_BIG_SELECTS;
- if (thd->client_capabilities & CLIENT_COMPRESS)
- net->compress=1; // Use compression
-
- thd->version= refresh_version;
- thd->proc_info= 0;
- thd->command= COM_SLEEP;
- thd->set_time();
- thd->init_for_queries();
-
- if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
- {
- execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
- if (thd->query_error)
- {
- thd->killed= THD::KILL_CONNECTION;
- sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
- thd->thread_id,(thd->db ? thd->db : "unconnected"),
- sctx->user ? sctx->user : "unauthenticated",
- sctx->host_or_ip, "init_connect command failed");
- sql_print_warning("%s", net->last_error);
- }
- thd->proc_info=0;
- thd->set_time();
- thd->init_for_queries();
- }
-
- while (!net->error && net->vio != 0 &&
- !(thd->killed == THD::KILL_CONNECTION))
- {
- net->no_send_error= 0;
- if (do_command(thd))
- break;
- }
- if (thd->user_connect)
- decrease_user_connections(thd->user_connect);
- if (net->error && net->vio != 0 && net->report_error)
- {
- if (!thd->killed && thd->variables.log_warnings > 1)
- sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
- thd->thread_id,(thd->db ? thd->db : "unconnected"),
- sctx->user ? sctx->user : "unauthenticated",
- sctx->host_or_ip,
- (net->last_errno ? ER(net->last_errno) :
- ER(ER_UNKNOWN_ERROR)));
- net_send_error(thd, net->last_errno, NullS);
- statistic_increment(aborted_threads,&LOCK_status);
- }
- else if (thd->killed)
- {
- statistic_increment(aborted_threads,&LOCK_status);
- }
-
-end_thread:
- close_connection(thd, 0, 1);
- end_thread(thd,1);
- /*
- If end_thread returns, we are either running with --one-thread
- or this thread has been schedule to handle the next query
- */
- thd= current_thd;
- thd->thread_stack= (char*) &thd;
- } while (!(test_flags & TEST_NO_THREADS));
- /* The following is only executed if we are not using --one-thread */
- return(0); /* purecov: deadcode */
-}
-
-#endif /* EMBEDDED_LIBRARY */
-
/*
Execute commands from bootstrap_file.
Used when creating the initial grant tables
@@ -1293,11 +317,6 @@ pthread_handler_t handle_bootstrap(void *arg)
#ifndef EMBEDDED_LIBRARY
pthread_detach_this_thread();
thd->thread_stack= (char*) &thd;
-#if !defined(__WIN__) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
#endif /* EMBEDDED_LIBRARY */
if (thd->variables.max_join_size == HA_POS_ERROR)
@@ -1355,6 +374,7 @@ pthread_handler_t handle_bootstrap(void *arg)
mode we have only one thread.
*/
thd->query_id=next_query_id();
+ thd->set_time();
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
if (thd->is_fatal_error)
@@ -1556,7 +576,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
#ifndef EMBEDDED_LIBRARY
/*
- Read one command from socket and execute it (query or simple command).
+ Read one command from connection and execute it (query or simple command).
This function is called in loop from thread function.
SYNOPSIS
do_command()
@@ -1567,24 +587,26 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
bool do_command(THD *thd)
{
- char *packet;
- uint old_timeout;
+ char *packet= 0;
ulong packet_length;
- NET *net;
+ NET *net= &thd->net;
enum enum_server_command command;
DBUG_ENTER("do_command");
- net= &thd->net;
/*
indicator of uninitialized lex => normal flow of errors handling
(see my_message_sql)
*/
thd->lex->current_select= 0;
- packet=0;
- old_timeout=net->read_timeout;
- /* Wait max for 8 hours */
- net->read_timeout=(uint) thd->variables.net_wait_timeout;
+ /*
+ This thread will do a blocking read from the client which
+ will be interrupted when the next command is received from
+ the client, the connection is closed or "net_wait_timeout"
+ number of seconds has passed
+ */
+ net_set_read_timeout(net, thd->variables.net_wait_timeout);
+
thd->clear_error(); // Clear error message
net_new_transaction(net);
@@ -1613,7 +635,10 @@ bool do_command(THD *thd)
vio_description(net->vio), command,
command_name[command].str));
}
- net->read_timeout=old_timeout; // restore it
+
+ /* Restore read timeout value */
+ net_set_read_timeout(net, thd->variables.net_read_timeout);
+
/*
packet_length contains length of data, as it was stored in packet
header. In case of malformed header, packet_length can be zero.
@@ -1664,7 +689,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
thd->set_time();
VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id=query_id;
+ thd->query_id= global_query_id;
if (command != COM_STATISTICS && command != COM_PING)
next_query_id();
thread_running++;
@@ -1858,7 +883,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error)
{
- char *packet= thd->lex->found_semicolon;
+ char *next_packet= thd->lex->found_semicolon;
net->no_send_error= 0;
/*
Multiple queries exits, execute them individually
@@ -1866,24 +891,24 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (thd->lock || thd->open_tables || thd->derived_tables ||
thd->prelocked_mode)
close_thread_tables(thd);
- ulong length= (ulong)(packet_end-packet);
+ ulong length= (ulong)(packet_end - next_packet);
log_slow_statement(thd);
/* Remove garbage at start of query */
- while (my_isspace(thd->charset(), *packet) && length > 0)
+ while (my_isspace(thd->charset(), *next_packet) && length > 0)
{
- packet++;
+ next_packet++;
length--;
}
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_length= length;
- thd->query= packet;
+ thd->query= next_packet;
thd->query_id= next_query_id();
thd->set_time(); /* Reset the query start time. */
/* TODO: set thd->lex->sql_command to SQLCOM_END here */
VOID(pthread_mutex_unlock(&LOCK_thread_count));
- mysql_parse(thd, packet, length);
+ mysql_parse(thd, next_packet, length);
}
if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -1900,11 +925,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
char *fields, *packet_end= packet + packet_length - 1, *arg_end;
/* Locked closure of all tables */
- TABLE_LIST *locked_tables= NULL;
TABLE_LIST table_list;
LEX_STRING conv_name;
- /* Saved variable value */
- my_bool old_innodb_table_locks= thd->variables.innodb_table_locks;
uint dummy;
/* used as fields initializator */
@@ -2074,7 +1096,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
*/
enum mysql_enum_shutdown_level level=
(enum mysql_enum_shutdown_level) (uchar) packet[0];
- DBUG_PRINT("quit",("Got shutdown command for level %u", level));
if (level == SHUTDOWN_DEFAULT)
level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable
else if (level != SHUTDOWN_WAIT_ALL_BUFFERS)
@@ -2118,7 +1139,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS],
&LOCK_status);
calc_sum_of_all_status(&current_global_status_var);
- uptime= (ulong) (thd->start_time - start_time);
+ uptime= (ulong) (thd->start_time - server_start_time);
length= my_snprintf((char*) buff, buff_len - 1,
"Uptime: %lu Threads: %d Questions: %lu "
"Slow queries: %lu Opens: %lu Flush tables: %lu "
@@ -2173,13 +1194,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION],
&LOCK_status);
- enum_mysql_set_option command= (enum_mysql_set_option) uint2korr(packet);
- switch (command) {
- case MYSQL_OPTION_MULTI_STATEMENTS_ON:
+ uint opt_command= uint2korr(packet);
+
+ switch (opt_command) {
+ case (int) MYSQL_OPTION_MULTI_STATEMENTS_ON:
thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
send_eof(thd);
break;
- case MYSQL_OPTION_MULTI_STATEMENTS_OFF:
+ case (int) MYSQL_OPTION_MULTI_STATEMENTS_OFF:
thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
send_eof(thd);
break;
@@ -2492,6 +1514,91 @@ static void reset_one_shot_variables(THD *thd)
}
+static
+bool sp_process_definer(THD *thd)
+{
+ DBUG_ENTER("sp_process_definer");
+
+ LEX *lex= thd->lex;
+
+ /*
+ If the definer is not specified, this means that CREATE-statement missed
+ DEFINER-clause. DEFINER-clause can be missed in two cases:
+
+ - The user submitted a statement w/o the clause. This is a normal
+ case, we should assign CURRENT_USER as definer.
+
+ - Our slave received an updated from the master, that does not
+ replicate definer for stored rountines. We should also assign
+ CURRENT_USER as definer here, but also we should mark this routine
+ as NON-SUID. This is essential for the sake of backward
+ compatibility.
+
+ The problem is the slave thread is running under "special" user (@),
+ that actually does not exist. In the older versions we do not fail
+ execution of a stored routine if its definer does not exist and
+ continue the execution under the authorization of the invoker
+ (BUG#13198). And now if we try to switch to slave-current-user (@),
+ we will fail.
+
+ Actually, this leads to the inconsistent state of master and
+ slave (different definers, different SUID behaviour), but it seems,
+ this is the best we can do.
+ */
+
+ if (!lex->definer)
+ {
+ Query_arena original_arena;
+ Query_arena *ps_arena= thd->activate_stmt_arena_if_needed(&original_arena);
+
+ lex->definer= create_default_definer(thd);
+
+ if (ps_arena)
+ thd->restore_active_arena(ps_arena, &original_arena);
+
+ /* Error has been already reported. */
+ if (lex->definer == NULL)
+ DBUG_RETURN(TRUE);
+
+ if (thd->slave_thread)
+ lex->sphead->m_chistics->suid= SP_IS_NOT_SUID;
+ }
+ else
+ {
+ /*
+ If the specified definer differs from the current user, we
+ should check that the current user has SUPER privilege (in order
+ to create a stored routine under another user one must have
+ SUPER privilege).
+ */
+ if ((strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
+ my_strcasecmp(system_charset_info, lex->definer->host.str,
+ thd->security_ctx->priv_host)) &&
+ check_global_access(thd, SUPER_ACL))
+ {
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
+ DBUG_RETURN(TRUE);
+ }
+ }
+
+ /* Check that the specified definer exists. Emit a warning if not. */
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (!is_acl_user(lex->definer->host.str, lex->definer->user.str))
+ {
+ push_warning_printf(thd,
+ MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_NO_SUCH_USER,
+ ER(ER_NO_SUCH_USER),
+ lex->definer->user.str,
+ lex->definer->host.str);
+ }
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+
+ DBUG_RETURN(FALSE);
+}
+
+
/*
Execute command saved in thd and lex->sql_command
@@ -2521,7 +1628,7 @@ mysql_execute_command(THD *thd)
{
bool res= FALSE;
bool need_start_waiting= FALSE; // have protection against global read lock
- int result= 0;
+ int up_result= 0;
LEX *lex= thd->lex;
/* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
SELECT_LEX *select_lex= &lex->select_lex;
@@ -2576,6 +1683,30 @@ mysql_execute_command(THD *thd)
#ifdef HAVE_REPLICATION
if (unlikely(thd->slave_thread))
{
+ if (lex->sql_command == SQLCOM_DROP_TRIGGER)
+ {
+ /*
+ When dropping a trigger, we need to load its table name
+ before checking slave filter rules.
+ */
+ add_table_for_trigger(thd, thd->lex->spname, 1, &all_tables);
+
+ if (!all_tables)
+ {
+ /*
+ If table name cannot be loaded,
+ it means the trigger does not exists possibly because
+ CREATE TRIGGER was previously skipped for this trigger
+ according to slave filtering rules.
+ Returning success without producing any errors in this case.
+ */
+ DBUG_RETURN(0);
+ }
+
+ // force searching in slave.cc:tables_ok()
+ all_tables->updating= 1;
+ }
+
/*
Check if statment should be skipped because of slave filtering
rules
@@ -3301,7 +2432,9 @@ end_with_restore_list:
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- /* Presumably, REPAIR and binlog writing doesn't require synchronization */
+ /*
+ Presumably, REPAIR and binlog writing doesn't require synchronization
+ */
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
@@ -3334,7 +2467,9 @@ end_with_restore_list:
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- /* Presumably, ANALYZE and binlog writing doesn't require synchronization */
+ /*
+ Presumably, ANALYZE and binlog writing doesn't require synchronization
+ */
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
@@ -3359,7 +2494,9 @@ end_with_restore_list:
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- /* Presumably, OPTIMIZE and binlog writing doesn't require synchronization */
+ /*
+ Presumably, OPTIMIZE and binlog writing doesn't require synchronization
+ */
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
@@ -3377,22 +2514,23 @@ end_with_restore_list:
break;
DBUG_ASSERT(select_lex->offset_limit == 0);
unit->set_limit(select_lex);
- res= (result= mysql_update(thd, all_tables,
- select_lex->item_list,
- lex->value_list,
- select_lex->where,
- select_lex->order_list.elements,
- (ORDER *) select_lex->order_list.first,
- unit->select_limit_cnt,
- lex->duplicates, lex->ignore));
+ res= (up_result= mysql_update(thd, all_tables,
+ select_lex->item_list,
+ lex->value_list,
+ select_lex->where,
+ select_lex->order_list.elements,
+ (ORDER *) select_lex->order_list.first,
+ unit->select_limit_cnt,
+ lex->duplicates, lex->ignore));
/* mysql_update return 2 if we need to switch to multi-update */
- if (result != 2)
+ if (up_result != 2)
break;
+ /* Fall through */
case SQLCOM_UPDATE_MULTI:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
/* if we switched from normal update, rights are checked */
- if (result != 2)
+ if (up_result != 2)
{
if ((res= multi_update_precheck(thd, all_tables)))
break;
@@ -3477,7 +2615,7 @@ end_with_restore_list:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
- select_result *result;
+ select_result *sel_result;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= insert_precheck(thd, all_tables)))
break;
@@ -3506,13 +2644,15 @@ end_with_restore_list:
select_lex->context.table_list=
select_lex->context.first_name_resolution_table= second_table;
res= mysql_insert_select_prepare(thd);
- if (!res && (result= new select_insert(first_table, first_table->table,
- &lex->field_list,
- &lex->update_list,
- &lex->value_list,
- lex->duplicates, lex->ignore)))
+ if (!res && (sel_result= new select_insert(first_table,
+ first_table->table,
+ &lex->field_list,
+ &lex->update_list,
+ &lex->value_list,
+ lex->duplicates,
+ lex->ignore)))
{
- res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
+ res= handle_select(thd, lex, sel_result, OPTION_SETUP_TABLES_DONE);
/*
Invalidate the table in the query cache if something changed
after unlocking when changes become visible.
@@ -3530,7 +2670,7 @@ end_with_restore_list:
first_table->next_local= save_table;
thd->lock=0;
}
- delete result;
+ delete sel_result;
}
/* revert changes for SP */
select_lex->table_list.first= (byte*) first_table;
@@ -3555,7 +2695,7 @@ end_with_restore_list:
break;
}
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_one_table_access(thd, DELETE_ACL, all_tables))
+ if (check_one_table_access(thd, DROP_ACL, all_tables))
goto error;
/*
Don't allow this within a transaction because we want to use
@@ -3596,7 +2736,7 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxiliary_table_list.first;
- multi_delete *result;
+ multi_delete *del_result;
if (!thd->locked_tables &&
!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
@@ -3621,8 +2761,8 @@ end_with_restore_list:
if ((res= mysql_multi_delete_prepare(thd)))
goto error;
- if (!thd->is_fatal_error && (result= new multi_delete(aux_tables,
- lex->table_count)))
+ if (!thd->is_fatal_error &&
+ (del_result= new multi_delete(aux_tables, lex->table_count)))
{
res= mysql_select(thd, &select_lex->ref_pointer_array,
select_lex->get_table_list(),
@@ -3634,8 +2774,8 @@ end_with_restore_list:
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
OPTION_SETUP_TABLES_DONE,
- result, unit, select_lex);
- delete result;
+ del_result, unit, select_lex);
+ delete del_result;
}
else
res= TRUE; // Error
@@ -3992,6 +3132,11 @@ end_with_restore_list:
"function calls as part of this statement");
break;
}
+
+ res= sp_process_definer(thd);
+ if (res)
+ break;
+
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
res= Events::get_instance()->
@@ -4043,7 +3188,6 @@ end_with_restore_list:
lex->spname->m_name);
else
{
- uint affected= 1;
if (!(res= Events::get_instance()->drop_event(thd,
lex->spname->m_db,
lex->spname->m_name,
@@ -4215,7 +3359,7 @@ end_with_restore_list:
{
if (!(user= get_current_user(thd, tmp_user)))
goto error;
- reset_mqh(user);
+ reset_mqh(user, 0);
}
}
}
@@ -4245,7 +3389,9 @@ end_with_restore_list:
We WANT to write and we CAN write.
! we write after unlocking the table.
*/
- /* Presumably, RESET and binlog writing doesn't require synchronization */
+ /*
+ Presumably, RESET and binlog writing doesn't require synchronization
+ */
if (!lex->no_write_to_binlog && write_to_binlog)
{
if (mysql_bin_log.is_open())
@@ -4441,7 +3587,7 @@ end_with_restore_list:
{
uint namelen;
char *name;
- int result= SP_INTERNAL_ERROR;
+ int sp_result= SP_INTERNAL_ERROR;
DBUG_ASSERT(lex->sphead != 0);
DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
@@ -4487,86 +3633,11 @@ end_with_restore_list:
}
#endif
- /*
- If the definer is not specified, this means that CREATE-statement missed
- DEFINER-clause. DEFINER-clause can be missed in two cases:
-
- - The user submitted a statement w/o the clause. This is a normal
- case, we should assign CURRENT_USER as definer.
-
- - Our slave received an updated from the master, that does not
- replicate definer for stored rountines. We should also assign
- CURRENT_USER as definer here, but also we should mark this routine
- as NON-SUID. This is essential for the sake of backward
- compatibility.
-
- The problem is the slave thread is running under "special" user (@),
- that actually does not exist. In the older versions we do not fail
- execution of a stored routine if its definer does not exist and
- continue the execution under the authorization of the invoker
- (BUG#13198). And now if we try to switch to slave-current-user (@),
- we will fail.
-
- Actually, this leads to the inconsistent state of master and
- slave (different definers, different SUID behaviour), but it seems,
- this is the best we can do.
- */
-
- if (!lex->definer)
- {
- bool res= FALSE;
- Query_arena original_arena;
- Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
-
- if (!(lex->definer= create_default_definer(thd)))
- res= TRUE;
-
- if (ps_arena)
- thd->restore_active_arena(ps_arena, &original_arena);
-
- /* Error has been already reported. */
- if (res)
- goto create_sp_error;
-
- if (thd->slave_thread)
- lex->sphead->m_chistics->suid= SP_IS_NOT_SUID;
- }
-
- /*
- If the specified definer differs from the current user, we should check
- that the current user has SUPER privilege (in order to create a stored
- routine under another user one must have SUPER privilege).
- */
-
- else if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
- my_strcasecmp(system_charset_info,
- lex->definer->host.str,
- thd->security_ctx->priv_host))
- {
- if (check_global_access(thd, SUPER_ACL))
- {
- my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
- goto create_sp_error;
- }
- }
-
- /* Check that the specified definer exists. Emit a warning if not. */
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!is_acl_user(lex->definer->host.str,
- lex->definer->user.str))
- {
- push_warning_printf(thd,
- MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_NO_SUCH_USER,
- ER(ER_NO_SUCH_USER),
- lex->definer->user.str,
- lex->definer->host.str);
- }
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+ if (sp_process_definer(thd))
+ goto create_sp_error;
- res= (result= lex->sphead->create(thd));
- switch (result) {
+ res= (sp_result= lex->sphead->create(thd));
+ switch (sp_result) {
case SP_OK:
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* only add privileges if really neccessary */
@@ -4603,10 +3674,7 @@ end_with_restore_list:
clean up the environment.
*/
create_sp_error:
- lex->unit.cleanup();
- delete lex->sphead;
- lex->sphead= 0;
- if (result != SP_OK )
+ if (sp_result != SP_OK )
goto error;
send_ok(thd);
break; /* break super switch */
@@ -4721,7 +3789,7 @@ create_sp_error:
case SQLCOM_ALTER_PROCEDURE:
case SQLCOM_ALTER_FUNCTION:
{
- int result;
+ int sp_result;
sp_head *sp;
st_sp_chistics chistics;
@@ -4736,7 +3804,7 @@ create_sp_error:
if (! sp)
{
if (lex->spname->m_db.str)
- result= SP_KEY_NOT_FOUND;
+ sp_result= SP_KEY_NOT_FOUND;
else
{
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
@@ -4761,7 +3829,7 @@ create_sp_error:
{
my_message(ER_BINLOG_UNSAFE_ROUTINE,
ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0));
- result= SP_INTERNAL_ERROR;
+ sp_result= SP_INTERNAL_ERROR;
}
else
{
@@ -4771,15 +3839,15 @@ create_sp_error:
follow the restrictions that log-bin-trust-function-creators=0
already puts on CREATE FUNCTION.
*/
+ /* Conditionally writes to binlog */
if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
- /* Conditionally writes to binlog */
- result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
+ sp_result= sp_update_procedure(thd, lex->spname,
+ &lex->sp_chistics);
else
- /* Conditionally writes to binlog */
- result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
+ sp_result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
}
}
- switch (result)
+ switch (sp_result)
{
case SP_OK:
send_ok(thd);
@@ -4798,13 +3866,13 @@ create_sp_error:
case SQLCOM_DROP_PROCEDURE:
case SQLCOM_DROP_FUNCTION:
{
- int result;
+ int sp_result;
int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
- result= sp_routine_exists_in_table(thd, type, lex->spname);
+ sp_result= sp_routine_exists_in_table(thd, type, lex->spname);
mysql_reset_errors(thd, 0);
- if (result == SP_OK)
+ if (sp_result == SP_OK)
{
char *db= lex->spname->m_db.str;
char *name= lex->spname->m_name.str;
@@ -4825,12 +3893,11 @@ create_sp_error:
ER(ER_PROC_AUTO_REVOKE_FAIL));
}
#endif
+ /* Conditionally writes to binlog */
if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
- /* Conditionally writes to binlog */
- result= sp_drop_procedure(thd, lex->spname); /* Conditionally writes to binlog */
+ sp_result= sp_drop_procedure(thd, lex->spname);
else
- /* Conditionally writes to binlog */
- result= sp_drop_function(thd, lex->spname); /* Conditionally writes to binlog */
+ sp_result= sp_drop_function(thd, lex->spname);
}
else
{
@@ -4854,16 +3921,15 @@ create_sp_error:
}
#endif
if (lex->spname->m_db.str)
- result= SP_KEY_NOT_FOUND;
+ sp_result= SP_KEY_NOT_FOUND;
else
{
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
goto error;
}
}
- res= result;
- switch (result)
- {
+ res= sp_result;
+ switch (sp_result) {
case SP_OK:
send_ok(thd);
break;
@@ -4983,9 +4049,6 @@ create_sp_error:
/* Conditionally writes to binlog. */
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;
break;
}
case SQLCOM_DROP_TRIGGER:
@@ -5631,7 +4694,9 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
{
uint found=0;
ulong found_access=0;
+#ifndef EMBEDDED_LIBRARY
TABLE_LIST *org_tables= tables;
+#endif
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx;
/*
@@ -6137,12 +5202,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
else
#endif
{
- if (thd->net.report_error)
- {
- delete lex->sphead;
- lex->sphead= NULL;
- }
- else
+ if (! thd->net.report_error)
{
/*
Binlog logs a string starting from thd->query and having length
@@ -6162,7 +5222,6 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
query_cache_end_of_result(thd);
}
}
- lex->unit.cleanup();
}
else
{
@@ -6170,19 +5229,14 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
thd->is_fatal_error));
- /*
- The first thing we do after parse error is freeing sp_head to
- ensure that we have restored original memroot.
- */
- if (lex->sphead)
- {
- /* Clean up after failed stored procedure/function */
- delete lex->sphead;
- lex->sphead= NULL;
- }
query_cache_abort(&thd->net);
- lex->unit.cleanup();
}
+ if (thd->lex->sphead)
+ {
+ delete thd->lex->sphead;
+ thd->lex->sphead= 0;
+ }
+ lex->unit.cleanup();
thd->proc_info="freeing items";
thd->end_statement();
thd->cleanup_after_query();
@@ -6565,6 +5619,7 @@ bool st_select_lex::init_nested_join(THD *thd)
join_list->push_front(ptr);
ptr->embedding= embedding;
ptr->join_list= join_list;
+ ptr->alias= (char*) "(nested_join)";
embedding= ptr;
join_list= &nested_join->join_list;
join_list->empty();
@@ -6649,6 +5704,7 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
ptr->embedding= embedding;
ptr->join_list= join_list;
+ ptr->alias= (char*) "(nest_last_join)";
embedded_list= &nested_join->join_list;
embedded_list->empty();
@@ -6665,11 +5721,8 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
If this is a JOIN ... USING, move the list of joined fields to the
table reference that describes the join.
*/
- if (table->join_using_fields)
- {
- ptr->join_using_fields= table->join_using_fields;
- table->join_using_fields= NULL;
- }
+ if (prev_join_using)
+ ptr->join_using_fields= prev_join_using;
}
}
join_list->push_front(ptr);
@@ -6805,18 +5858,18 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
0 on success
*/
-bool st_select_lex_unit::add_fake_select_lex(THD *thd)
+bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
{
SELECT_LEX *first_sl= first_select();
DBUG_ENTER("add_fake_select_lex");
DBUG_ASSERT(!fake_select_lex);
- if (!(fake_select_lex= new (thd->mem_root) SELECT_LEX()))
+ if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX()))
DBUG_RETURN(1);
fake_select_lex->include_standalone(this,
(SELECT_LEX_NODE**)&fake_select_lex);
fake_select_lex->select_number= INT_MAX;
- fake_select_lex->parent_lex= thd->lex; /* Used in init_query. */
+ fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */
fake_select_lex->make_empty_select();
fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
fake_select_lex->select_limit= 0;
@@ -6836,9 +5889,9 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd)
*/
global_parameters= fake_select_lex;
fake_select_lex->no_table_names_allowed= 1;
- thd->lex->current_select= fake_select_lex;
+ thd_arg->lex->current_select= fake_select_lex;
}
- thd->lex->pop_context();
+ thd_arg->lex->pop_context();
DBUG_RETURN(0);
}
@@ -6925,6 +5978,7 @@ void add_join_on(TABLE_LIST *b, Item *expr)
a Left join argument
b Right join argument
using_fields Field names from USING clause
+ lex The current st_select_lex
IMPLEMENTATION
This function marks that table b should be joined with a either via
@@ -6953,10 +6007,11 @@ void add_join_on(TABLE_LIST *b, Item *expr)
None
*/
-void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields)
+void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
+ SELECT_LEX *lex)
{
b->natural_join= a;
- b->join_using_fields= using_fields;
+ lex->prev_join_using= using_fields;
}
@@ -7144,7 +6199,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
}
#endif
if (options & REFRESH_USER_RESOURCES)
- reset_mqh((LEX_USER *) NULL);
+ reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
*write_to_binlog= tmp_write_to_binlog;
return result;
}
diff --git a/sql/sql_parse.cc.rej b/sql/sql_parse.cc.rej
deleted file mode 100644
index 6e2bd03867d..00000000000
--- a/sql/sql_parse.cc.rej
+++ /dev/null
@@ -1,166 +0,0 @@
-***************
-*** 67,109 ****
- static void decrease_user_connections(USER_CONN *uc);
- #endif /* NO_EMBEDDED_ACCESS_CHECKS */
- static bool check_multi_update_lock(THD *thd);
-- static void remove_escape(char *name);
- static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
-
- const char *any_db="*any*"; // Special symbol for check_access
-
-! LEX_STRING command_name[]={
-! (char *)STRING_WITH_LEN("Sleep"),
-! (char *)STRING_WITH_LEN("Quit"),
-! (char *)STRING_WITH_LEN("Init DB"),
-! (char *)STRING_WITH_LEN("Query"),
-! (char *)STRING_WITH_LEN("Field List"),
-! (char *)STRING_WITH_LEN("Create DB"),
-! (char *)STRING_WITH_LEN("Drop DB"),
-! (char *)STRING_WITH_LEN("Refresh"),
-! (char *)STRING_WITH_LEN("Shutdown"),
-! (char *)STRING_WITH_LEN("Statistics"),
-! (char *)STRING_WITH_LEN("Processlist"),
-! (char *)STRING_WITH_LEN("Connect"),
-! (char *)STRING_WITH_LEN("Kill"),
-! (char *)STRING_WITH_LEN("Debug"),
-! (char *)STRING_WITH_LEN("Ping"),
-! (char *)STRING_WITH_LEN("Time"),
-! (char *)STRING_WITH_LEN("Delayed insert"),
-! (char *)STRING_WITH_LEN("Change user"),
-! (char *)STRING_WITH_LEN("Binlog Dump"),
-! (char *)STRING_WITH_LEN("Table Dump"),
-! (char *)STRING_WITH_LEN("Connect Out"),
-! (char *)STRING_WITH_LEN("Register Slave"),
-! (char *)STRING_WITH_LEN("Prepare"),
-! (char *)STRING_WITH_LEN("Execute"),
-! (char *)STRING_WITH_LEN("Long Data"),
-! (char *)STRING_WITH_LEN("Close stmt"),
-! (char *)STRING_WITH_LEN("Reset stmt"),
-! (char *)STRING_WITH_LEN("Set option"),
-! (char *)STRING_WITH_LEN("Fetch"),
-! (char *)STRING_WITH_LEN("Daemon"),
-! (char *)STRING_WITH_LEN("Error") // Last command number
- };
-
- const char *xa_state_names[]={
---- 67,108 ----
- static void decrease_user_connections(USER_CONN *uc);
- #endif /* NO_EMBEDDED_ACCESS_CHECKS */
- static bool check_multi_update_lock(THD *thd);
- static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
-
- const char *any_db="*any*"; // Special symbol for check_access
-
-! const LEX_STRING command_name[]={
-! C_STRING_WITH_LEN("Sleep"),
-! C_STRING_WITH_LEN("Quit"),
-! C_STRING_WITH_LEN("Init DB"),
-! C_STRING_WITH_LEN("Query"),
-! C_STRING_WITH_LEN("Field List"),
-! C_STRING_WITH_LEN("Create DB"),
-! C_STRING_WITH_LEN("Drop DB"),
-! C_STRING_WITH_LEN("Refresh"),
-! C_STRING_WITH_LEN("Shutdown"),
-! C_STRING_WITH_LEN("Statistics"),
-! C_STRING_WITH_LEN("Processlist"),
-! C_STRING_WITH_LEN("Connect"),
-! C_STRING_WITH_LEN("Kill"),
-! C_STRING_WITH_LEN("Debug"),
-! C_STRING_WITH_LEN("Ping"),
-! C_STRING_WITH_LEN("Time"),
-! C_STRING_WITH_LEN("Delayed insert"),
-! C_STRING_WITH_LEN("Change user"),
-! C_STRING_WITH_LEN("Binlog Dump"),
-! C_STRING_WITH_LEN("Table Dump"),
-! C_STRING_WITH_LEN("Connect Out"),
-! C_STRING_WITH_LEN("Register Slave"),
-! C_STRING_WITH_LEN("Prepare"),
-! C_STRING_WITH_LEN("Execute"),
-! C_STRING_WITH_LEN("Long Data"),
-! C_STRING_WITH_LEN("Close stmt"),
-! C_STRING_WITH_LEN("Reset stmt"),
-! C_STRING_WITH_LEN("Set option"),
-! C_STRING_WITH_LEN("Fetch"),
-! C_STRING_WITH_LEN("Daemon"),
-! C_STRING_WITH_LEN("Error") // Last command number
- };
-
- const char *xa_state_names[]={
-***************
-*** 1738,1744 ****
- password. New clients send the size (1 byte) + string (not null
- terminated, so also '\0' for empty string).
- */
-! char db_buff[NAME_LEN+1]; // buffer to store db in utf8
- char *db= passwd;
- uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
- *passwd++ : strlen(passwd);
---- 1736,1742 ----
- password. New clients send the size (1 byte) + string (not null
- terminated, so also '\0' for empty string).
- */
-! char db_buff[NAME_LEN+1]; // buffer to store db in utf8
- char *db= passwd;
- uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
- *passwd++ : strlen(passwd);
-***************
-*** 2315,2321 ****
- DBUG_RETURN(1);
- }
- db= lex->select_lex.db;
-- remove_escape(db); // Fix escaped '_'
- if (check_db_name(db))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), db);
---- 2312,2317 ----
- DBUG_RETURN(1);
- }
- db= lex->select_lex.db;
- if (check_db_name(db))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), db);
-***************
-*** 6310,6345 ****
- }
-
-
-- /* Fix escaping of _, % and \ in database and table names (for ODBC) */
--
-- static void remove_escape(char *name)
-- {
-- if (!*name) // For empty DB names
-- return;
-- char *to;
-- #ifdef USE_MB
-- char *strend=name+(uint) strlen(name);
-- #endif
-- for (to=name; *name ; name++)
-- {
-- #ifdef USE_MB
-- int l;
-- if (use_mb(system_charset_info) &&
-- (l = my_ismbchar(system_charset_info, name, strend)))
-- {
-- while (l--)
-- *to++ = *name++;
-- name--;
-- continue;
-- }
-- #endif
-- if (*name == '\\' && name[1])
-- name++; // Skip '\\'
-- *to++= *name;
-- }
-- *to=0;
-- }
--
- /****************************************************************************
- ** save order by and tables in own lists
- ****************************************************************************/
---- 6296,6301 ----
- }
-
-
- /****************************************************************************
- ** save order by and tables in own lists
- ****************************************************************************/
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 0b6d841a337..dbac53ed5f6 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -2002,7 +2002,6 @@ char *generate_partition_syntax(partition_info *part_info,
{
uint i,j, tot_no_parts, no_subparts;
partition_element *part_elem;
- partition_element *save_part_elem= NULL;
ulonglong buffer_length;
char path[FN_REFLEN];
int err= 0;
@@ -5369,7 +5368,6 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
List_iterator<partition_element> temp_it(part_info->temp_partitions);
uint no_temp_partitions= part_info->temp_partitions.elements;
uint no_elements= part_info->partitions.elements;
- uint i= 0;
DBUG_ENTER("write_log_dropped_partitions");
ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
@@ -5742,7 +5740,6 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt,
bool dont_crash)
{
partition_info *part_info= lpt->part_info;
- uint count_loop= 0;
DDL_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry;
DBUG_ENTER("write_log_completed");
@@ -6016,8 +6013,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
uint fast_alter_partition)
{
/* Set-up struct used to write frm files */
- ulonglong copied= 0;
- ulonglong deleted= 0;
partition_info *part_info= table->part_info;
ALTER_PARTITION_PARAM_TYPE lpt_obj;
ALTER_PARTITION_PARAM_TYPE *lpt= &lpt_obj;
@@ -6736,7 +6731,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
}
}
else
- DBUG_ASSERT(0);
+ assert(0);
/*
Find minimum: Do special handling if the interval has left bound in form
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 1d711b7835c..e3e24c1f375 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -31,25 +31,37 @@ const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{ C_STRING_WITH_LEN("UDF") },
{ C_STRING_WITH_LEN("STORAGE ENGINE") },
{ C_STRING_WITH_LEN("FTPARSER") },
- { C_STRING_WITH_LEN("DAEMON") }
+ { C_STRING_WITH_LEN("DAEMON") },
+ { C_STRING_WITH_LEN("INFORMATION SCHEMA") }
};
+extern int initialize_schema_table(st_plugin_int *plugin);
+extern int finalize_schema_table(st_plugin_int *plugin);
+
+/*
+ The number of elements in both plugin_type_initialize and
+ plugin_type_deinitialize should equal to the number of plugins
+ defined.
+*/
plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
- 0,ha_initialize_handlerton,0,0
+ 0,ha_initialize_handlerton,0,0,initialize_schema_table
};
plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
- 0,ha_finalize_handlerton,0,0
+ 0,ha_finalize_handlerton,0,0,finalize_schema_table
};
+#ifdef HAVE_DLOPEN
static const char *plugin_interface_version_sym=
"_mysql_plugin_interface_version_";
static const char *sizeof_st_plugin_sym=
"_mysql_sizeof_struct_st_plugin_";
static const char *plugin_declarations_sym= "_mysql_plugin_declarations_";
static int min_plugin_interface_version= MYSQL_PLUGIN_INTERFACE_VERSION & ~0xFF;
+#endif
+
/* Note that 'int version' must be the first field of every plugin
sub-structure (plugin->info).
*/
@@ -58,14 +70,16 @@ static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
0x0000,
MYSQL_HANDLERTON_INTERFACE_VERSION,
MYSQL_FTPARSER_INTERFACE_VERSION,
- MYSQL_DAEMON_INTERFACE_VERSION
+ MYSQL_DAEMON_INTERFACE_VERSION,
+ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
};
static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
0x0000, /* UDF: not implemented */
MYSQL_HANDLERTON_INTERFACE_VERSION,
MYSQL_FTPARSER_INTERFACE_VERSION,
- MYSQL_DAEMON_INTERFACE_VERSION
+ MYSQL_DAEMON_INTERFACE_VERSION,
+ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
};
static DYNAMIC_ARRAY plugin_dl_array;
@@ -80,6 +94,8 @@ static int plugin_array_version=0;
my_bool plugin_register_builtin(struct st_mysql_plugin *plugin);
void plugin_load(void);
+#ifdef HAVE_DLOPEN
+
static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *dl)
{
uint i;
@@ -117,6 +133,8 @@ static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl)
DBUG_RETURN(dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1,
struct st_plugin_dl *));
}
+#endif /* HAVE_DLOPEN */
+
static inline void free_plugin_mem(struct st_plugin_dl *p)
{
@@ -534,6 +552,8 @@ static void plugin_del(struct st_plugin_int *plugin)
DBUG_VOID_RETURN;
}
+#ifdef NOT_USED
+
static void plugin_del(const LEX_STRING *name)
{
struct st_plugin_int *plugin;
@@ -543,6 +563,8 @@ static void plugin_del(const LEX_STRING *name)
DBUG_VOID_RETURN;
}
+#endif
+
void plugin_unlock(struct st_plugin_int *plugin)
{
DBUG_ENTER("plugin_unlock");
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 57f7ee056d7..d4db2f536e5 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -34,6 +34,12 @@ When one prepares a statement:
[Params meta info (stubs only for now)] (if Param_count > 0)
[Columns meta info] (if Column_count > 0)
+ During prepare the tables used in a statement are opened, but no
+ locks are acquired. Table opening will block any DDL during the
+ operation, and we do not need any locks as we neither read nor
+ modify any data during prepare. Tables are closed after prepare
+ finishes.
+
When one executes a statement:
- Server gets the command 'COM_STMT_EXECUTE' to execute the
@@ -53,6 +59,10 @@ When one executes a statement:
- Execute the query without re-parsing and send back the results
to client
+ During execution of prepared statement tables are opened and locked
+ the same way they would for normal (non-prepared) statement
+ execution. Tables are unlocked and closed after the execution.
+
When one supplies long data for a placeholder:
- Server gets the long data in pieces with command type
@@ -99,9 +109,12 @@ public:
#endif
};
-/******************************************************************************
- Prepared_statement: a statement that can contain placeholders
-******************************************************************************/
+/****************************************************************************/
+
+/**
+ @class Prepared_statement
+ @brief Prepared_statement: a statement that can contain placeholders
+*/
class Prepared_statement: public Statement
{
@@ -141,6 +154,16 @@ public:
bool execute(String *expanded_query, bool open_cursor);
/* Destroy this statement */
bool deallocate();
+private:
+ /**
+ Store the parsed tree of a prepared statement here.
+ */
+ LEX main_lex;
+ /**
+ The memory root to allocate parsed tree elements (instances of Item,
+ SELECT_LEX and other classes).
+ */
+ MEM_ROOT main_mem_root;
};
@@ -976,19 +999,19 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
/* Insert @'escaped-varname' instead of parameter in the query */
if (entry)
{
- char *begin, *ptr;
+ char *start, *ptr;
buf.length(0);
if (buf.reserve(entry->name.length*2+3))
DBUG_RETURN(1);
- begin= ptr= buf.c_ptr_quick();
+ start= ptr= buf.c_ptr_quick();
*ptr++= '@';
*ptr++= '\'';
ptr+= escape_string_for_mysql(&my_charset_utf8_general_ci,
ptr, 0, entry->name.str,
entry->name.length);
*ptr++= '\'';
- buf.length(ptr - begin);
+ buf.length(ptr - start);
val= &buf;
}
else
@@ -1026,7 +1049,6 @@ static bool mysql_test_insert(Prepared_statement *stmt,
enum_duplicates duplic)
{
THD *thd= stmt->thd;
- LEX *lex= stmt->lex;
List_iterator_fast<List_item> its(values_list);
List_item *values;
DBUG_ENTER("mysql_test_insert");
@@ -1117,41 +1139,22 @@ static int mysql_test_update(Prepared_statement *stmt,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint want_privilege;
#endif
- bool need_reopen;
DBUG_ENTER("mysql_test_update");
- if (update_precheck(thd, table_list))
+ if (update_precheck(thd, table_list) ||
+ open_normal_and_derived_tables(thd, table_list, 0))
goto error;
- for ( ; ; )
+ if (table_list->multitable_view)
{
- if (open_tables(thd, &table_list, &table_count, 0))
- goto error;
-
- if (table_list->multitable_view)
- {
- DBUG_ASSERT(table_list->view != 0);
- DBUG_PRINT("info", ("Switch to multi-update"));
- /* pass counter value */
- thd->lex->table_count= table_count;
- /* convert to multiupdate */
- DBUG_RETURN(2);
- }
-
- if (!lock_tables(thd, table_list, table_count, &need_reopen))
- break;
- if (!need_reopen)
- goto error;
- close_tables_for_reopen(thd, &table_list);
+ DBUG_ASSERT(table_list->view != 0);
+ DBUG_PRINT("info", ("Switch to multi-update"));
+ /* pass counter value */
+ thd->lex->table_count= table_count;
+ /* convert to multiupdate */
+ DBUG_RETURN(2);
}
- /*
- thd->fill_derived_tables() is false here for sure (because it is
- preparation of PS, so we even do not check it).
- */
- if (mysql_handle_derived(thd->lex, &mysql_derived_prepare))
- goto error;
-
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* TABLE_LIST contain right privilages request */
want_privilege= table_list->grant.want_privilege;
@@ -1209,7 +1212,7 @@ static bool mysql_test_delete(Prepared_statement *stmt,
DBUG_ENTER("mysql_test_delete");
if (delete_precheck(thd, table_list) ||
- open_and_lock_tables(thd, table_list))
+ open_normal_and_derived_tables(thd, table_list, 0))
goto error;
if (!table_list->table)
@@ -1268,7 +1271,7 @@ static int mysql_test_select(Prepared_statement *stmt,
goto error;
}
- if (open_and_lock_tables(thd, tables))
+ if (open_normal_and_derived_tables(thd, tables, 0))
goto error;
thd->used_tables= 0; // Updated by setup_fields
@@ -1329,7 +1332,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
DBUG_RETURN(TRUE);
- if (open_and_lock_tables(thd, tables))
+ if (open_normal_and_derived_tables(thd, tables, 0))
DBUG_RETURN(TRUE);
DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0));
}
@@ -1359,7 +1362,7 @@ static bool mysql_test_set_fields(Prepared_statement *stmt,
set_var_base *var;
if (tables && check_table_access(thd, SELECT_ACL, tables, 0) ||
- open_and_lock_tables(thd, tables))
+ open_normal_and_derived_tables(thd, tables, 0))
goto error;
while ((var= it++))
@@ -1385,7 +1388,7 @@ error:
NOTE
This function won't directly open tables used in select. They should
be opened either by calling function (and in this case you probably
- should use select_like_stmt_test_with_open_n_lock()) or by
+ should use select_like_stmt_test_with_open()) or by
"specific_prepare" call (like this happens in case of multi-update).
RETURN VALUE
@@ -1413,14 +1416,14 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
}
/*
- Check internal SELECT of the prepared command (with opening and
- locking of used tables).
+ Check internal SELECT of the prepared command (with opening of used
+ tables).
SYNOPSIS
- select_like_stmt_test_with_open_n_lock()
+ select_like_stmt_test_with_open()
stmt prepared statement
- tables list of tables to be opened and locked
- before calling specific_prepare function
+ tables list of tables to be opened before calling
+ specific_prepare function
specific_prepare function of command specific prepare
setup_tables_done_option options to be passed to LEX::unit.prepare()
@@ -1430,19 +1433,20 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
*/
static bool
-select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt,
- TABLE_LIST *tables,
- bool (*specific_prepare)(THD *thd),
- ulong setup_tables_done_option)
+select_like_stmt_test_with_open(Prepared_statement *stmt,
+ TABLE_LIST *tables,
+ bool (*specific_prepare)(THD *thd),
+ ulong setup_tables_done_option)
{
- DBUG_ENTER("select_like_stmt_test_with_open_n_lock");
+ DBUG_ENTER("select_like_stmt_test_with_open");
/*
- We should not call LEX::unit.cleanup() after this open_and_lock_tables()
- call because we don't allow prepared EXPLAIN yet so derived tables will
- clean up after themself.
+ We should not call LEX::unit.cleanup() after this
+ open_normal_and_derived_tables() call because we don't allow
+ prepared EXPLAIN yet so derived tables will clean up after
+ themself.
*/
- if (open_and_lock_tables(stmt->thd, tables))
+ if (open_normal_and_derived_tables(stmt->thd, tables, 0))
DBUG_RETURN(TRUE);
DBUG_RETURN(select_like_stmt_test(stmt, specific_prepare,
@@ -1481,7 +1485,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
if (select_lex->item_list.elements)
{
select_lex->context.resolve_in_select_list= TRUE;
- res= select_like_stmt_test_with_open_n_lock(stmt, tables, 0, 0);
+ res= select_like_stmt_test_with_open(stmt, tables, 0, 0);
}
/* put tables back for PS rexecuting */
@@ -1541,9 +1545,9 @@ static bool mysql_test_multidelete(Prepared_statement *stmt,
}
if (multi_delete_precheck(stmt->thd, tables) ||
- select_like_stmt_test_with_open_n_lock(stmt, tables,
- &mysql_multi_delete_prepare,
- OPTION_SETUP_TABLES_DONE))
+ select_like_stmt_test_with_open(stmt, tables,
+ &mysql_multi_delete_prepare,
+ OPTION_SETUP_TABLES_DONE))
goto error;
if (!tables->table)
{
@@ -1559,34 +1563,30 @@ error:
/*
Wrapper for mysql_insert_select_prepare, to make change of local tables
- after open_and_lock_tables() call.
+ after open_normal_and_derived_tables() call.
SYNOPSIS
mysql_insert_select_prepare_tester()
thd thread handle
NOTE
- We need to remove the first local table after open_and_lock_tables,
- because mysql_handle_derived uses local tables lists.
+ We need to remove the first local table after
+ open_normal_and_derived_tables(), because mysql_handle_derived
+ uses local tables lists.
*/
static bool mysql_insert_select_prepare_tester(THD *thd)
{
- TABLE_LIST *first;
- bool res;
SELECT_LEX *first_select= &thd->lex->select_lex;
+ TABLE_LIST *second_table= ((TABLE_LIST*)first_select->table_list.first)->
+ next_local;
+
/* Skip first table, which is the table we are inserting in */
- first_select->table_list.first= (byte*)(first=
- ((TABLE_LIST*)first_select->
- table_list.first)->next_local);
- res= mysql_insert_select_prepare(thd);
- /*
- insert/replace from SELECT give its SELECT_LEX for SELECT,
- and item_list belong to SELECT
- */
- thd->lex->select_lex.context.resolve_in_select_list= TRUE;
- thd->lex->select_lex.context.table_list= first;
- return res;
+ first_select->table_list.first= (byte *) second_table;
+ thd->lex->select_lex.context.table_list=
+ thd->lex->select_lex.context.first_name_resolution_table= second_table;
+
+ return mysql_insert_select_prepare(thd);
}
@@ -1624,9 +1624,9 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
DBUG_ASSERT(first_local_table != 0);
res=
- select_like_stmt_test_with_open_n_lock(stmt, tables,
- &mysql_insert_select_prepare_tester,
- OPTION_SETUP_TABLES_DONE);
+ select_like_stmt_test_with_open(stmt, tables,
+ &mysql_insert_select_prepare_tester,
+ OPTION_SETUP_TABLES_DONE);
/* revert changes made by mysql_insert_select_prepare_tester */
lex->select_lex.table_list.first= (byte*) first_local_table;
return res;
@@ -1677,7 +1677,7 @@ static bool check_prepared_statement(Prepared_statement *stmt,
case SQLCOM_INSERT:
res= mysql_test_insert(stmt, tables, lex->field_list,
lex->many_values,
- select_lex->item_list, lex->value_list,
+ lex->update_list, lex->value_list,
lex->duplicates);
break;
@@ -2054,6 +2054,7 @@ void mysql_sql_stmt_prepare(THD *thd)
const char *query;
uint query_len;
DBUG_ENTER("mysql_sql_stmt_prepare");
+ LINT_INIT(query_len);
DBUG_ASSERT(thd->protocol == &thd->protocol_text);
if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
@@ -2078,6 +2079,7 @@ void mysql_sql_stmt_prepare(THD *thd)
delete stmt;
DBUG_VOID_RETURN;
}
+
if (thd->stmt_map.insert(thd, stmt))
{
/* The statement is deleted and an error is set if insert fails */
@@ -2243,11 +2245,11 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
{
uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround
ulong stmt_id= uint4korr(packet);
- ulong flags= (ulong) ((uchar) packet[4]);
+ ulong flags= (ulong) packet[4];
/* Query text for binary, general or slow log, if any of them is open */
String expanded_query;
#ifndef EMBEDDED_LIBRARY
- uchar *packet_end= (uchar *) packet + packet_length - 1;
+ uchar *packet_end= packet + packet_length - 1;
#endif
Prepared_statement *stmt;
bool error;
@@ -2270,9 +2272,9 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
#ifndef EMBEDDED_LIBRARY
if (stmt->param_count)
{
- uchar *null_array= (uchar *) packet;
- if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) ||
- stmt->set_params(stmt, null_array, (uchar *) packet, packet_end,
+ uchar *null_array= packet;
+ if (setup_conversion_functions(stmt, &packet, packet_end) ||
+ stmt->set_params(stmt, null_array, packet, packet_end,
&expanded_query))
goto set_params_data_err;
}
@@ -2566,7 +2568,9 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
uint param_number;
Prepared_statement *stmt;
Item_param *param;
+#ifndef EMBEDDED_LIBRARY
char *packet_end= packet + packet_length - 1;
+#endif
DBUG_ENTER("mysql_stmt_get_longdata");
statistic_increment(thd->status_var.com_stmt_send_long_data, &LOCK_status);
@@ -2620,8 +2624,8 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
Select_fetch_protocol_binary
****************************************************************************/
-Select_fetch_protocol_binary::Select_fetch_protocol_binary(THD *thd)
- :protocol(thd)
+Select_fetch_protocol_binary::Select_fetch_protocol_binary(THD *thd_arg)
+ :protocol(thd_arg)
{}
bool Select_fetch_protocol_binary::send_fields(List<Item> &list, uint flags)
@@ -2670,17 +2674,18 @@ Select_fetch_protocol_binary::send_data(List<Item> &fields)
****************************************************************************/
Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg)
- :Statement(INITIALIZED, ++thd_arg->statement_id_counter,
- thd_arg->variables.query_alloc_block_size,
- thd_arg->variables.query_prealloc_size),
+ :Statement(&main_lex, &main_mem_root,
+ INITIALIZED, ++thd_arg->statement_id_counter),
thd(thd_arg),
result(thd_arg),
protocol(protocol_arg),
param_array(0),
param_count(0),
last_errno(0),
- flags((uint) IS_IN_USE)
+ flags((uint) IS_IN_USE)
{
+ init_alloc_root(&main_mem_root, thd_arg->variables.query_alloc_block_size,
+ thd_arg->variables.query_prealloc_size);
*last_error= '\0';
}
@@ -2730,6 +2735,7 @@ Prepared_statement::~Prepared_statement()
*/
free_items();
delete lex->result;
+ free_root(&main_mem_root, MYF(0));
DBUG_VOID_RETURN;
}
@@ -2745,6 +2751,7 @@ void Prepared_statement::cleanup_stmt()
DBUG_ENTER("Prepared_statement::cleanup_stmt");
DBUG_PRINT("enter",("stmt: 0x%lx", (long) this));
+ DBUG_ASSERT(lex->sphead == 0);
/* The order is important */
lex->unit.cleanup();
cleanup_items(free_list);
@@ -2830,18 +2837,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
error= MYSQLparse((void *)thd) || thd->is_fatal_error ||
thd->net.report_error || init_param_array(this);
- /*
- The first thing we do after parse error is freeing sp_head to
- ensure that we have restored original memroot.
- */
- if (error && lex->sphead)
- {
- delete lex->sphead;
- lex->sphead= NULL;
- }
-
lex->safe_to_cache_query= FALSE;
-
/*
While doing context analysis of the query (in check_prepared_statement)
we allocate a lot of additional memory: for open tables, JOINs, derived
@@ -2867,12 +2863,18 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
if (error == 0)
error= check_prepared_statement(this, name.str != 0);
- /* Free sp_head if check_prepared_statement() failed. */
- if (error && lex->sphead)
+ /*
+ Currently CREATE PROCEDURE/TRIGGER/EVENT are prohibited in prepared
+ statements: ensure we have no memory leak here if by someone tries
+ to PREPARE stmt FROM "CREATE PROCEDURE ..."
+ */
+ DBUG_ASSERT(lex->sphead == NULL || error != 0);
+ if (lex->sphead)
{
delete lex->sphead;
lex->sphead= NULL;
}
+
lex_end(lex);
cleanup_stmt();
thd->restore_backup_statement(this, &stmt_backup);
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index a7b168fe47f..debc9a7b572 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -23,7 +23,9 @@
int max_binlog_dump_events = 0; // unlimited
my_bool opt_sporadic_binlog_dump_fail = 0;
+#ifndef DBUG_OFF
static int binlog_dump_count = 0;
+#endif
/*
fake_rotate_event() builds a fake (=which does not exist physically in any
@@ -92,8 +94,8 @@ static int send_file(THD *thd)
The client might be slow loading the data, give him wait_timeout to do
the job
*/
- old_timeout = thd->net.read_timeout;
- thd->net.read_timeout = thd->variables.net_wait_timeout;
+ old_timeout= net->read_timeout;
+ net_set_read_timeout(net, thd->variables.net_wait_timeout);
/*
We need net_flush here because the client will not know it needs to send
@@ -137,7 +139,7 @@ static int send_file(THD *thd)
error = 0;
err:
- thd->net.read_timeout = old_timeout;
+ net_set_read_timeout(net, old_timeout);
if (fd >= 0)
(void) my_close(fd, MYF(0));
if (errmsg)
@@ -884,12 +886,14 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report )
{
+ DBUG_ENTER("stop_slave");
+
int slave_errno;
if (!thd)
thd = current_thd;
if (check_access(thd, SUPER_ACL, any_db,0,0,0,0))
- return 1;
+ DBUG_RETURN(1);
thd->proc_info = "Killing slave";
int thread_mask;
lock_slave_threads(mi);
@@ -923,12 +927,12 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report )
{
if (net_report)
my_message(slave_errno, ER(slave_errno), MYF(0));
- return 1;
+ DBUG_RETURN(1);
}
else if (net_report)
send_ok(thd);
- return 0;
+ DBUG_RETURN(0);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 919024ba457..2da2261d3e1 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -109,7 +109,6 @@ static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list,
static COND *optimize_cond(JOIN *join, COND *conds,
List<TABLE_LIST> *join_list,
Item::cond_result *cond_value);
-static bool resolve_nested_join (TABLE_LIST *table);
static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
static bool open_tmp_table(TABLE *table);
static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
@@ -269,6 +268,70 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
/*
+ Fix fields referenced from inner selects.
+
+ SYNOPSIS
+ fix_inner_refs()
+ thd Thread handle
+ all_fields List of all fields used in select
+ select Current select
+ ref_pointer_array Array of references to Items used in current select
+
+ DESCRIPTION
+ The function fixes fields referenced from inner selects and
+ also fixes references (Item_ref objects) to these fields. Each field
+ is fixed as a usual hidden field of the current select - it is added
+ to the all_fields list and the pointer to it is saved in the
+ ref_pointer_array if latter is provided.
+ After the field has been fixed we proceed with fixing references
+ (Item_ref objects) to this field from inner subqueries. If the
+ ref_pointer_array is provided then Item_ref objects is set to
+ reference element in that array with the pointer to the field.
+
+ RETURN
+ TRUE an error occured
+ FALSE ok
+*/
+
+bool
+fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
+ Item **ref_pointer_array)
+{
+ Item_outer_ref *ref;
+ bool res= FALSE;
+ List_iterator<Item_outer_ref> ref_it(select->inner_refs_list);
+ while ((ref= ref_it++))
+ {
+ Item_field *item= ref->outer_field;
+ /*
+ TODO: this field item already might be present in the select list.
+ In this case instead of adding new field item we could use an
+ existing one. The change will lead to less operations for copying fields,
+ smaller temporary tables and less data passed through filesort.
+ */
+ if (ref_pointer_array)
+ {
+ int el= all_fields.elements;
+ ref_pointer_array[el]= (Item*)item;
+ /* Add the field item to the select list of the current select. */
+ all_fields.push_front((Item*)item);
+ /*
+ If it's needed reset each Item_ref item that refers this field with
+ a new reference taken from ref_pointer_array.
+ */
+ ref->ref= ref_pointer_array + el;
+ }
+ if (!ref->fixed && ref->fix_fields(thd, 0))
+ {
+ res= TRUE;
+ break;
+ }
+ thd->used_tables|= item->used_tables();
+ }
+ return res;
+}
+
+/*
Function to setup clauses without sum functions
*/
inline int setup_without_group(THD *thd, Item **ref_pointer_array,
@@ -395,6 +458,10 @@ JOIN::prepare(Item ***rref_pointer_array,
if (having && having->with_sum_func)
having->split_sum_func2(thd, ref_pointer_array, all_fields,
&having, TRUE);
+ if (select_lex->inner_refs_list.elements &&
+ fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array))
+ DBUG_RETURN(-1);
+
if (select_lex->inner_sum_func_list)
{
Item_sum *end=select_lex->inner_sum_func_list;
@@ -475,6 +542,9 @@ JOIN::prepare(Item ***rref_pointer_array,
}
}
+ if (!procedure && result && result->prepare(fields_list, unit_arg))
+ goto err; /* purecov: inspected */
+
/* Init join struct */
count_field_types(&tmp_table_param, all_fields, 0);
ref_pointer_array_size= all_fields.elements*sizeof(Item*);
@@ -488,9 +558,6 @@ JOIN::prepare(Item ***rref_pointer_array,
goto err;
}
#endif
- if (!procedure && result && result->prepare(fields_list, unit_arg))
- goto err; /* purecov: inspected */
-
if (select_lex->olap == ROLLUP_TYPE && rollup_init())
goto err;
if (alloc_func_list())
@@ -506,72 +573,88 @@ err:
/*
- test if it is known for optimisation IN subquery
+ Remove the predicates pushed down into the subquery
SYNOPSIS
- JOIN::test_in_subselect()
- where - pointer for variable in which conditions should be
- stored if subquery is known
+ JOIN::remove_subq_pushed_predicates()
+ where IN Must be NULL
+ OUT The remaining WHERE condition, or NULL
- RETURN
- 1 - known
- 0 - unknown
+ DESCRIPTION
+ Given that this join will be executed using (unique|index)_subquery,
+ without "checking NULL", remove the predicates that were pushed down
+ into the subquery.
+
+ We can remove the equalities that will be guaranteed to be true by the
+ fact that subquery engine will be using index lookup.
+
+ If the subquery compares scalar values, we can remove the condition that
+ was wrapped into trig_cond (it will be checked when needed by the subquery
+ engine)
+
+ If the subquery compares row values, we need to keep the wrapped
+ equalities in the WHERE clause: when the left (outer) tuple has both NULL
+ and non-NULL values, we'll do a full table scan and will rely on the
+ equalities corresponding to non-NULL parts of left tuple to filter out
+ non-matching records.
*/
-bool JOIN::test_in_subselect(Item **where)
+void JOIN::remove_subq_pushed_predicates(Item **where)
{
if (conds->type() == Item::FUNC_ITEM &&
((Item_func *)this->conds)->functype() == Item_func::EQ_FUNC &&
((Item_func *)conds)->arguments()[0]->type() == Item::REF_ITEM &&
((Item_func *)conds)->arguments()[1]->type() == Item::FIELD_ITEM)
{
- join_tab->info= "Using index";
*where= 0;
- return 1;
+ return;
}
if (conds->type() == Item::COND_ITEM &&
((class Item_func *)this->conds)->functype() ==
Item_func::COND_AND_FUNC)
{
- if ((*where= remove_additional_cond(conds)))
- join_tab->info= "Using index; Using where";
- else
- join_tab->info= "Using index";
- return 1;
+ *where= remove_additional_cond(conds);
}
- return 0;
}
/*
- Check if the passed HAVING clause is a clause added by subquery optimizer
+ Index lookup-based subquery: save some flags for EXPLAIN output
SYNOPSIS
- is_having_subq_predicates()
- having Having clause
+ save_index_subquery_explain_info()
+ join_tab Subquery's join tab (there is only one as index lookup is
+ only used for subqueries that are single-table SELECTs)
+ where Subquery's WHERE clause
- RETURN
- TRUE The passed HAVING clause was added by the subquery optimizer
- FALSE Otherwise
+ DESCRIPTION
+ For index lookup-based subquery (i.e. one executed with
+ subselect_uniquesubquery_engine or subselect_indexsubquery_engine),
+ check its EXPLAIN output row should contain
+ "Using index" (TAB_INFO_FULL_SCAN_ON_NULL)
+ "Using Where" (TAB_INFO_USING_WHERE)
+ "Full scan on NULL key" (TAB_INFO_FULL_SCAN_ON_NULL)
+ and set appropriate flags in join_tab->packed_info.
*/
-bool is_having_subq_predicates(Item *having)
+static void save_index_subquery_explain_info(JOIN_TAB *join_tab, Item* where)
{
- if (having->type() == Item::FUNC_ITEM)
+ join_tab->packed_info= TAB_INFO_HAVE_VALUE;
+ if (join_tab->table->used_keys.is_set(join_tab->ref.key))
+ join_tab->packed_info |= TAB_INFO_USING_INDEX;
+ if (where)
+ join_tab->packed_info |= TAB_INFO_USING_WHERE;
+ for (uint i = 0; i < join_tab->ref.key_parts; i++)
{
- if (((Item_func *) having)->functype() == Item_func::ISNOTNULLTEST_FUNC)
- return TRUE;
- if (((Item_func *) having)->functype() == Item_func::TRIG_COND_FUNC)
+ if (join_tab->ref.cond_guards[i])
{
- having= ((Item_func*)having)->arguments()[0];
- if (((Item_func *) having)->functype() == Item_func::ISNOTNULLTEST_FUNC)
- return TRUE;
+ join_tab->packed_info |= TAB_INFO_FULL_SCAN_ON_NULL;
+ break;
}
- return TRUE;
}
- return FALSE;
}
+
/*
global select optimisation.
return 0 - success
@@ -701,11 +784,20 @@ JOIN::optimize()
{
int res;
/*
- opt_sum_query() returns -1 if no rows match to the WHERE conditions,
- or 1 if all items were resolved, or 0, or an error number HA_ERR_...
+ opt_sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match
+ to the WHERE conditions,
+ or 1 if all items were resolved,
+ or 0, or an error number HA_ERR_...
*/
if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds)))
{
+ if (res == HA_ERR_KEY_NOT_FOUND)
+ {
+ DBUG_PRINT("info",("No matching min/max row"));
+ zero_result_cause= "No matching min/max row";
+ error=0;
+ DBUG_RETURN(0);
+ }
if (res > 1)
{
thd->fatal_error();
@@ -713,13 +805,6 @@ JOIN::optimize()
DBUG_PRINT("error",("Error from opt_sum_query"));
DBUG_RETURN(1);
}
- if (res < 0)
- {
- DBUG_PRINT("info",("No matching min/max row"));
- zero_result_cause= "No matching min/max row";
- error=0;
- DBUG_RETURN(0);
- }
DBUG_PRINT("info",("Select tables optimized away"));
zero_result_cause= "Select tables optimized away";
tables_list= 0; // All tables resolved
@@ -849,6 +934,13 @@ JOIN::optimize()
{
ORDER *org_order= order;
order=remove_const(this, order,conds,1, &simple_order);
+ if (thd->net.report_error)
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from remove_const"));
+ DBUG_RETURN(1);
+ }
+
/*
If we are using ORDER BY NULL or ORDER BY const_expression,
return result in any order (even if we are using a GROUP BY)
@@ -858,10 +950,11 @@ JOIN::optimize()
}
/*
Check if we can optimize away GROUP BY/DISTINCT.
- We can do that if there are no aggregate functions and the
+ We can do that if there are no aggregate functions, the
fields in DISTINCT clause (if present) and/or columns in GROUP BY
(if present) contain direct references to all key parts of
- an unique index (in whatever order).
+ an unique index (in whatever order) and if the key parts of the
+ unique index cannot contain NULLs.
Note that the unique keys for DISTINCT and GROUP BY should not
be the same (as long as they are unique).
@@ -956,6 +1049,12 @@ JOIN::optimize()
group_list= remove_const(this, (old_group_list= group_list), conds,
rollup.state == ROLLUP::STATE_NONE,
&simple_group);
+ if (thd->net.report_error)
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from remove_const"));
+ DBUG_RETURN(1);
+ }
if (old_group_list && !group_list)
select_distinct= 0;
}
@@ -972,6 +1071,12 @@ JOIN::optimize()
{
group_list= procedure->group= remove_const(this, procedure->group, conds,
1, &simple_group);
+ if (thd->net.report_error)
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from remove_const"));
+ DBUG_RETURN(1);
+ }
calc_group_buffer(this, group_list);
}
@@ -1027,51 +1132,47 @@ JOIN::optimize()
if (join_tab[0].type == JT_EQ_REF &&
join_tab[0].ref.items[0]->name == in_left_expr_name)
{
- if (test_in_subselect(&where))
- {
- join_tab[0].type= JT_UNIQUE_SUBQUERY;
- error= 0;
- DBUG_RETURN(unit->item->
- change_engine(new
- subselect_uniquesubquery_engine(thd,
- join_tab,
- unit->item,
- where)));
- }
+ remove_subq_pushed_predicates(&where);
+ save_index_subquery_explain_info(join_tab, where);
+ join_tab[0].type= JT_UNIQUE_SUBQUERY;
+ error= 0;
+ DBUG_RETURN(unit->item->
+ change_engine(new
+ subselect_uniquesubquery_engine(thd,
+ join_tab,
+ unit->item,
+ where)));
}
else if (join_tab[0].type == JT_REF &&
join_tab[0].ref.items[0]->name == in_left_expr_name)
{
- if (test_in_subselect(&where))
- {
- join_tab[0].type= JT_INDEX_SUBQUERY;
- error= 0;
- DBUG_RETURN(unit->item->
- change_engine(new
- subselect_indexsubquery_engine(thd,
- join_tab,
- unit->item,
- where,
- 0)));
- }
+ remove_subq_pushed_predicates(&where);
+ save_index_subquery_explain_info(join_tab, where);
+ join_tab[0].type= JT_INDEX_SUBQUERY;
+ error= 0;
+ DBUG_RETURN(unit->item->
+ change_engine(new
+ subselect_indexsubquery_engine(thd,
+ join_tab,
+ unit->item,
+ where,
+ NULL,
+ 0)));
}
} else if (join_tab[0].type == JT_REF_OR_NULL &&
join_tab[0].ref.items[0]->name == in_left_expr_name &&
- is_having_subq_predicates(having))
+ having->name == in_having_cond)
{
join_tab[0].type= JT_INDEX_SUBQUERY;
error= 0;
-
- if ((conds= remove_additional_cond(conds)))
- join_tab->info= "Using index; Using where";
- else
- join_tab->info= "Using index";
-
+ conds= remove_additional_cond(conds);
+ save_index_subquery_explain_info(join_tab, conds);
DBUG_RETURN(unit->item->
change_engine(new subselect_indexsubquery_engine(thd,
join_tab,
unit->item,
conds,
+ having,
1)));
}
@@ -1474,7 +1575,7 @@ JOIN::exec()
if ((curr_join->select_lex->options & OPTION_SCHEMA_TABLE) &&
!thd->lex->describe &&
- get_schema_tables_result(curr_join))
+ get_schema_tables_result(curr_join, PROCESSED_BY_JOIN_EXEC))
{
DBUG_VOID_RETURN;
}
@@ -2457,14 +2558,14 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
for( ; sargables->field ; sargables++)
{
Field *field= sargables->field;
- JOIN_TAB *stat= field->table->reginfo.join_tab;
+ JOIN_TAB *join_tab= field->table->reginfo.join_tab;
key_map possible_keys= field->key_start;
possible_keys.intersect(field->table->keys_in_use_for_query);
bool is_const= 1;
- for (uint i=0; i< sargables->num_values; i++)
- is_const&= sargables->arg_value[i]->const_item();
+ for (uint j=0; j < sargables->num_values; j++)
+ is_const&= sargables->arg_value[j]->const_item();
if (is_const)
- stat[0].const_keys.merge(possible_keys);
+ join_tab[0].const_keys.merge(possible_keys);
}
}
@@ -2585,9 +2686,7 @@ typedef struct key_field_t { // Used when finding key fields
when val IS NULL.
*/
bool null_rejecting;
-
- /* TRUE<=> This ref access is an outer subquery reference access */
- bool outer_ref;
+ bool *cond_guard; /* See KEYUSE::cond_guard */
} KEY_FIELD;
/* Values in optimize */
@@ -2853,15 +2952,9 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
/*
We can't use indexes if the effective collation
of the operation differ from the field collation.
-
- We also cannot use index on a text column, as the column may
- contain 'x' 'x\t' 'x ' and 'read_next_same' will stop after
- 'x' when searching for WHERE col='x '
*/
if (field->cmp_type() == STRING_RESULT &&
- (((Field_str*)field)->charset() != cond->compare_collation() ||
- ((*value)->type() != Item::NULL_ITEM &&
- (field->flags & BLOB_FLAG) && !field->binary())))
+ ((Field_str*)field)->charset() != cond->compare_collation())
return;
}
}
@@ -2889,7 +2982,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
cond->functype() == Item_func::MULT_EQUAL_FUNC) &&
((*value)->type() == Item::FIELD_ITEM) &&
((Item_field*)*value)->field->maybe_null());
- (*key_fields)->outer_ref= FALSE;
+ (*key_fields)->cond_guard= NULL;
(*key_fields)++;
}
@@ -2986,25 +3079,26 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
}
/*
- Subquery optimization: check if the encountered condition is one
- added by condition push down into subquery.
+ Subquery optimization: Conditions that are pushed down into subqueries
+ are wrapped into Item_func_trig_cond. We process the wrapped condition
+ but need to set cond_guard for KEYUSE elements generated from it.
*/
{
if (cond->type() == Item::FUNC_ITEM &&
((Item_func*)cond)->functype() == Item_func::TRIG_COND_FUNC)
{
- cond= ((Item_func*)cond)->arguments()[0];
+ Item *cond_arg= ((Item_func*)cond)->arguments()[0];
if (!join->group_list && !join->order &&
join->unit->item &&
join->unit->item->substype() == Item_subselect::IN_SUBS &&
!join->unit->first_select()->next_select())
{
KEY_FIELD *save= *key_fields;
- add_key_fields(join, key_fields, and_level, cond, usable_tables,
+ add_key_fields(join, key_fields, and_level, cond_arg, usable_tables,
sargables);
// Indicate that this ref access candidate is for subquery lookup:
for (; save != *key_fields; save++)
- save->outer_ref= TRUE;
+ save->cond_guard= ((Item_func_trig_cond*)cond)->get_trig_var();
}
return;
}
@@ -3184,7 +3278,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
keyuse.used_tables=key_field->val->used_tables();
keyuse.optimize= key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL;
keyuse.null_rejecting= key_field->null_rejecting;
- keyuse.outer_ref= key_field->outer_ref;
+ keyuse.cond_guard= key_field->cond_guard;
VOID(insert_dynamic(keyuse_array,(gptr) &keyuse));
}
}
@@ -3461,16 +3555,16 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
*/
if (keyuse->elements)
{
- KEYUSE end,*prev,*save_pos,*use;
+ KEYUSE key_end,*prev,*save_pos,*use;
qsort(keyuse->buffer,keyuse->elements,sizeof(KEYUSE),
(qsort_cmp) sort_keyuse);
- bzero((char*) &end,sizeof(end)); /* Add for easy testing */
- VOID(insert_dynamic(keyuse,(gptr) &end));
+ bzero((char*) &key_end,sizeof(key_end)); /* Add for easy testing */
+ VOID(insert_dynamic(keyuse,(gptr) &key_end));
use=save_pos=dynamic_element(keyuse,0,KEYUSE*);
- prev=&end;
+ prev= &key_end;
found_eq_constant=0;
for (i=0 ; i < keyuse->elements-1 ; i++,use++)
{
@@ -3488,7 +3582,11 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
continue;
}
- *save_pos= *use;
+#ifdef HAVE_purify
+ /* Valgrind complains about overlapped memcpy when save_pos==use. */
+ if (save_pos != use)
+#endif
+ *save_pos= *use;
prev=use;
found_eq_constant= !use->used_tables;
/* Save ptr to first use */
@@ -3498,7 +3596,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
save_pos++;
}
i=(uint) (save_pos-(KEYUSE*) keyuse->buffer);
- VOID(set_dynamic(keyuse,(gptr) &end,i));
+ VOID(set_dynamic(keyuse,(gptr) &key_end,i));
keyuse->elements=i;
}
return FALSE;
@@ -3683,7 +3781,6 @@ best_access_path(JOIN *join,
table_map best_ref_depends_map= 0;
double tmp;
ha_rows rec;
-
DBUG_ENTER("best_access_path");
if (s->keyuse)
@@ -3731,12 +3828,12 @@ best_access_path(JOIN *join,
if (!(keyuse->used_tables & ~join->const_table_map))
const_part|= keyuse->keypart_map;
- double tmp= prev_record_reads(join, idx, (found_ref |
+ double tmp2= prev_record_reads(join, idx, (found_ref |
keyuse->used_tables));
- if (tmp < best_prev_record_reads)
+ if (tmp2 < best_prev_record_reads)
{
best_part_found_ref= keyuse->used_tables & ~join->const_table_map;
- best_prev_record_reads= tmp;
+ best_prev_record_reads= tmp2;
}
if (rec > keyuse->ref_table_rows)
rec= keyuse->ref_table_rows;
@@ -5144,7 +5241,8 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
if (!(j->ref.key_buff= (byte*) thd->calloc(ALIGN_SIZE(length)*2)) ||
!(j->ref.key_copy= (store_key**) thd->alloc((sizeof(store_key*) *
(keyparts+1)))) ||
- !(j->ref.items= (Item**) thd->alloc(sizeof(Item*)*keyparts)))
+ !(j->ref.items= (Item**) thd->alloc(sizeof(Item*)*keyparts)) ||
+ !(j->ref.cond_guards= (bool**) thd->alloc(sizeof(uint*)*keyparts)))
{
DBUG_RETURN(TRUE);
}
@@ -5159,6 +5257,8 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
if (ftkey)
{
j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
+ /* Predicates pushed down into subquery can't be used FT access */
+ j->ref.cond_guards[0]= NULL;
if (keyuse->used_tables)
DBUG_RETURN(TRUE); // not supported yet. SerG
@@ -5175,6 +5275,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
uint maybe_null= test(keyinfo->key_part[i].null_bit);
j->ref.items[i]=keyuse->val; // Save for cond removal
+ j->ref.cond_guards[i]= keyuse->cond_guard;
if (keyuse->null_rejecting)
j->ref.null_rejecting |= 1 << i;
keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables;
@@ -5248,13 +5349,15 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
key_part->length,
keyuse->val);
}
- else if (keyuse->val->type() == Item::FIELD_ITEM)
+ else if (keyuse->val->type() == Item::FIELD_ITEM ||
+ (keyuse->val->type() == Item::REF_ITEM &&
+ ((Item_ref*)keyuse->val)->ref_type() == Item_ref::OUTER_REF) )
return new store_key_field(thd,
key_part->field,
key_buff + maybe_null,
maybe_null ? key_buff : 0,
key_part->length,
- ((Item_field*) keyuse->val)->field,
+ ((Item_field*) keyuse->val->real_item())->field,
keyuse->val->full_name());
return new store_key_item(thd,
key_part->field,
@@ -5902,37 +6005,42 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
*/
COND *on_expr= *first_inner_tab->on_expr_ref;
- table_map used_tables= join->const_table_map |
- OUTER_REF_TABLE_BIT | RAND_TABLE_BIT;
+ table_map used_tables2= (join->const_table_map |
+ OUTER_REF_TABLE_BIT | RAND_TABLE_BIT);
for (tab= join->join_tab+join->const_tables; tab <= last_tab ; tab++)
{
current_map= tab->table->map;
- used_tables|= current_map;
- COND *tmp= make_cond_for_table(on_expr, used_tables, current_map);
- if (tmp)
+ used_tables2|= current_map;
+ COND *tmp_cond= make_cond_for_table(on_expr, used_tables2,
+ current_map);
+ if (tmp_cond)
{
JOIN_TAB *cond_tab= tab < first_inner_tab ? first_inner_tab : tab;
/*
First add the guards for match variables of
all embedding outer join operations.
*/
- if (!(tmp= add_found_match_trig_cond(cond_tab->first_inner,
- tmp, first_inner_tab)))
+ if (!(tmp_cond= add_found_match_trig_cond(cond_tab->first_inner,
+ tmp_cond,
+ first_inner_tab)))
DBUG_RETURN(1);
/*
Now add the guard turning the predicate off for
the null complemented row.
*/
DBUG_PRINT("info", ("Item_func_trig_cond"));
- tmp= new Item_func_trig_cond(tmp,
- &first_inner_tab->not_null_compl);
- DBUG_PRINT("info", ("Item_func_trig_cond 0x%lx", (ulong) tmp));
- if (tmp)
- tmp->quick_fix_field();
+ tmp_cond= new Item_func_trig_cond(tmp_cond,
+ &first_inner_tab->
+ not_null_compl);
+ DBUG_PRINT("info", ("Item_func_trig_cond 0x%lx",
+ (ulong) tmp_cond));
+ if (tmp_cond)
+ tmp_cond->quick_fix_field();
/* Add the predicate to other pushed down predicates */
DBUG_PRINT("info", ("Item_cond_and"));
- cond_tab->select_cond= !cond_tab->select_cond ? tmp :
- new Item_cond_and(cond_tab->select_cond,tmp);
+ cond_tab->select_cond= !cond_tab->select_cond ? tmp_cond :
+ new Item_cond_and(cond_tab->select_cond,
+ tmp_cond);
DBUG_PRINT("info", ("Item_cond_and 0x%lx",
(ulong)cond_tab->select_cond));
if (!cond_tab->select_cond)
@@ -6251,7 +6359,7 @@ void JOIN_TAB::cleanup()
void JOIN::join_free()
{
- SELECT_LEX_UNIT *unit;
+ SELECT_LEX_UNIT *tmp_unit;
SELECT_LEX *sl;
/*
Optimization: if not EXPLAIN and we are done with the JOIN,
@@ -6263,8 +6371,10 @@ void JOIN::join_free()
cleanup(full);
- for (unit= select_lex->first_inner_unit(); unit; unit= unit->next_unit())
- for (sl= unit->first_select(); sl; sl= sl->next_select())
+ for (tmp_unit= select_lex->first_inner_unit();
+ tmp_unit;
+ tmp_unit= tmp_unit->next_unit())
+ for (sl= tmp_unit->first_select(); sl; sl= sl->next_select())
{
Item_subselect *subselect= sl->master_unit()->item;
bool full_local= full && (!subselect || subselect->is_evaluated());
@@ -6563,6 +6673,8 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
*simple_order=0; // Must do a temp table to sort
else if (!(order_tables & not_const_tables))
{
+ if (order->item[0]->with_subselect)
+ order->item[0]->val_str(&order->item[0]->str_value);
DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
continue; // skip const item
}
@@ -6900,9 +7012,9 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
else
{
/* None of the fields was found in multiple equalities */
- Item_equal *item= new Item_equal((Item_field *) left_item,
- (Item_field *) right_item);
- cond_equal->current_level.push_back(item);
+ Item_equal *item_equal= new Item_equal((Item_field *) left_item,
+ (Item_field *) right_item);
+ cond_equal->current_level.push_back(item_equal);
}
}
return TRUE;
@@ -7009,8 +7121,8 @@ static bool check_row_equality(Item *left_row, Item_row *right_row,
for (uint i= 0 ; i < n; i++)
{
bool is_converted;
- Item *left_item= left_row->el(i);
- Item *right_item= right_row->el(i);
+ Item *left_item= left_row->element_index(i);
+ Item *right_item= right_row->element_index(i);
if (left_item->type() == Item::ROW_ITEM &&
right_item->type() == Item::ROW_ITEM)
is_converted= check_row_equality((Item_row *) left_item,
@@ -7400,14 +7512,15 @@ static COND *build_equal_items(THD *thd, COND *cond,
{
if (table->on_expr)
{
- List<TABLE_LIST> *join_list= table->nested_join ?
- &table->nested_join->join_list : NULL;
+ List<TABLE_LIST> *nested_join_list= table->nested_join ?
+ &table->nested_join->join_list : NULL;
/*
We can modify table->on_expr because its old value will
be restored before re-execution of PS/SP.
*/
table->on_expr= build_equal_items(thd, table->on_expr, inherited,
- join_list, &table->cond_equal);
+ nested_join_list,
+ &table->cond_equal);
}
}
}
@@ -7722,6 +7835,22 @@ static void update_const_equal_items(COND *cond, JOIN_TAB *tab)
key_map possible_keys= field->key_start;
possible_keys.intersect(field->table->keys_in_use_for_query);
stat[0].const_keys.merge(possible_keys);
+
+ /*
+ For each field in the multiple equality (for which we know that it
+ is a constant) we have to find its corresponding key part, and set
+ that key part in const_key_parts.
+ */
+ if (!possible_keys.is_clear_all())
+ {
+ TABLE *tab= field->table;
+ KEYUSE *use;
+ for (use= stat->keyuse; use && use->table == tab; use++)
+ if (possible_keys.is_set(use->key) &&
+ tab->key_info[use->key].key_part[use->keypart].field ==
+ field)
+ tab->const_key_parts[use->key]|= use->keypart_map;
+ }
}
}
}
@@ -7764,7 +7893,7 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
value->result_type() != STRING_RESULT ||
left_item->collation.collation == value->collation.collation))
{
- Item *tmp=value->new_item();
+ Item *tmp=value->clone_item();
tmp->collation.set(right_item->collation);
if (tmp)
@@ -7788,7 +7917,7 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
value->result_type() != STRING_RESULT ||
right_item->collation.collation == value->collation.collation))
{
- Item *tmp=value->new_item();
+ Item *tmp= value->clone_item();
tmp->collation.set(left_item->collation);
if (tmp)
@@ -7816,7 +7945,7 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
SYNOPSIS
remove_additional_cond()
- conds - condition for processing
+ conds Condition for processing
RETURN VALUES
new conditions
@@ -8037,9 +8166,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;
@@ -8049,7 +8183,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)
@@ -8199,7 +8333,7 @@ static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list,
*/
if (nested_join->join_list.elements != 1)
{
- nested_join->nj_map= 1 << first_unused++;
+ nested_join->nj_map= (nested_join_map) 1 << first_unused++;
first_unused= build_bitmap_for_nested_joins(&nested_join->join_list,
first_unused);
}
@@ -8409,7 +8543,6 @@ optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list,
Item::cond_result *cond_value)
{
THD *thd= join->thd;
- SELECT_LEX *select= thd->lex->current_select;
DBUG_ENTER("optimize_cond");
if (!conds)
@@ -8761,6 +8894,8 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field,
if (org_field->type() == MYSQL_TYPE_VAR_STRING ||
org_field->type() == MYSQL_TYPE_VARCHAR)
table->s->db_create_options|= HA_OPTION_PACK_RECORD;
+ else if (org_field->type() == FIELD_TYPE_DOUBLE)
+ ((Field_double *) new_field)->not_fixed= TRUE;
}
return new_field;
}
@@ -8801,7 +8936,7 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
switch (item->result_type()) {
case REAL_RESULT:
new_field= new Field_double(item->max_length, maybe_null,
- item->name, item->decimals);
+ item->name, item->decimals, TRUE);
break;
case INT_RESULT:
/* Select an integer type with the minimal fit precision */
@@ -8821,7 +8956,8 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
type they needed to be handled separately.
*/
if ((type= item->field_type()) == MYSQL_TYPE_DATETIME ||
- type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE)
+ type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE ||
+ type == MYSQL_TYPE_TIMESTAMP)
new_field= item->tmp_table_field_from_field_type(table, 1);
/*
Make sure that the blob fits into a Field_varstring which has
@@ -8937,9 +9073,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item *orig_item= 0;
if (type != Item::FIELD_ITEM &&
- item->real_item()->type() == Item::FIELD_ITEM &&
- (item->type() != Item::REF_ITEM ||
- !((Item_ref *) item)->depended_from))
+ item->real_item()->type() == Item::FIELD_ITEM)
{
orig_item= item;
item= item->real_item();
@@ -9101,7 +9235,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
uint hidden_null_count, hidden_null_pack_length, hidden_field_count;
uint blob_count,group_null_items, string_count;
uint temp_pool_slot=MY_BIT_NONE;
- ulong reclength, string_total_length, fieldnr= 0;
+ uint fieldnr= 0;
+ ulong reclength, string_total_length;
bool using_unique_constraint= 0;
bool use_packed_rows= 0;
bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS);
@@ -10267,7 +10402,6 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
else
{
DBUG_ASSERT(join->tables);
- DBUG_ASSERT(join_tab);
error= sub_select(join,join_tab,0);
if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
error= sub_select(join,join_tab,1);
@@ -11130,7 +11264,9 @@ int rr_sequential(READ_RECORD *info);
int init_read_record_seq(JOIN_TAB *tab)
{
tab->read_record.read_record= rr_sequential;
- return tab->read_record.file->ha_rnd_init(1);
+ if (tab->read_record.file->ha_rnd_init(1))
+ return 1;
+ return (*tab->read_record.read_record)(&tab->read_record);
}
static int
@@ -12075,7 +12211,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
/*
- Check if GROUP BY/DISTINCT can be optimized away because the set is
+ Check if GROUP BY/DISTINCT can be optimized away because the set is
already known to be distinct.
SYNOPSIS
@@ -12083,7 +12219,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
table The table to operate on.
find_func function to iterate over the list and search
for a field
-
+
DESCRIPTION
Used in removing the GROUP BY/DISTINCT of the following types of
statements:
@@ -12094,12 +12230,13 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
then <any combination of a,b,c>,{whatever} is also distinct
This function checks if all the key parts of any of the unique keys
- of the table are referenced by a list : either the select list
+ of the table are referenced by a list : either the select list
through find_field_in_item_list or GROUP BY list through
find_field_in_order_list.
- If the above holds then we can safely remove the GROUP BY/DISTINCT,
+ If the above holds and the key parts cannot contain NULLs then we
+ can safely remove the GROUP BY/DISTINCT,
as no result set can be more distinct than an unique key.
-
+
RETURN VALUE
1 found
0 not found.
@@ -12122,7 +12259,8 @@ list_contains_unique_index(TABLE *table,
key_part < key_part_end;
key_part++)
{
- if (!find_func(key_part->field, data))
+ if (key_part->field->maybe_null() ||
+ !find_func(key_part->field, data))
break;
}
if (key_part == key_part_end)
@@ -12230,13 +12368,14 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
DBUG_ENTER("test_if_skip_sort_order");
LINT_INIT(ref_key_parts);
+ /* Check which keys can be used to resolve ORDER BY. */
+ usable_keys= table->keys_in_use_for_query;
+
/*
- Check which keys can be used to resolve ORDER BY.
- We must not try to use disabled keys.
+ Keys disabled by ALTER TABLE ... DISABLE KEYS should have already
+ been taken into account.
*/
- usable_keys= table->s->keys_in_use;
- /* we must not consider keys that are disabled by IGNORE INDEX */
- usable_keys.intersect(table->keys_in_use_for_query);
+ DBUG_ASSERT(usable_keys.is_subset(table->s->keys_in_use));
for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
{
@@ -12484,7 +12623,7 @@ static int
create_sort_index(THD *thd, JOIN *join, ORDER *order,
ha_rows filesort_limit, ha_rows select_limit)
{
- uint length;
+ uint length= 0;
ha_rows examined_rows;
TABLE *table;
SQL_SELECT *select;
@@ -12505,8 +12644,10 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
!(join->select_options & SELECT_BIG_RESULT)) &&
test_if_skip_sort_order(tab,order,select_limit,0))
DBUG_RETURN(0);
+ for (ORDER *ord= join->order; ord; ord= ord->next)
+ length++;
if (!(join->sortorder=
- make_unireg_sortorder(order,&length,join->sortorder)))
+ make_unireg_sortorder(order, &length, join->sortorder)))
goto err; /* purecov: inspected */
table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
@@ -12549,7 +12690,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
/* Fill schema tables with data before filesort if it's necessary */
if ((join->select_lex->options & OPTION_SCHEMA_TABLE) &&
!thd->lex->describe &&
- get_schema_tables_result(join))
+ get_schema_tables_result(join, PROCESSED_BY_CREATE_SORT_INDEX))
goto err;
if (table->s->tmp_table)
@@ -12914,22 +13055,24 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length,
for (ORDER *tmp = order; tmp; tmp=tmp->next)
count++;
if (!sortorder)
- sortorder= (SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD)*(count+1));
- pos=sort=sortorder;
+ sortorder= (SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD) *
+ (max(count, *length) + 1));
+ pos= sort= sortorder;
+
if (!pos)
return 0;
for (;order;order=order->next,pos++)
{
- pos->field=0; pos->item=0;
- if (order->item[0]->type() == Item::FIELD_ITEM)
- pos->field= ((Item_field*) (*order->item))->field;
- else if (order->item[0]->type() == Item::SUM_FUNC_ITEM &&
- !order->item[0]->const_item())
- pos->field= ((Item_sum*) order->item[0])->get_tmp_table_field();
- else if (order->item[0]->type() == Item::COPY_STR_ITEM)
+ Item *item= order->item[0]->real_item();
+ pos->field= 0; pos->item= 0;
+ if (item->type() == Item::FIELD_ITEM)
+ pos->field= ((Item_field*) item)->field;
+ else if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item())
+ pos->field= ((Item_sum*) item)->get_tmp_table_field();
+ else if (item->type() == Item::COPY_STR_ITEM)
{ // Blob patch
- pos->item= ((Item_copy_string*) (*order->item))->item;
+ pos->item= ((Item_copy_string*) item)->item;
}
else
pos->item= *order->item;
@@ -13443,49 +13586,83 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
bool *hidden_group_fields)
{
*hidden_group_fields=0;
+ ORDER *ord;
+
if (!order)
return 0; /* Everything is ok */
- if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY)
- {
- Item *item;
- List_iterator<Item> li(fields);
- while ((item=li++))
- item->marker=0; /* Marker that field is not used */
- }
uint org_fields=all_fields.elements;
thd->where="group statement";
- for (; order; order=order->next)
+ for (ord= order; ord; ord= ord->next)
{
- if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
+ if (find_order_in_list(thd, ref_pointer_array, tables, ord, fields,
all_fields, TRUE))
return 1;
- (*order->item)->marker=1; /* Mark found */
- if ((*order->item)->with_sum_func)
+ (*ord->item)->marker= UNDEF_POS; /* Mark found */
+ if ((*ord->item)->with_sum_func)
{
- my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*order->item)->full_name());
+ my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*ord->item)->full_name());
return 1;
}
}
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY)
{
- /* Don't allow one to use fields that is not used in GROUP BY */
+ /*
+ Don't allow one to use fields that is not used in GROUP BY
+ For each select a list of field references that aren't under an
+ aggregate function is created. Each field in this list keeps the
+ position of the select list expression which it belongs to.
+
+ First we check an expression from the select list against the GROUP BY
+ list. If it's found there then it's ok. It's also ok if this expression
+ is a constant or an aggregate function. Otherwise we scan the list
+ of non-aggregated fields and if we'll find at least one field reference
+ that belongs to this expression and doesn't occur in the GROUP BY list
+ we throw an error. If there are no fields in the created list for a
+ select list expression this means that all fields in it are used under
+ aggregate functions.
+ */
Item *item;
+ Item_field *field;
+ int cur_pos_in_select_list= 0;
List_iterator<Item> li(fields);
+ List_iterator<Item_field> naf_it(thd->lex->current_select->non_agg_fields);
- while ((item=li++))
+ field= naf_it++;
+ while (field && (item=li++))
{
- if (item->type() != Item::SUM_FUNC_ITEM && !item->marker &&
- !item->const_item())
+ if (item->type() != Item::SUM_FUNC_ITEM && item->marker >= 0 &&
+ !item->const_item() &&
+ !(item->real_item()->type() == Item::FIELD_ITEM &&
+ item->used_tables() & OUTER_REF_TABLE_BIT))
{
- /*
- TODO: change ER_WRONG_FIELD_WITH_GROUP to more detailed
- ER_NON_GROUPING_FIELD_USED
- */
- my_error(ER_WRONG_FIELD_WITH_GROUP, MYF(0), item->full_name());
- return 1;
+ while (field)
+ {
+ /* Skip fields from previous expressions. */
+ if (field->marker < cur_pos_in_select_list)
+ goto next_field;
+ /* Found a field from the next expression. */
+ if (field->marker > cur_pos_in_select_list)
+ break;
+ /*
+ Check whether the field occur in the GROUP BY list.
+ Throw the error later if the field isn't found.
+ */
+ for (ord= order; ord; ord= ord->next)
+ if ((*ord->item)->eq((Item*)field, 0))
+ goto next_field;
+ /*
+ TODO: change ER_WRONG_FIELD_WITH_GROUP to more detailed
+ ER_NON_GROUPING_FIELD_USED
+ */
+ my_error(ER_WRONG_FIELD_WITH_GROUP, MYF(0), field->full_name());
+ return 1;
+next_field:
+ field= naf_it++;
+ }
}
+ cur_pos_in_select_list++;
}
}
if (org_fields != all_fields.elements)
@@ -13611,10 +13788,10 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
param->quick_group=1;
while ((field=li++))
{
- Item::Type type=field->real_item()->type();
- if (type == Item::FIELD_ITEM)
+ Item::Type real_type= field->real_item()->type();
+ if (real_type == Item::FIELD_ITEM)
param->field_count++;
- else if (type == Item::SUM_FUNC_ITEM)
+ else if (real_type == Item::SUM_FUNC_ITEM)
{
if (! field->const_item())
{
@@ -14752,7 +14929,7 @@ int JOIN::rollup_send_data(uint idx)
1 if write_data_failed()
*/
-int JOIN::rollup_write_data(uint idx, TABLE *table)
+int JOIN::rollup_write_data(uint idx, TABLE *table_arg)
{
uint i;
for (i= send_group_parts ; i-- > idx ; )
@@ -14763,7 +14940,7 @@ int JOIN::rollup_write_data(uint idx, TABLE *table)
ref_pointer_array_size);
if ((!having || having->val_int()))
{
- int error;
+ int write_error;
Item *item;
List_iterator_fast<Item> it(rollup.fields[i]);
while ((item= it++))
@@ -14772,10 +14949,10 @@ int JOIN::rollup_write_data(uint idx, TABLE *table)
item->save_in_result_field(1);
}
copy_sum_funcs(sum_funcs_end[i+1], sum_funcs_end[i]);
- if ((error= table->file->write_row(table->record[0])))
+ if ((write_error= table_arg->file->write_row(table_arg->record[0])))
{
- if (create_myisam_from_heap(thd, table, &tmp_table_param,
- error, 0))
+ if (create_myisam_from_heap(thd, table_arg, &tmp_table_param,
+ write_error, 0))
return 1;
}
}
@@ -14971,9 +15148,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
}
else
{
- TABLE_LIST *tab=table->pos_in_table_list;
- item_list.push_back(new Item_string(tab->alias,
- strlen(tab->alias),
+ TABLE_LIST *real_table= table->pos_in_table_list;
+ item_list.push_back(new Item_string(real_table->alias,
+ strlen(real_table->alias),
cs));
}
/* "partitions" column */
@@ -15086,7 +15263,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
Item_float *filtered;
float f;
if (examined_rows)
- f= 100.0 * join->best_positions[i].records_read / examined_rows;
+ f= (float) (100.0 * join->best_positions[i].records_read /
+ examined_rows);
else
f= 0.0;
item_list.push_back((filtered= new Item_float(f)));
@@ -15105,6 +15283,24 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
if (tab->info)
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
+ else if (tab->packed_info & TAB_INFO_HAVE_VALUE)
+ {
+ if (tab->packed_info & TAB_INFO_USING_INDEX)
+ extra.append(STRING_WITH_LEN("; Using index"));
+ if (tab->packed_info & TAB_INFO_USING_WHERE)
+ extra.append(STRING_WITH_LEN("; Using where"));
+ if (tab->packed_info & TAB_INFO_FULL_SCAN_ON_NULL)
+ extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
+ /* Skip initial "; "*/
+ const char *str= extra.ptr();
+ uint32 len= extra.length();
+ if (len)
+ {
+ str += 2;
+ len -= 2;
+ }
+ item_list.push_back(new Item_string(str, len, cs));
+ }
else
{
if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
@@ -15163,6 +15359,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
}
if (distinct & test_all_bits(used_tables,thd->used_tables))
extra.append(STRING_WITH_LEN("; Distinct"));
+
+ for (uint part= 0; part < tab->ref.key_parts; part++)
+ {
+ if (tab->ref.cond_guards[part])
+ {
+ extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
+ break;
+ }
+ }
/* Skip initial "; "*/
const char *str= extra.ptr();
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 6ab4463605b..1d1fa666c60 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -35,8 +35,17 @@ typedef struct keyuse_t {
satisfied if val has NULL 'value'.
*/
bool null_rejecting;
- /* TRUE<=> This ref access is an outer subquery reference access */
- bool outer_ref;
+ /*
+ !NULL - This KEYUSE was created from an equality that was wrapped into
+ an Item_func_trig_cond. This means the equality (and validity of
+ this KEYUSE element) can be turned on and off. The on/off state
+ is indicted by the pointed value:
+ *cond_guard == TRUE <=> equality condition is on
+ *cond_guard == FALSE <=> equality condition is off
+
+ NULL - Otherwise (the source equality can't be turned off)
+ */
+ bool *cond_guard;
} KEYUSE;
class store_key;
@@ -51,6 +60,18 @@ typedef struct st_table_ref
byte *key_buff2; // key_buff+key_length
store_key **key_copy; //
Item **items; // val()'s for each keypart
+ /*
+ Array of pointers to trigger variables. Some/all of the pointers may be
+ NULL. The ref access can be used iff
+
+ for each used key part i, (!cond_guards[i] || *cond_guards[i])
+
+ This array is used by subquery code. The subquery code may inject
+ triggered conditions, i.e. conditions that can be 'switched off'. A ref
+ access created from such condition is not valid when at least one of the
+ underlying conditions is switched off (see subquery code for more details)
+ */
+ bool **cond_guards;
/*
(null_rejecting & (1<<i)) means the condition is '=' and no matching
rows will be produced if items[i] IS NULL (see add_not_null_conds())
@@ -99,6 +120,13 @@ enum enum_nested_loop_state
NESTED_LOOP_QUERY_LIMIT= 3, NESTED_LOOP_CURSOR_LIMIT= 4
};
+
+/* Values for JOIN_TAB::packed_info */
+#define TAB_INFO_HAVE_VALUE 1
+#define TAB_INFO_USING_INDEX 2
+#define TAB_INFO_USING_WHERE 4
+#define TAB_INFO_FULL_SCAN_ON_NULL 8
+
typedef enum_nested_loop_state
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
typedef int (*Read_record_func)(struct st_join_table *tab);
@@ -120,7 +148,15 @@ typedef struct st_join_table {
st_join_table *last_inner; /* last table table for embedding outer join */
st_join_table *first_upper; /* first inner table for embedding outer join */
st_join_table *first_unmatched; /* used for optimization purposes only */
+
+ /* Special content for EXPLAIN 'Extra' column or NULL if none */
const char *info;
+ /*
+ Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
+ column, or 0 if there is no info.
+ */
+ uint packed_info;
+
Read_record_func read_first_record;
Next_select_func next_select;
READ_RECORD read_record;
@@ -425,7 +461,7 @@ public:
Item_sum ***func);
int rollup_send_data(uint idx);
int rollup_write_data(uint idx, TABLE *table);
- bool test_in_subselect(Item **where);
+ void remove_subq_pushed_predicates(Item **where);
/*
Release memory and, if possible, the open tables held by this execution
plan (and nested plans). It's used to release some tables before
diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc
index 0ec7c54487a..5fa97dc5c2b 100644
--- a/sql/sql_servers.cc
+++ b/sql/sql_servers.cc
@@ -32,7 +32,6 @@ uint servers_cache_initialised=FALSE;
static uint servers_version=0;
static MEM_ROOT mem;
static rw_lock_t THR_LOCK_servers;
-static bool initialized=0;
static byte *servers_cache_get_key(FOREIGN_SERVER *server, uint *length,
my_bool not_used __attribute__((unused)))
@@ -329,24 +328,22 @@ my_bool get_server_from_table_to_cache(TABLE *table)
my_bool server_exists_in_table(THD *thd, LEX_SERVER_OPTIONS *server_options)
{
- byte server_key[MAX_KEY_LENGTH];
int result= 1;
int error= 0;
TABLE_LIST tables;
TABLE *table;
-
DBUG_ENTER("server_exists");
bzero((char*) &tables, sizeof(tables));
tables.db= (char*) "mysql";
tables.alias= tables.table_name= (char*) "servers";
- table->use_all_columns();
-
/* need to open before acquiring THR_LOCK_plugin or it will deadlock */
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
DBUG_RETURN(TRUE);
+ table->use_all_columns();
+
rw_wrlock(&THR_LOCK_servers);
VOID(pthread_mutex_lock(&servers_cache_mutex));
@@ -393,7 +390,6 @@ my_bool server_exists_in_table(THD *thd, LEX_SERVER_OPTIONS *server_options)
int insert_server(THD *thd, FOREIGN_SERVER *server)
{
- byte server_key[MAX_KEY_LENGTH];
int error= 0;
TABLE_LIST tables;
TABLE *table;
@@ -608,7 +604,6 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server)
int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
{
- byte server_key[MAX_KEY_LENGTH];
int error= 0;
TABLE_LIST tables;
TABLE *table;
@@ -1208,7 +1203,7 @@ void servers_free(bool end)
FOREIGN_SERVER *get_server_by_name(const char *server_name)
{
ulong error_num=0;
- uint i, server_name_length;
+ uint server_name_length;
FOREIGN_SERVER *server= 0;
DBUG_ENTER("get_server_by_name");
DBUG_PRINT("info", ("server_name %s", server_name));
diff --git a/sql/sql_servers.h b/sql/sql_servers.h
index 36fb4d07d1b..23b8cefd5bb 100644
--- a/sql/sql_servers.h
+++ b/sql/sql_servers.h
@@ -26,7 +26,6 @@ typedef struct st_federated_server
/* cache handlers */
my_bool servers_init(bool dont_read_server_table);
-static my_bool servers_load(THD *thd, TABLE_LIST *tables);
my_bool servers_reload(THD *thd);
my_bool get_server_from_table_to_cache(TABLE *table);
void servers_free(bool end=0);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index c4bb6a8fc92..881cf7dc6c4 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -32,7 +32,6 @@
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
#endif
-
enum enum_i_s_events_fields
{
ISE_EVENT_CATALOG= 0,
@@ -57,11 +56,11 @@ enum enum_i_s_events_fields
};
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
static const char *grant_names[]={
"select","insert","update","delete","create","drop","reload","shutdown",
"process","file","grant","references","index","alter"};
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
"grant_types",
grant_names, NULL};
@@ -140,7 +139,6 @@ static my_bool show_plugins(THD *thd, st_plugin_int *plugin,
{
TABLE *table= (TABLE*) arg;
struct st_mysql_plugin *plug= plugin->plugin;
- Protocol *protocol= thd->protocol;
CHARSET_INFO *cs= system_charset_info;
char version_buf[20];
@@ -153,8 +151,7 @@ static my_bool show_plugins(THD *thd, st_plugin_int *plugin,
cs);
- switch (plugin->state)
- {
+ switch (plugin->state) {
/* case PLUGIN_IS_FREED: does not happen */
case PLUGIN_IS_DELETED:
table->field[2]->store(STRING_WITH_LEN("DELETED"), cs);
@@ -688,10 +685,10 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
bool mysqld_show_create_db(THD *thd, char *dbname,
HA_CREATE_INFO *create_info)
{
- Security_context *sctx= thd->security_ctx;
char buff[2048];
String buffer(buff, sizeof(buff), system_charset_info);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *sctx= thd->security_ctx;
uint db_access;
#endif
HA_CREATE_INFO create;
@@ -1020,7 +1017,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
HA_CREATE_INFO *create_info_arg)
{
List<Item> field_list;
- char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end;
+ char tmp[MAX_FIELD_WIDTH], *for_str, buff[128];
const char *alias;
String type(tmp, sizeof(tmp), system_charset_info);
Field **ptr,*field;
@@ -1307,8 +1304,9 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
but may extrapolate its existence from that of an AUTO_INCREMENT column.
*/
- if(create_info.auto_increment_value > 1)
+ if (create_info.auto_increment_value > 1)
{
+ char *end;
packet->append(STRING_WITH_LEN(" AUTO_INCREMENT="));
end= longlong10_to_str(create_info.auto_increment_value, buff,10);
packet->append(buff, (uint) (end - buff));
@@ -1338,6 +1336,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
if (share->min_rows)
{
+ char *end;
packet->append(STRING_WITH_LEN(" MIN_ROWS="));
end= longlong10_to_str(share->min_rows, buff, 10);
packet->append(buff, (uint) (end- buff));
@@ -1345,6 +1344,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
if (share->max_rows && !table_list->schema_table)
{
+ char *end;
packet->append(STRING_WITH_LEN(" MAX_ROWS="));
end= longlong10_to_str(share->max_rows, buff, 10);
packet->append(buff, (uint) (end - buff));
@@ -1352,6 +1352,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
if (share->avg_row_length)
{
+ char *end;
packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH="));
end= longlong10_to_str(share->avg_row_length, buff,10);
packet->append(buff, (uint) (end - buff));
@@ -1372,6 +1373,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
}
if (table->s->key_block_size)
{
+ char *end;
packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
end= longlong10_to_str(table->s->key_block_size, buff, 10);
packet->append(buff, (uint) (end - buff));
@@ -1685,10 +1687,6 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if (mysys_var)
pthread_mutex_unlock(&mysys_var->mutex);
-#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
- if (pthread_kill(tmp->real_id,0))
- tmp->proc_info="*** DEAD ***"; // This shouldn't happen
-#endif
#ifdef EXTRA_DEBUG
thd_info->start_time= tmp->time_after_lock;
#else
@@ -2067,7 +2065,7 @@ static bool show_status_array(THD *thd, const char *wild,
if (show_type == SHOW_SYS)
{
- show_type= ((sys_var*) value)->type();
+ show_type= ((sys_var*) value)->show_type();
value= (char*) ((sys_var*) value)->value_ptr(thd, value_type,
&null_lex_str);
}
@@ -2120,7 +2118,7 @@ static bool show_status_array(THD *thd, const char *wild,
end= strend(pos);
break;
}
- case SHOW_CHAR_PTR:
+ case SHOW_CHAR_PTR:
{
if (!(pos= *(char**) value))
pos= "";
@@ -2451,10 +2449,48 @@ int make_db_list(THD *thd, List<char> *files,
mysql_data_home, NullS, 1) != FIND_FILES_OK);
}
+struct st_add_schema_table
+{
+ List<char> *files;
+ const char *wild;
+};
+
+static my_bool add_schema_table(THD *thd, st_plugin_int *plugin,
+ void* p_data)
+{
+ st_add_schema_table *data= (st_add_schema_table *)p_data;
+ List<char> *file_list= data->files;
+ const char *wild= data->wild;
+ ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data;
+ DBUG_ENTER("add_schema_table");
+
+ if (schema_table->hidden)
+ DBUG_RETURN(0);
+ if (wild)
+ {
+ if (lower_case_table_names)
+ {
+ if (wild_case_compare(files_charset_info,
+ schema_table->table_name,
+ wild))
+ DBUG_RETURN(0);
+ }
+ else if (wild_compare(schema_table->table_name, wild, 0))
+ DBUG_RETURN(0);
+ }
+
+ if (file_list->push_back(thd->strdup(schema_table->table_name)))
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
+}
int schema_tables_add(THD *thd, List<char> *files, const char *wild)
{
ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
+ st_add_schema_table add_data;
+ DBUG_ENTER("schema_tables_add");
+
for (; tmp_schema_table->table_name; tmp_schema_table++)
{
if (tmp_schema_table->hidden)
@@ -2472,9 +2508,16 @@ int schema_tables_add(THD *thd, List<char> *files, const char *wild)
continue;
}
if (files->push_back(thd->strdup(tmp_schema_table->table_name)))
- return 1;
+ DBUG_RETURN(1);
}
- return 0;
+
+ add_data.files= files;
+ add_data.wild= wild;
+ if (plugin_foreach(thd, add_schema_table,
+ MYSQL_INFORMATION_SCHEMA_PLUGIN, &add_data))
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
}
@@ -2489,26 +2532,27 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
SELECT_LEX sel;
INDEX_FIELD_VALUES idx_field_vals;
- char path[FN_REFLEN], *end, *base_name, *orig_base_name, *file_name;
+ char path[FN_REFLEN], *base_name, *orig_base_name, *file_name;
uint len;
bool with_i_schema;
enum enum_schema_tables schema_table_idx;
List<char> bases;
List_iterator_fast<char> it(bases);
COND *partial_cond;
- Security_context *sctx= thd->security_ctx;
uint derived_tables= lex->derived_tables;
int error= 1;
enum legacy_db_type not_used;
Open_tables_state open_tables_state_backup;
bool save_view_prepare_mode= lex->view_prepare_mode;
Query_tables_list query_tables_list_backup;
- lex->view_prepare_mode= TRUE;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *sctx= thd->security_ctx;
+#endif
DBUG_ENTER("get_all_tables");
- LINT_INIT(end);
LINT_INIT(len);
+ lex->view_prepare_mode= TRUE;
lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
/*
@@ -2597,7 +2641,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
else
{
len= build_table_filename(path, sizeof(path), base_name, "", "", 0);
- end= path + len;
len= FN_LEN - len;
find_files_result res= find_files(thd, &files, base_name,
path, idx_field_vals.table_value, 0);
@@ -2647,7 +2690,9 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
}
else
{
- my_snprintf(end, len, "/%s%s", file_name, reg_ext);
+ build_table_filename(path, sizeof(path),
+ base_name, file_name, reg_ext, 0);
+
switch (mysql_frm_type(thd, path, &not_used)) {
case FRMTYPE_ERROR:
table->field[3]->store(STRING_WITH_LEN("ERROR"),
@@ -2747,7 +2792,9 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
bool with_i_schema;
HA_CREATE_INFO create;
TABLE *table= tables->table;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *sctx= thd->security_ctx;
+#endif
DBUG_ENTER("fill_schema_shemata");
if (make_db_list(thd, &files, &idx_field_vals,
@@ -2891,20 +2938,21 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
if (file->stats.create_time)
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
- file->stats.create_time);
+ (my_time_t) file->stats.create_time);
table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[14]->set_notnull();
}
if (file->stats.update_time)
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
- file->stats.update_time);
+ (my_time_t) file->stats.update_time);
table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[15]->set_notnull();
}
if (file->stats.check_time)
{
- thd->variables.time_zone->gmt_sec_to_TIME(&time, file->stats.check_time);
+ thd->variables.time_zone->gmt_sec_to_TIME(&time,
+ (my_time_t) file->stats.check_time);
table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[16]->set_notnull();
}
@@ -3102,7 +3150,7 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type
field->real_type() == MYSQL_TYPE_STRING) // For binary type
{
- uint32 octet_max_length= field->max_length();
+ uint32 octet_max_length= field->max_display_length();
if (is_blob && octet_max_length != (uint32) 4294967295U)
octet_max_length /= field->charset()->mbmaxlen;
longlong char_max_len= is_blob ?
@@ -3132,10 +3180,10 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_INT24:
- field_length= field->max_length() - 1;
+ field_length= field->max_display_length() - 1;
break;
case MYSQL_TYPE_BIT:
- field_length= field->max_length();
+ field_length= field->max_display_length();
decimals= -1; // return NULL
break;
case MYSQL_TYPE_FLOAT:
@@ -3854,8 +3902,8 @@ static int get_schema_key_column_usage_record(THD *thd,
show_table->file->get_foreign_key_list(thd, &f_key_list);
FOREIGN_KEY_INFO *f_key_info;
- List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
- while ((f_key_info= it++))
+ List_iterator_fast<FOREIGN_KEY_INFO> fkey_it(f_key_list);
+ while ((f_key_info= fkey_it++))
{
LEX_STRING *f_info;
LEX_STRING *r_info;
@@ -4019,7 +4067,6 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables,
partition_element *part_elem;
List_iterator<partition_element> part_it(part_info->partitions);
uint part_pos= 0, part_id= 0;
- uint no_parts= part_info->no_parts;
restore_record(table, s->default_values);
table->field[1]->store(base_name, strlen(base_name), cs);
@@ -4189,6 +4236,7 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables,
}
+#ifdef NOT_USED
static interval_type get_real_interval_type(interval_type i_type)
{
switch (i_type) {
@@ -4232,6 +4280,8 @@ static interval_type get_real_interval_type(interval_type i_type)
return INTERVAL_SECOND;
}
+#endif
+
/*
Loads an event from mysql.event and copies it's data to a row of
@@ -4497,8 +4547,10 @@ get_referential_constraints_record(THD *thd, struct st_table_list *tables,
f_key_info->forein_id->length, cs);
table->field[4]->store(f_key_info->referenced_db->str,
f_key_info->referenced_db->length, cs);
- table->field[5]->store(f_key_info->referenced_table->str,
+ table->field[10]->store(f_key_info->referenced_table->str,
f_key_info->referenced_table->length, cs);
+ table->field[5]->store(f_key_info->referenced_key_name->str,
+ f_key_info->referenced_key_name->length, cs);
table->field[6]->store(STRING_WITH_LEN("NONE"), cs);
table->field[7]->store(f_key_info->update_method->str,
f_key_info->update_method->length, cs);
@@ -4511,6 +4563,44 @@ get_referential_constraints_record(THD *thd, struct st_table_list *tables,
DBUG_RETURN(0);
}
+struct schema_table_ref
+{
+ const char *table_name;
+ ST_SCHEMA_TABLE *schema_table;
+};
+
+
+/*
+ Find schema_tables elment by name
+
+ SYNOPSIS
+ find_schema_table_in_plugin()
+ thd thread handler
+ plugin plugin
+ table_name table name
+
+ RETURN
+ 0 table not found
+ 1 found the schema table
+*/
+static my_bool find_schema_table_in_plugin(THD *thd, st_plugin_int *plugin,
+ void* p_table)
+{
+ schema_table_ref *p_schema_table= (schema_table_ref *)p_table;
+ const char* table_name= p_schema_table->table_name;
+ ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data;
+ DBUG_ENTER("find_schema_table_in_plugin");
+
+ if (!my_strcasecmp(system_charset_info,
+ schema_table->table_name,
+ table_name)) {
+ p_schema_table->schema_table= schema_table;
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN(0);
+}
+
/*
Find schema_tables elment by name
@@ -4527,15 +4617,24 @@ get_referential_constraints_record(THD *thd, struct st_table_list *tables,
ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
{
+ schema_table_ref schema_table_a;
ST_SCHEMA_TABLE *schema_table= schema_tables;
+ DBUG_ENTER("find_schema_table");
+
for (; schema_table->table_name; schema_table++)
{
if (!my_strcasecmp(system_charset_info,
schema_table->table_name,
table_name))
- return schema_table;
+ DBUG_RETURN(schema_table);
}
- return 0;
+
+ schema_table_a.table_name= table_name;
+ if (plugin_foreach(thd, find_schema_table_in_plugin,
+ MYSQL_INFORMATION_SCHEMA_PLUGIN, &schema_table_a))
+ DBUG_RETURN(schema_table_a.schema_table);
+
+ DBUG_RETURN(NULL);
}
@@ -4948,13 +5047,15 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
SYNOPSIS
get_schema_tables_result()
join join which use schema tables
+ executed_place place where I_S table processed
RETURN
FALSE success
TRUE error
*/
-bool get_schema_tables_result(JOIN *join)
+bool get_schema_tables_result(JOIN *join,
+ enum enum_schema_table_state executed_place)
{
JOIN_TAB *tmp_join_tab= join->join_tab+join->tables;
THD *thd= join->thd;
@@ -4974,15 +5075,26 @@ bool get_schema_tables_result(JOIN *join)
bool is_subselect= (&lex->unit != lex->current_select->master_unit() &&
lex->current_select->master_unit()->item);
/*
- The schema table is already processed and
- the statement is not a subselect.
- So we don't need to handle this table again.
+ If schema table is already processed and
+ the statement is not a subselect then
+ we don't need to fill this table again.
+ If schema table is already processed and
+ schema_table_state != executed_place then
+ table is already processed and
+ we should skip second data processing.
*/
- if (table_list->is_schema_table_processed && !is_subselect)
+ if (table_list->schema_table_state &&
+ (!is_subselect || table_list->schema_table_state != executed_place))
continue;
- if (is_subselect) // is subselect
+ /*
+ if table is used in a subselect and
+ table has been processed earlier with the same
+ 'executed_place' value then we should refresh the table.
+ */
+ if (table_list->schema_table_state && is_subselect)
{
+ table_list->table->file->extra(HA_EXTRA_NO_CACHE);
table_list->table->file->extra(HA_EXTRA_RESET_STATE);
table_list->table->file->delete_all_rows();
free_io_cache(table_list->table);
@@ -4997,10 +5109,10 @@ bool get_schema_tables_result(JOIN *join)
{
result= 1;
join->error= 1;
- table_list->is_schema_table_processed= TRUE;
+ table_list->schema_table_state= executed_place;
break;
}
- table_list->is_schema_table_processed= TRUE;
+ table_list->schema_table_state= executed_place;
}
}
thd->no_warnings_for_error= 0;
@@ -5026,7 +5138,6 @@ static my_bool run_hton_fill_schema_files(THD *thd, st_plugin_int *plugin,
int fill_schema_files(THD *thd, TABLE_LIST *tables, COND *cond)
{
- TABLE *table= tables->table;
DBUG_ENTER("fill_schema_files");
struct run_hton_fill_schema_files_args args;
@@ -5084,7 +5195,7 @@ int fill_schema_status(THD *thd, SHOW_VAR *variables,
if (show_type == SHOW_SYS)
{
- show_type= ((sys_var*) value)->type();
+ show_type= ((sys_var*) value)->show_type();
value= (char*) ((sys_var*) value)->value_ptr(thd, OPT_GLOBAL,
&null_lex_str);
}
@@ -5668,6 +5779,7 @@ ST_FIELD_INFO referential_constraints_fields_info[]=
{"UPDATE_RULE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"DELETE_RULE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"REFERENCED_TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5752,3 +5864,54 @@ ST_SCHEMA_TABLE schema_tables[]=
template class List_iterator_fast<char>;
template class List<char>;
#endif
+
+int initialize_schema_table(st_plugin_int *plugin)
+{
+ ST_SCHEMA_TABLE *schema_table;
+ DBUG_ENTER("initialize_schema_table");
+
+ if (!(schema_table= (ST_SCHEMA_TABLE *)my_malloc(sizeof(ST_SCHEMA_TABLE),
+ MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(1);
+ /* Historical Requirement */
+ plugin->data= schema_table; // shortcut for the future
+ if (plugin->plugin->init)
+ {
+ schema_table->create_table= create_schema_table;
+ schema_table->old_format= make_old_format;
+ schema_table->idx_field1= -1,
+ schema_table->idx_field2= -1;
+
+ if (plugin->plugin->init(schema_table))
+ {
+ sql_print_error("Plugin '%s' init function returned error.",
+ plugin->name.str);
+ goto err;
+ }
+ schema_table->table_name= plugin->name.str;
+ }
+
+ DBUG_RETURN(0);
+err:
+ my_free((gptr)schema_table, MYF(0));
+ DBUG_RETURN(1);
+}
+
+int finalize_schema_table(st_plugin_int *plugin)
+{
+ ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data;
+ DBUG_ENTER("finalize_schema_table");
+
+ if (schema_table && plugin->plugin->deinit)
+ {
+ DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
+ if (plugin->plugin->deinit(NULL))
+ {
+ DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
+ plugin->name.str));
+ }
+ my_free((gptr)schema_table, MYF(0));
+ }
+
+ DBUG_RETURN(0);
+}
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 2aaab83796f..52af2f2dd90 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -607,27 +607,26 @@ skip:
}
/*
-** replace substring with string
-** If wrong parameter or not enough memory, do nothing
+ Replace substring with string
+ If wrong parameter or not enough memory, do nothing
*/
-
bool String::replace(uint32 offset,uint32 arg_length,const String &to)
{
return replace(offset,arg_length,to.ptr(),to.length());
}
bool String::replace(uint32 offset,uint32 arg_length,
- const char *to,uint32 length)
+ const char *to, uint32 to_length)
{
- long diff = (long) length-(long) arg_length;
+ long diff = (long) to_length-(long) arg_length;
if (offset+arg_length <= str_length)
{
if (diff < 0)
{
- if (length)
- memcpy(Ptr+offset,to,length);
- bmove(Ptr+offset+length,Ptr+offset+arg_length,
+ if (to_length)
+ memcpy(Ptr+offset,to,to_length);
+ bmove(Ptr+offset+to_length,Ptr+offset+arg_length,
str_length-offset-arg_length);
}
else
@@ -639,8 +638,8 @@ bool String::replace(uint32 offset,uint32 arg_length,
bmove_upp(Ptr+str_length+diff,Ptr+str_length,
str_length-offset-arg_length);
}
- if (length)
- memcpy(Ptr+offset,to,length);
+ if (to_length)
+ memcpy(Ptr+offset,to,to_length);
}
str_length+=(uint32) diff;
}
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 08c3a4cb60d..128ed749b5f 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -84,7 +84,8 @@ public:
{ /* never called */ }
~String() { free(); }
- inline void set_charset(CHARSET_INFO *charset) { str_charset= charset; }
+ inline void set_charset(CHARSET_INFO *charset_arg)
+ { str_charset= charset_arg; }
inline CHARSET_INFO *charset() const { return str_charset; }
inline uint32 length() const { return str_length;}
inline uint32 alloced_length() const { return Alloced_length;}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 351e16ff12a..0697fdd79b4 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -41,7 +41,7 @@ static int copy_data_between_tables(TABLE *from,TABLE *to,
static bool prepare_blob_field(THD *thd, create_field *sql_field);
static bool check_engine(THD *thd, const char *table_name,
- HA_CREATE_INFO *create_info);
+ HA_CREATE_INFO *create_info);
static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
List<create_field> *fields,
List<Key> *keys, bool tmp_table,
@@ -460,10 +460,10 @@ static bool write_ddl_log_header()
global_ddl_log.num_entries);
const_var= FN_LEN;
int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS],
- const_var);
+ (ulong) const_var);
const_var= IO_SIZE;
int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS],
- const_var);
+ (ulong) const_var);
if (write_ddl_log_file_entry(0UL))
{
sql_print_error("Error writing ddl log header");
@@ -598,7 +598,6 @@ bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry)
static bool init_ddl_log()
{
- bool error= FALSE;
char file_name[FN_REFLEN];
DBUG_ENTER("init_ddl_log");
@@ -2296,14 +2295,14 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
interval= sql_field->interval= typelib(stmt_root,
sql_field->interval_list);
- List_iterator<String> it(sql_field->interval_list);
+ List_iterator<String> int_it(sql_field->interval_list);
String conv, *tmp;
char comma_buf[2];
int comma_length= cs->cset->wc_mb(cs, ',', (uchar*) comma_buf,
(uchar*) comma_buf +
sizeof(comma_buf));
DBUG_ASSERT(comma_length > 0);
- for (uint i= 0; (tmp= it++); i++)
+ for (uint i= 0; (tmp= int_it++); i++)
{
uint lengthsp;
if (String::needs_conversion(tmp->length(), tmp->charset(),
@@ -3417,16 +3416,11 @@ bool mysql_create_table_internal(THD *thd,
{
#ifdef FN_DEVCHAR
/* check if the table name contains FN_DEVCHAR when defined */
- const char *start= alias;
- while (*start != '\0')
+ if (strchr(alias, FN_DEVCHAR))
{
- if (*start == FN_DEVCHAR)
- {
- my_error(ER_WRONG_TABLE_NAME, MYF(0), alias);
- DBUG_RETURN(TRUE);
- }
- start++;
- }
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), alias);
+ DBUG_RETURN(TRUE);
+ }
#endif
path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext,
internal_tmp_table ? FN_IS_TMP : 0);
@@ -4037,7 +4031,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
HA_CHECK_OPT *),
int (view_operator_func)(THD *, TABLE_LIST*))
{
- TABLE_LIST *table, *save_next_global, *save_next_local;
+ TABLE_LIST *table;
SELECT_LEX *select= &thd->lex->select_lex;
List<Item> field_list;
Item *item;
@@ -4071,46 +4065,48 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
thd->open_options|= extra_open_options;
table->lock_type= lock_type;
/* open only one table from local list of command */
- save_next_global= table->next_global;
- table->next_global= 0;
- save_next_local= table->next_local;
- table->next_local= 0;
- select->table_list.first= (byte*)table;
- /*
- Time zone tables and SP tables can be add to lex->query_tables list,
- so it have to be prepared.
- TODO: Investigate if we can put extra tables into argument instead of
- using lex->query_tables
- */
- lex->query_tables= table;
- lex->query_tables_last= &table->next_global;
- lex->query_tables_own_last= 0;
- thd->no_warnings_for_error= no_warnings_for_error;
- if (view_operator_func == NULL)
- table->required_type=FRMTYPE_TABLE;
-
- /*
- If we want to perform an admin operation on the log table
- (E.g. rename) and lock_type >= TL_READ_NO_INSERT disable
- log tables
- */
-
- if (check_if_log_table(table->db_length, table->db,
- table->table_name_length,
- table->table_name, 1) &&
- lock_type >= TL_READ_NO_INSERT)
{
- disable_logs= 1;
- logger.lock();
- logger.tmp_close_log_tables(thd);
- }
+ TABLE_LIST *save_next_global, *save_next_local;
+ save_next_global= table->next_global;
+ table->next_global= 0;
+ save_next_local= table->next_local;
+ table->next_local= 0;
+ select->table_list.first= (byte*)table;
+ /*
+ Time zone tables and SP tables can be add to lex->query_tables list,
+ so it have to be prepared.
+ TODO: Investigate if we can put extra tables into argument instead of
+ using lex->query_tables
+ */
+ lex->query_tables= table;
+ lex->query_tables_last= &table->next_global;
+ lex->query_tables_own_last= 0;
+ thd->no_warnings_for_error= no_warnings_for_error;
+ if (view_operator_func == NULL)
+ table->required_type=FRMTYPE_TABLE;
- open_and_lock_tables(thd, table);
- thd->no_warnings_for_error= 0;
- table->next_global= save_next_global;
- table->next_local= save_next_local;
- thd->open_options&= ~extra_open_options;
+ /*
+ If we want to perform an admin operation on the log table
+ (E.g. rename) and lock_type >= TL_READ_NO_INSERT disable
+ log tables
+ */
+ if (check_if_log_table(table->db_length, table->db,
+ table->table_name_length,
+ table->table_name, 1) &&
+ lock_type >= TL_READ_NO_INSERT)
+ {
+ disable_logs= 1;
+ logger.lock();
+ logger.tmp_close_log_tables(thd);
+ }
+
+ open_and_lock_tables(thd, table);
+ thd->no_warnings_for_error= 0;
+ table->next_global= save_next_global;
+ table->next_local= save_next_local;
+ thd->open_options&= ~extra_open_options;
+ }
if (prepare_func)
{
switch ((*prepare_func)(thd, table, check_opt)) {
@@ -4601,7 +4597,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
Table_ident *table_ident)
{
TABLE *tmp_table;
- char src_path[FN_REFLEN], dst_path[FN_REFLEN], tmp_path[FN_REFLEN];
+ char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char src_table_name_buff[FN_REFLEN], src_db_name_buff[FN_REFLEN];
uint dst_path_length;
char *db= table->db;
@@ -4612,7 +4608,9 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
bool res= TRUE, unlock_dst_table= FALSE;
enum legacy_db_type not_used;
HA_CREATE_INFO *create_info;
-
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ char tmp_path[FN_REFLEN];
+#endif
TABLE_LIST src_tables_list, dst_tables_list;
DBUG_ENTER("mysql_create_like_table");
@@ -4820,7 +4818,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
else
unlock_dst_table= TRUE;
- int result= store_create_info(thd, table, &query, create_info);
+ IF_DBUG(int result=) store_create_info(thd, table, &query,
+ create_info);
DBUG_ASSERT(result == 0); // store_create_info() always return 0
write_bin_log(thd, TRUE, query.ptr(), query.length());
@@ -5303,7 +5302,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
ALTER_INFO *alter_info, bool do_send_ok)
{
TABLE *table,*new_table=0;
- int error;
+ int error= 0;
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN];
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
char index_file[FN_REFLEN], data_file[FN_REFLEN], tablespace[FN_LEN];
@@ -5413,11 +5412,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
VOID(pthread_mutex_lock(&LOCK_open));
if (lock_table_names(thd, table_list))
{
- error= TRUE;
+ error= 1;
goto view_err;
}
- error= FALSE;
if (!do_rename(thd, table_list, new_db, new_name, new_name, 1))
{
if (mysql_bin_log.is_open())
@@ -5544,7 +5542,6 @@ view_err:
{
switch (alter_info->keys_onoff) {
case LEAVE_AS_IS:
- error= 0;
break;
case ENABLE:
/*
@@ -5576,10 +5573,10 @@ view_err:
}
if (error == HA_ERR_WRONG_COMMAND)
{
+ error= 0;
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
table->alias);
- error= 0;
}
VOID(pthread_mutex_lock(&LOCK_open));
@@ -5620,10 +5617,10 @@ view_err:
if (error == HA_ERR_WRONG_COMMAND)
{
+ error= 0;
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
table->alias);
- error= 0;
}
if (!error)
@@ -6649,7 +6646,8 @@ view_err:
thd->query, thd->query_length,
db, table_name);
- DBUG_ASSERT(!(mysql_bin_log.is_open() && thd->current_stmt_binlog_row_based &&
+ DBUG_ASSERT(!(mysql_bin_log.is_open() &&
+ thd->current_stmt_binlog_row_based &&
(create_info->options & HA_LEX_CREATE_TMP_TABLE)));
write_bin_log(thd, TRUE, thd->query, thd->query_length);
@@ -6712,7 +6710,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
Copy_field *copy,*copy_end;
ulong found_count,delete_count;
THD *thd= current_thd;
- uint length;
+ uint length= 0;
SORT_FIELD *sortorder;
READ_RECORD info;
TABLE_LIST tables;
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 4fc5bde8fdc..9e30cf5878c 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -73,17 +73,18 @@ void print_cached_tables(void)
uint idx,count,unused;
TABLE *start_link,*lnk;
+ /* purecov: begin tested */
VOID(pthread_mutex_lock(&LOCK_open));
- puts("DB Table Version Thread L.thread Open Lock");
+ puts("DB Table Version Thread Open Lock");
for (idx=unused=0 ; idx < open_cache.records ; idx++)
{
TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
- printf("%-14.14s %-32s%6ld%8ld%10ld%6d %s\n",
- entry->s->db.str, entry->s->table_name.str, entry->s->version,
+ printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
+ entry->s->db.str, entry->s->table_name.str, entry->s->version,
entry->in_use ? entry->in_use->thread_id : 0L,
- entry->in_use ? entry->in_use->dbug_thread_id : 0L,
- entry->db_stat ? 1 : 0, entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use");
+ entry->db_stat ? 1 : 0,
+ entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use");
if (!entry->in_use)
unused++;
}
@@ -110,6 +111,7 @@ void print_cached_tables(void)
printf("Error: File hash table is corrupted\n");
fflush(stdout);
VOID(pthread_mutex_unlock(&LOCK_open));
+ /* purecov: end */
return;
}
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 3f9058f74c2..c8680aecd50 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -106,10 +106,6 @@ const LEX_STRING trg_event_type_names[]=
};
-static int
-add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
- TABLE_LIST ** table);
-
class Handle_old_incorrect_sql_modes_hook: public Unknown_key_hook
{
private:
@@ -781,7 +777,7 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table)
table == (*fld)->table)))
return 1;
(*old_fld)->move_field_offset((my_ptrdiff_t)(table->record[1] -
- table->record[0]));
+ table->record[0]));
}
*old_fld= 0;
@@ -799,8 +795,8 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table)
void Table_triggers_list::set_table(TABLE *new_table)
{
- table= new_table;
- for (Field **field= table->triggers->record1_field ; *field ; field++)
+ trigger_table= new_table;
+ for (Field **field= new_table->triggers->record1_field ; *field ; field++)
{
(*field)->table= (*field)->orig_table= new_table;
(*field)->table_name= &new_table->alias;
@@ -985,11 +981,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
thd->spcont= 0;
if (MYSQLparse((void *)thd) || thd->is_fatal_error)
{
- /*
- Free lex associated resources.
- QQ: Do we really need all this stuff here ?
- */
- delete lex.sphead;
+ /* Currently sphead is always deleted in case of a parse error */
+ DBUG_ASSERT(lex.sphead == 0);
goto err_with_lex_cleanup;
}
@@ -1180,7 +1173,7 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
1 Error
*/
-static int
+int
add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
TABLE_LIST **table)
{
@@ -1363,7 +1356,8 @@ Table_triggers_list::change_table_name_in_triggers(THD *thd,
It is OK to allocate some memory on table's MEM_ROOT since this
table instance will be thrown out at the end of rename anyway.
*/
- new_def.str= memdup_root(&table->mem_root, buff.ptr(), buff.length());
+ new_def.str= memdup_root(&trigger_table->mem_root, buff.ptr(),
+ buff.length());
new_def.length= buff.length();
on_table_name->str= new_def.str + before_on_len;
on_table_name->length= on_q_table_name_len;
@@ -1541,12 +1535,12 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
if (old_row_is_record1)
{
old_field= record1_field;
- new_field= table->field;
+ new_field= trigger_table->field;
}
else
{
new_field= record1_field;
- old_field= table->field;
+ old_field= trigger_table->field;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *save_ctx;
@@ -1562,7 +1556,8 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
fill_effective_table_privileges(thd,
&subject_table_grants[event][time_type],
- table->s->db.str, table->s->table_name.str);
+ trigger_table->s->db.str,
+ trigger_table->s->table_name.str);
/* Check that the definer has TRIGGER privilege on the subject table. */
@@ -1573,7 +1568,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), priv_desc,
thd->security_ctx->priv_user, thd->security_ctx->host_or_ip,
- table->s->table_name.str);
+ trigger_table->s->table_name.str);
sp_restore_security_context(thd, save_ctx);
return TRUE;
@@ -1582,7 +1577,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
err_status= sp_trigger->execute_trigger
- (thd, table->s->db.str, table->s->table_name.str,
+ (thd, trigger_table->s->db.str, trigger_table->s->table_name.str,
&subject_table_grants[event][time_type]);
thd->restore_sub_statement_state(&statement_state);
@@ -1623,13 +1618,13 @@ void Table_triggers_list::mark_fields_used(trg_event_type event)
/* We cannot mark fields which does not present in table. */
if (trg_field->field_idx != (uint)-1)
{
- bitmap_set_bit(table->read_set, trg_field->field_idx);
+ bitmap_set_bit(trigger_table->read_set, trg_field->field_idx);
if (trg_field->get_settable_routine_parameter())
- bitmap_set_bit(table->write_set, trg_field->field_idx);
+ bitmap_set_bit(trigger_table->write_set, trg_field->field_idx);
}
}
}
- table->file->column_bitmaps_signal();
+ trigger_table->file->column_bitmaps_signal();
}
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index 3892e964aa7..707fcc4e380 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -42,8 +42,9 @@ class Table_triggers_list: public Sql_alloc
*/
Field **new_field;
Field **old_field;
+
/* TABLE instance for which this triggers list object was created */
- TABLE *table;
+ TABLE *trigger_table;
/*
Names of triggers.
Should correspond to order of triggers on definitions_list,
@@ -83,7 +84,7 @@ public:
List<LEX_STRING> definers_list;
Table_triggers_list(TABLE *table_arg):
- record1_field(0), table(table_arg)
+ record1_field(0), trigger_table(table_arg)
{
bzero((char *)bodies, sizeof(bodies));
bzero((char *)trigger_fields, sizeof(trigger_fields));
@@ -136,3 +137,7 @@ private:
extern const LEX_STRING trg_action_time_type_names[];
extern const LEX_STRING trg_event_type_names[];
+
+int
+add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
+ TABLE_LIST **table);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index e9e244676d1..f020168d742 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -111,7 +111,7 @@ bool select_union::flush()
*/
bool
-select_union::create_result_table(THD *thd, List<Item> *column_types,
+select_union::create_result_table(THD *thd_arg, List<Item> *column_types,
bool is_union_distinct, ulonglong options,
const char *alias)
{
@@ -119,7 +119,7 @@ select_union::create_result_table(THD *thd, List<Item> *column_types,
tmp_table_param.init();
tmp_table_param.field_count= column_types->elements;
- if (! (table= create_tmp_table(thd, &tmp_table_param, *column_types,
+ if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
(ORDER*) 0, is_union_distinct, 1,
options, HA_POS_ERROR, (char*) alias)))
return TRUE;
@@ -141,12 +141,14 @@ select_union::create_result_table(THD *thd, List<Item> *column_types,
*/
void
-st_select_lex_unit::init_prepare_fake_select_lex(THD *thd)
+st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg)
{
- thd->lex->current_select= fake_select_lex;
+ thd_arg->lex->current_select= fake_select_lex;
fake_select_lex->table_list.link_in_list((byte *)&result_table_list,
(byte **)
&result_table_list.next_local);
+ fake_select_lex->context.table_list= fake_select_lex->context.first_name_resolution_table=
+ fake_select_lex->get_table_list();
for (ORDER *order= (ORDER *)global_parameters->order_list.first;
order;
order=order->next)
@@ -197,7 +199,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
DBUG_RETURN(FALSE);
}
prepared= 1;
- res= FALSE;
+ saved_error= FALSE;
thd_arg->lex->current_select= sl= first_sl;
found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS;
@@ -238,23 +240,25 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
can_skip_order_by= is_union && !(sl->braces && sl->explicit_limit);
- res= join->prepare(&sl->ref_pointer_array,
- (TABLE_LIST*) sl->table_list.first, sl->with_wild,
- sl->where,
- (can_skip_order_by ? 0 : sl->order_list.elements) +
- sl->group_list.elements,
- can_skip_order_by ?
- (ORDER*) 0 : (ORDER *)sl->order_list.first,
- (ORDER*) sl->group_list.first,
- sl->having,
- (is_union ? (ORDER*) 0 :
- (ORDER*) thd_arg->lex->proc_list.first),
- sl, this);
+ saved_error= join->prepare(&sl->ref_pointer_array,
+ (TABLE_LIST*) sl->table_list.first,
+ sl->with_wild,
+ sl->where,
+ (can_skip_order_by ? 0 :
+ sl->order_list.elements) +
+ sl->group_list.elements,
+ can_skip_order_by ?
+ (ORDER*) 0 : (ORDER *)sl->order_list.first,
+ (ORDER*) sl->group_list.first,
+ sl->having,
+ (is_union ? (ORDER*) 0 :
+ (ORDER*) thd_arg->lex->proc_list.first),
+ sl, this);
/* There are no * in the statement anymore (for PS) */
sl->with_wild= 0;
last_procedure= join->procedure;
- if ((res= (res || thd_arg->is_fatal_error)))
+ if (saved_error || (saved_error= thd_arg->is_fatal_error))
goto err;
/*
Use items list of underlaid select for derived tables to preserve
@@ -349,12 +353,12 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
arena= thd->activate_stmt_arena_if_needed(&backup_arena);
- res= table->fill_item_list(&item_list);
+ saved_error= table->fill_item_list(&item_list);
if (arena)
thd->restore_active_arena(arena, &backup_arena);
- if (res)
+ if (saved_error)
goto err;
if (thd->stmt_arena->is_stmt_prepare())
@@ -373,7 +377,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
fake_select_lex->item_list= item_list;
thd_arg->lex->current_select= fake_select_lex;
- res= fake_select_lex->join->
+ saved_error= fake_select_lex->join->
prepare(&fake_select_lex->ref_pointer_array,
(TABLE_LIST*) fake_select_lex->table_list.first,
0, 0,
@@ -398,7 +402,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
thd_arg->lex->current_select= lex_select_save;
- DBUG_RETURN(res || thd_arg->is_fatal_error);
+ DBUG_RETURN(saved_error || thd_arg->is_fatal_error);
err:
thd_arg->lex->current_select= lex_select_save;
@@ -442,7 +446,7 @@ bool st_select_lex_unit::exec()
thd->lex->current_select= sl;
if (optimized)
- res= sl->join->reinit();
+ saved_error= sl->join->reinit();
else
{
set_limit(sl);
@@ -465,9 +469,9 @@ bool st_select_lex_unit::exec()
sl->join->select_options=
(select_limit_cnt == HA_POS_ERROR || sl->braces) ?
sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
- res= sl->join->optimize();
+ saved_error= sl->join->optimize();
}
- if (!res)
+ if (!saved_error)
{
records_at_start= table->file->stats.records;
sl->join->exec();
@@ -477,11 +481,11 @@ bool st_select_lex_unit::exec()
DBUG_RETURN(TRUE);
table->no_keyread=1;
}
- res= sl->join->error;
+ saved_error= sl->join->error;
offset_limit_cnt= (ha_rows)(sl->offset_limit ?
sl->offset_limit->val_uint() :
0);
- if (!res)
+ if (!saved_error)
{
examined_rows+= thd->examined_row_count;
if (union_result->flush())
@@ -491,10 +495,10 @@ bool st_select_lex_unit::exec()
}
}
}
- if (res)
+ if (saved_error)
{
thd->lex->current_select= lex_select_save;
- DBUG_RETURN(res);
+ DBUG_RETURN(saved_error);
}
/* Needed for the following test and for records_at_start in next loop */
int error= table->file->info(HA_STATUS_VARIABLE);
@@ -520,7 +524,7 @@ bool st_select_lex_unit::exec()
optimized= 1;
/* Send result to 'result' */
- res= TRUE;
+ saved_error= TRUE;
{
List<Item_func_match> empty_list;
empty_list.empty();
@@ -561,17 +565,17 @@ bool st_select_lex_unit::exec()
}
join->init(thd, item_list, fake_select_lex->options, result);
}
- res= mysql_select(thd, &fake_select_lex->ref_pointer_array,
- &result_table_list,
- 0, item_list, NULL,
- global_parameters->order_list.elements,
- (ORDER*)global_parameters->order_list.first,
- (ORDER*) NULL, NULL, (ORDER*) NULL,
- fake_select_lex->options | SELECT_NO_UNLOCK,
- result, this, fake_select_lex);
+ saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
+ &result_table_list,
+ 0, item_list, NULL,
+ global_parameters->order_list.elements,
+ (ORDER*)global_parameters->order_list.first,
+ (ORDER*) NULL, NULL, (ORDER*) NULL,
+ fake_select_lex->options | SELECT_NO_UNLOCK,
+ result, this, fake_select_lex);
fake_select_lex->table_list.empty();
- if (!res)
+ if (!saved_error)
{
thd->limit_found_rows = (ulonglong)table->file->stats.records + add_rows;
thd->examined_row_count+= examined_rows;
@@ -583,7 +587,7 @@ bool st_select_lex_unit::exec()
}
}
thd->lex->current_select= lex_select_save;
- DBUG_RETURN(res);
+ DBUG_RETURN(saved_error);
}
@@ -660,18 +664,18 @@ void st_select_lex_unit::reinit_exec_mechanism()
TRUE - error
*/
-bool st_select_lex_unit::change_result(select_subselect *result,
+bool st_select_lex_unit::change_result(select_subselect *new_result,
select_subselect *old_result)
{
bool res= FALSE;
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
{
if (sl->join && sl->join->result == old_result)
- if (sl->join->change_result(result))
+ if (sl->join->change_result(new_result))
return TRUE;
}
if (fake_select_lex && fake_select_lex->join)
- res= fake_select_lex->join->change_result(result);
+ res= fake_select_lex->join->change_result(new_result);
return (res);
}
@@ -734,6 +738,7 @@ bool st_select_lex::cleanup()
{
error= (bool) ((uint) error | (uint) lex_unit->cleanup());
}
+ non_agg_fields.empty();
DBUG_RETURN(error);
}
@@ -750,4 +755,3 @@ void st_select_lex::cleanup_all_joins(bool full)
for (sl= unit->first_select(); sl; sl= sl->next_select())
sl->cleanup_all_joins(full);
}
-
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 370efff201b..27a58a295ff 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -26,7 +26,7 @@
/* Return 0 if row hasn't changed */
-static bool compare_record(TABLE *table)
+bool compare_record(TABLE *table)
{
if (table->s->blob_fields + table->s->varchar_fields == 0)
return cmp_record(table,record[1]);
@@ -64,7 +64,6 @@ static bool check_fields(THD *thd, List<Item> &items)
List_iterator<Item> it(items);
Item *item;
Item_field *field;
- Name_resolution_context *context= &thd->lex->select_lex.context;
while ((item= it++))
{
@@ -134,6 +133,7 @@ int mysql_update(THD *thd,
SELECT_LEX *select_lex= &thd->lex->select_lex;
bool need_reopen;
ulonglong id;
+ List<Item> all_fields;
DBUG_ENTER("mysql_update");
for ( ; ; )
@@ -217,6 +217,10 @@ int mysql_update(THD *thd,
DBUG_RETURN(1); /* purecov: inspected */
}
+ if (select_lex->inner_refs_list.elements &&
+ fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
+ DBUG_RETURN(-1);
+
if (conds)
{
Item::cond_result cond_value;
@@ -318,7 +322,7 @@ int mysql_update(THD *thd,
to update
NOTE: filesort will call table->prepare_for_position()
*/
- uint length;
+ uint length= 0;
SORT_FIELD *sortorder;
ha_rows examined_rows;
@@ -903,7 +907,7 @@ reopen_tables:
tl->lock_type= using_update_log ? TL_READ_NO_INSERT : TL_READ;
tl->updating= 0;
/* Update TABLE::lock_type accordingly. */
- if (!tl->placeholder() && !tl->schema_table && !using_lock_tables)
+ if (!tl->placeholder() && !using_lock_tables)
tl->table->reginfo.lock_type= tl->lock_type;
}
}
@@ -1570,6 +1574,15 @@ int multi_update::do_updates(bool from_send_error)
if (!can_compare_record || compare_record(table))
{
+ int error;
+ if ((error= cur_table->view_check_option(thd, ignore)) !=
+ VIEW_CHECK_OK)
+ {
+ if (error == VIEW_CHECK_SKIP)
+ continue;
+ else if (error == VIEW_CHECK_ERROR)
+ goto err;
+ }
if ((local_error=table->file->ha_update_row(table->record[1],
table->record[0])))
{
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index a57d21ba7b2..622f7b99d33 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -713,7 +713,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
File_parser *parser;
path.str= path_buff;
- fn_format(path_buff, file.str, dir.str, 0, MY_UNPACK_FILENAME);
+ fn_format(path_buff, file.str, dir.str, "", MY_UNPACK_FILENAME);
path.length= strlen(path_buff);
if (!access(path.str, F_OK))
@@ -862,7 +862,8 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
Query_arena *arena, backup;
TABLE_LIST *top_view= table->top_table();
int res;
- bool result;
+ bool result, view_is_mergeable;
+ TABLE_LIST *view_main_select_tables;
DBUG_ENTER("mysql_make_view");
DBUG_PRINT("info", ("table: 0x%lx (%s)", (ulong) table, table->table_name));
@@ -1095,9 +1096,8 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
*/
if (lex->binlog_row_based_if_mixed)
old_lex->binlog_row_based_if_mixed= TRUE;
- bool view_is_mergeable= (table->algorithm != VIEW_ALGORITHM_TMPTABLE &&
- lex->can_be_merged());
- TABLE_LIST *view_main_select_tables;
+ view_is_mergeable= (table->algorithm != VIEW_ALGORITHM_TMPTABLE &&
+ lex->can_be_merged());
LINT_INIT(view_main_select_tables);
if (view_is_mergeable)
@@ -1272,6 +1272,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
but it will not be included to SELECT_LEX tree, because it
will not be executed
*/
+ table->select_lex->order_list.push_back(&lex->select_lex.order_list);
goto ok;
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 1129aa89608..5d24fb4fa65 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -47,11 +47,18 @@ const LEX_STRING null_lex_str={0,0};
#define yyoverflow(A,B,C,D,E,F) {ulong val= *(F); if (my_yyoverflow((B), (D), &val)) { yyerror((char*) (A)); return 2; } else { *(F)= (YYSIZE_T)val; }}
-#define YYERROR_UNLESS(A) \
+#define MYSQL_YYABORT \
+ do \
+ { \
+ LEX::cleanup_lex_after_parse_error(YYTHD);\
+ YYABORT; \
+ } while (0)
+
+#define MYSQL_YYABORT_UNLESS(A) \
if (!(A)) \
- { \
- yyerror(ER(ER_SYNTAX_ERROR)); \
- YYABORT; \
+ { \
+ my_parse_error(ER(ER_SYNTAX_ERROR));\
+ MYSQL_YYABORT; \
}
/*
@@ -76,19 +83,6 @@ const LEX_STRING null_lex_str={0,0};
#define __attribute__(X)
#endif
-/* Helper for parsing "IS [NOT] truth_value" */
-inline Item *is_truth_value(THD *thd, Item *A, bool v1, bool v2)
-{
- Item *v1_t= new (thd->mem_root) Item_int((char *) (v1 ? "TRUE" : "FALSE"),
- v1, 1);
- Item *v1_f= new (thd->mem_root) Item_int((char *) (v1 ? "FALSE" : "TRUE"),
- !v1, 1);
- Item *v2_t= new (thd->mem_root) Item_int((char *) (v2 ? "TRUE" : "FALSE"),
- v2, 1);
- Item *ifnull= new (thd->mem_root) Item_func_ifnull(A, v2_t);
-
- return new (thd->mem_root) Item_func_if(ifnull, v1_t, v1_f);
-}
#ifndef DBUG_OFF
#define YYDEBUG 1
@@ -96,6 +90,66 @@ inline Item *is_truth_value(THD *thd, Item *A, bool v1, bool v2)
#define YYDEBUG 0
#endif
+/**
+ @brief Push an error message into MySQL error stack with line
+ and position information.
+
+ This function provides semantic action implementers with a way
+ to push the famous "You have a syntax error near..." error
+ message into the error stack, which is normally produced only if
+ a parse error is discovered internally by the Bison generated
+ parser.
+*/
+
+void my_parse_error(const char *s)
+{
+ THD *thd= current_thd;
+
+ char *yytext= (char*) thd->lex->tok_start;
+ /* Push an error into the error stack */
+ my_printf_error(ER_PARSE_ERROR, ER(ER_PARSE_ERROR), MYF(0), s,
+ (yytext ? (char*) yytext : ""),
+ thd->lex->yylineno);
+}
+
+/**
+ @brief Bison callback to report a syntax/OOM error
+
+ This function is invoked by the bison-generated parser
+ when a syntax error, a parse error or an out-of-memory
+ condition occurs. This function is not invoked when the
+ parser is requested to abort by semantic action code
+ by means of YYABORT or YYACCEPT macros. This is why these
+ macros should not be used (use MYSQL_YYABORT/MYSQL_YYACCEPT
+ instead).
+
+ The parser will abort immediately after invoking this callback.
+
+ This function is not for use in semantic actions and is internal to
+ the parser, as it performs some pre-return cleanup.
+ In semantic actions, please use my_parse_error or my_error to
+ push an error into the error stack and MYSQL_YYABORT
+ to abort from the parser.
+*/
+
+void MYSQLerror(const char *s)
+{
+ THD *thd= current_thd;
+
+ /*
+ Restore the original LEX if it was replaced when parsing
+ a stored procedure. We must ensure that a parsing error
+ does not leave any side effects in the THD.
+ */
+ LEX::cleanup_lex_after_parse_error(thd);
+
+ /* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
+ if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
+ s= ER(ER_SYNTAX_ERROR);
+ my_parse_error(s);
+}
+
+
#ifndef DBUG_OFF
void turn_parser_debug_on()
{
@@ -310,6 +364,81 @@ void case_stmt_action_end_case(LEX *lex, bool simple)
lex->sphead->do_cont_backpatch();
}
+/**
+ Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>.
+ See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383.
+ This function returns the proper item for the SQL expression
+ <code>left [NOT] IN ( expr )</code>
+ @param thd the current thread
+ @param left the in predicand
+ @param equal true for IN predicates, false for NOT IN predicates
+ @param expr first and only expression of the in value list
+ @return an expression representing the IN predicate.
+*/
+Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
+ Item *expr)
+{
+ /*
+ Relevant references for this issue:
+ - SQL:2003, Part 2, section 8.4 <in predicate>, page 383,
+ - SQL:2003, Part 2, section 7.2 <row value expression>, page 296,
+ - SQL:2003, Part 2, section 6.3 <value expression primary>, page 174,
+ - SQL:2003, Part 2, section 7.15 <subquery>, page 370,
+ - SQL:2003 Feature F561, "Full value expressions".
+
+ The exception in SQL:2003 Note 184 means:
+ Item_singlerow_subselect, which corresponds to a <scalar subquery>,
+ should be re-interpreted as an Item_in_subselect, which corresponds
+ to a <table subquery> when used inside an <in predicate>.
+
+ Our reading of Note 184 is reccursive, so that all:
+ - IN (( <subquery> ))
+ - IN ((( <subquery> )))
+ - IN '('^N <subquery> ')'^N
+ - etc
+ should be interpreted as a <table subquery>, no matter how deep in the
+ expression the <subquery> is.
+ */
+
+ Item *result;
+
+ DBUG_ENTER("handle_sql2003_note184_exception");
+
+ if (expr->type() == Item::SUBSELECT_ITEM)
+ {
+ Item_subselect *expr2 = (Item_subselect*) expr;
+
+ if (expr2->substype() == Item_subselect::SINGLEROW_SUBS)
+ {
+ Item_singlerow_subselect *expr3 = (Item_singlerow_subselect*) expr2;
+ st_select_lex *subselect;
+
+ /*
+ Implement the mandated change, by altering the semantic tree:
+ left IN Item_singlerow_subselect(subselect)
+ is modified to
+ left IN (subselect)
+ which is represented as
+ Item_in_subselect(left, subselect)
+ */
+ subselect= expr3->invalidate_and_restore_select_lex();
+ result= new (thd->mem_root) Item_in_subselect(left, subselect);
+
+ if (! equal)
+ result = negate_expression(thd, result);
+
+ DBUG_RETURN(result);
+ }
+ }
+
+ if (equal)
+ result= new (thd->mem_root) Item_func_eq(left, expr);
+ else
+ result= new (thd->mem_root) Item_func_ne(left, expr);
+
+ DBUG_RETURN(result);
+}
+
%}
%union {
int num;
@@ -359,6 +488,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%}
%pure_parser /* We have threads */
+/*
+ Currently there is 287 shift/reduce conflict. We should not introduce
+ new conflicts any more.
+*/
+%expect 287
/*
Comments for TOKENS.
@@ -556,7 +690,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token GLOBAL_SYM /* SQL-2003-R */
%token GRANT /* SQL-2003-R */
%token GRANTS
-%token GROUP /* SQL-2003-R */
+%token GROUP_SYM /* SQL-2003-R */
%token GROUP_CONCAT_SYM
%token GT_SYM /* OPERATOR */
%token HANDLER_SYM
@@ -1067,6 +1201,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
old_or_new_charset_name_or_default
collation_name
collation_name_or_default
+ opt_load_data_charset
%type <variable> internal_variable_name
@@ -1150,7 +1285,7 @@ query:
(!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT)))
{
my_message(ER_EMPTY_QUERY, ER(ER_EMPTY_QUERY), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -1222,12 +1357,12 @@ statement:
deallocate:
deallocate_or_drop PREPARE_SYM ident
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
if (lex->stmt_prepare_mode)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_DEALLOCATE_PREPARE;
lex->prepared_stmt_name= $3;
@@ -1242,12 +1377,12 @@ deallocate_or_drop:
prepare:
PREPARE_SYM ident FROM prepare_src
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
if (lex->stmt_prepare_mode)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_PREPARE;
lex->prepared_stmt_name= $2;
@@ -1256,14 +1391,14 @@ prepare:
prepare_src:
TEXT_STRING_sys
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
lex->prepared_stmt_code= $1;
lex->prepared_stmt_code_is_varref= FALSE;
}
| '@' ident_or_text
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
lex->prepared_stmt_code= $2;
lex->prepared_stmt_code_is_varref= TRUE;
@@ -1272,12 +1407,12 @@ prepare_src:
execute:
EXECUTE_SYM ident
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
if (lex->stmt_prepare_mode)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_EXECUTE;
lex->prepared_stmt_name= $2;
@@ -1301,7 +1436,7 @@ execute_var_ident: '@' ident_or_text
LEX *lex=Lex;
LEX_STRING *lexstr= (LEX_STRING*)sql_memdup(&$2, sizeof(LEX_STRING));
if (!lexstr || lex->prepared_stmt_params.push_back(lexstr))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -1313,7 +1448,7 @@ help:
if (Lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "HELP");
- YYABORT;
+ MYSQL_YYABORT;
}
}
ident_or_text
@@ -1433,14 +1568,14 @@ create:
CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident
{
THD *thd= YYTHD;
- LEX *lex=Lex;
+ LEX *lex= thd->lex;
lex->sql_command= SQLCOM_CREATE_TABLE;
if (!lex->select_lex.add_table_to_list(thd, $5, NULL,
TL_OPTION_UPDATING,
(using_update_log ?
TL_READ_NO_INSERT:
TL_READ)))
- YYABORT;
+ MYSQL_YYABORT;
lex->create_list.empty();
lex->key_list.empty();
lex->col_list.empty();
@@ -1463,7 +1598,7 @@ create:
if (!lex->current_select->add_table_to_list(lex->thd, $7,
NULL,
TL_OPTION_UPDATING))
- YYABORT;
+ MYSQL_YYABORT;
lex->create_list.empty();
lex->key_list.empty();
lex->col_list.empty();
@@ -1474,8 +1609,8 @@ create:
LEX *lex=Lex;
if ($2 != Key::FULLTEXT && lex->key_create_info.parser_name.str)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->key_list.push_back(new Key($2, $4.str, &lex->key_create_info, 0,
lex->col_list));
@@ -1505,7 +1640,7 @@ create:
{
Lex->sql_command = SQLCOM_CREATE_USER;
}
- | CREATE LOGFILE_SYM GROUP logfile_group_info
+ | CREATE LOGFILE_SYM GROUP_SYM logfile_group_info
{
Lex->alter_tablespace_info->ts_cmd_type= CREATE_LOGFILE_GROUP;
}
@@ -1579,7 +1714,7 @@ event_tail:
Lex->create_info.options= $2;
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
- YYABORT;
+ MYSQL_YYABORT;
Lex->event_parse_data->identifier= $3;
/*
@@ -1710,11 +1845,11 @@ ev_sql_stmt:
if (lex->sphead)
{
my_error(ER_EVENT_RECURSIVITY_FORBIDDEN, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
if (!(lex->sphead= new sp_head()))
- YYABORT;
+ MYSQL_YYABORT;
lex->sphead->reset_thd_mem_root(YYTHD);
lex->sphead->init(lex);
@@ -1780,12 +1915,12 @@ sp_name:
if (!$1.str || check_db_name(&$1))
{
my_error(ER_WRONG_DB_NAME, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
if (check_routine_name($3))
{
my_error(ER_SP_WRONG_NAME, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
$$= new sp_name($1, $3);
$$->init_qname(YYTHD);
@@ -1797,10 +1932,10 @@ sp_name:
if (check_routine_name($1))
{
my_error(ER_SP_WRONG_NAME, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
if (thd->copy_db_to(&db.str, &db.length))
- YYABORT;
+ MYSQL_YYABORT;
$$= new sp_name(db, $1);
if ($$)
$$->init_qname(YYTHD);
@@ -1811,7 +1946,7 @@ create_function_tail:
RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
{
THD *thd= YYTHD;
- LEX *lex=Lex;
+ LEX *lex= thd->lex;
if (lex->definer != NULL)
{
/*
@@ -1821,13 +1956,13 @@ create_function_tail:
and is considered a parsing error.
*/
my_error(ER_WRONG_USAGE, MYF(0), "SONAME", "DEFINER");
- YYABORT;
+ MYSQL_YYABORT;
}
if (is_native_function(thd, & lex->spname->m_name))
{
my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0),
lex->spname->m_name.str);
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_CREATE_FUNCTION;
lex->udf.name = lex->spname->m_name;
@@ -1846,13 +1981,13 @@ create_function_tail:
if (lex->udf.type == UDFTYPE_AGGREGATE)
{
my_error(ER_SP_NO_AGGREGATE, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->sphead)
{
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION");
- YYABORT;
+ MYSQL_YYABORT;
}
/* Order is important here: new - reset - init */
sp= new sp_head();
@@ -1898,13 +2033,13 @@ create_function_tail:
&& (lex->type & BINCMP_FLAG))
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "return value collation");
- YYABORT;
+ MYSQL_YYABORT;
}
if (sp->fill_field_definition(YYTHD, lex,
(enum enum_field_types) $8,
&sp->m_return_field_def))
- YYABORT;
+ MYSQL_YYABORT;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
}
@@ -1918,18 +2053,18 @@ create_function_tail:
sp_proc_stmt
{
THD *thd= YYTHD;
- LEX *lex= Lex;
+ LEX *lex= thd->lex;
sp_head *sp= lex->sphead;
if (sp->is_not_allowed_in_function("function"))
- YYABORT;
+ MYSQL_YYABORT;
lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
sp->init_strings(thd, lex);
if (!(sp->m_flags & sp_head::HAS_RETURN))
{
my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
- YYABORT;
+ MYSQL_YYABORT;
}
if (is_native_function(thd, & sp->m_name))
{
@@ -2093,7 +2228,7 @@ sp_fdparam:
if (spc->find_variable(&$1, TRUE))
{
my_error(ER_SP_DUP_PARAM, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
sp_variable_t *spvar= spc->push_variable(&$1,
(enum enum_field_types)$3,
@@ -2103,7 +2238,7 @@ sp_fdparam:
(enum enum_field_types) $3,
&spvar->field_def))
{
- YYABORT;
+ MYSQL_YYABORT;
}
spvar->field_def.field_name= spvar->name.str;
spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
@@ -2130,7 +2265,7 @@ sp_pdparam:
if (spc->find_variable(&$3, TRUE))
{
my_error(ER_SP_DUP_PARAM, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
sp_variable_t *spvar= spc->push_variable(&$3,
(enum enum_field_types)$4,
@@ -2140,7 +2275,7 @@ sp_pdparam:
(enum enum_field_types) $4,
&spvar->field_def))
{
- YYABORT;
+ MYSQL_YYABORT;
}
spvar->field_def.field_name= spvar->name.str;
spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
@@ -2179,13 +2314,13 @@ sp_decls:
{ /* Variable or condition following cursor or handler */
my_message(ER_SP_VARCOND_AFTER_CURSHNDLR,
ER(ER_SP_VARCOND_AFTER_CURSHNDLR), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
if ($2.curs && $1.hndlrs)
{ /* Cursor following handler */
my_message(ER_SP_CURSOR_AFTER_HANDLER,
ER(ER_SP_CURSOR_AFTER_HANDLER), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
$$.vars= $1.vars + $2.vars;
$$.conds= $1.conds + $2.conds;
@@ -2223,7 +2358,7 @@ sp_decl:
sp_variable_t *spvar= pctx->find_variable(var_idx);
if (!spvar)
- YYABORT;
+ MYSQL_YYABORT;
spvar->type= var_type;
spvar->dflt= dflt_value_item;
@@ -2231,7 +2366,7 @@ sp_decl:
if (lex->sphead->fill_field_definition(YYTHD, lex, var_type,
&spvar->field_def))
{
- YYABORT;
+ MYSQL_YYABORT;
}
spvar->field_def.field_name= spvar->name.str;
@@ -2259,7 +2394,7 @@ sp_decl:
if (spc->find_cond(&$2, TRUE))
{
my_error(ER_SP_DUP_COND, MYF(0), $2.str);
- YYABORT;
+ MYSQL_YYABORT;
}
YYTHD->lex->spcont->push_cond(&$2, $5);
$$.vars= $$.hndlrs= $$.curs= 0;
@@ -2317,7 +2452,7 @@ sp_decl:
{
my_error(ER_SP_DUP_CURS, MYF(0), $2.str);
delete $5;
- YYABORT;
+ MYSQL_YYABORT;
}
i= new sp_instr_cpush(sp->instructions(), ctx, $5,
ctx->current_cursor_count());
@@ -2348,13 +2483,13 @@ sp_cursor_stmt:
{
my_message(ER_SP_BAD_CURSOR_QUERY, ER(ER_SP_BAD_CURSOR_QUERY),
MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->result)
{
my_message(ER_SP_BAD_CURSOR_SELECT, ER(ER_SP_BAD_CURSOR_SELECT),
MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sp_lex_in_use= TRUE;
$$= lex;
@@ -2378,7 +2513,7 @@ sp_hcond_list:
if (ctx->find_handler($1))
{
my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2399,7 +2534,7 @@ sp_hcond_list:
if (ctx->find_handler($3))
{
my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2425,7 +2560,7 @@ sp_cond:
if (!sp_cond_check(&$3))
{
my_error(ER_SP_BAD_SQLSTATE, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
$$->type= sp_cond_type_t::state;
@@ -2450,7 +2585,7 @@ sp_hcond:
if ($$ == NULL)
{
my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
}
| SQLWARNING_SYM /* SQLSTATEs 01??? */
@@ -2481,7 +2616,7 @@ sp_decl_idents:
if (spc->find_variable(&$1, TRUE))
{
my_error(ER_SP_DUP_VAR, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
spc->push_variable(&$1, (enum_field_types)0, sp_param_in);
$$= 1;
@@ -2496,7 +2631,7 @@ sp_decl_idents:
if (spc->find_variable(&$3, TRUE))
{
my_error(ER_SP_DUP_VAR, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
spc->push_variable(&$3, (enum_field_types)0, sp_param_in);
$$= $1 + 1;
@@ -2544,7 +2679,7 @@ sp_proc_stmt_statement:
if (lex->sql_command == SQLCOM_CHANGE_DB)
{ /* "USE db" doesn't work in a procedure */
my_error(ER_SP_BADSTATEMENT, MYF(0), "USE");
- YYABORT;
+ MYSQL_YYABORT;
}
/*
Don't add an instruction for SET statements, since all
@@ -2587,7 +2722,7 @@ sp_proc_stmt_return:
if (sp->m_type != TYPE_ENUM_FUNCTION)
{
my_message(ER_SP_BADRETURN, ER(ER_SP_BADRETURN), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2627,7 +2762,7 @@ sp_proc_stmt_leave:
if (! lab)
{
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "LEAVE", $2.str);
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2659,7 +2794,7 @@ sp_proc_stmt_iterate:
if (! lab || lab->type != SP_LAB_ITER)
{
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "ITERATE", $2.str);
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2690,7 +2825,7 @@ sp_proc_stmt_open:
if (! lex->spcont->find_cursor(&$2, &offset))
{
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str);
- YYABORT;
+ MYSQL_YYABORT;
}
i= new sp_instr_copen(sp->instructions(), lex->spcont, offset);
sp->add_instr(i);
@@ -2708,7 +2843,7 @@ sp_proc_stmt_fetch:
if (! lex->spcont->find_cursor(&$3, &offset))
{
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
i= new sp_instr_cfetch(sp->instructions(), lex->spcont, offset);
sp->add_instr(i);
@@ -2728,7 +2863,7 @@ sp_proc_stmt_close:
if (! lex->spcont->find_cursor(&$2, &offset))
{
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str);
- YYABORT;
+ MYSQL_YYABORT;
}
i= new sp_instr_cclose(sp->instructions(), lex->spcont, offset);
sp->add_instr(i);
@@ -2752,7 +2887,7 @@ sp_fetch_list:
if (!spc || !(spv = spc->find_variable(&$1)))
{
my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2773,7 +2908,7 @@ sp_fetch_list:
if (!spc || !(spv = spc->find_variable(&$3)))
{
my_error(ER_SP_UNDECLARED_VAR, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2842,7 +2977,7 @@ simple_case_stmt:
{
LEX *lex= Lex;
if (case_stmt_action_expr(lex, $3))
- YYABORT;
+ MYSQL_YYABORT;
lex->sphead->restore_lex(YYTHD); /* For expr $3 */
}
@@ -2945,7 +3080,7 @@ sp_labeled_control:
if (lab)
{
my_error(ER_SP_LABEL_REDEFINE, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2966,7 +3101,7 @@ sp_labeled_control:
my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
{
my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str);
- YYABORT;
+ MYSQL_YYABORT;
}
}
lex->sphead->backpatch(lex->spcont->pop_label());
@@ -3081,11 +3216,11 @@ trg_event:
ALTER TABLESPACE name CHANGE DATAFILE ...
ALTER TABLESPACE name ADD DATAFILE ...
ALTER TABLESPACE name access_mode
- CREATE LOGFILE GROUP name ...
- ALTER LOGFILE GROUP name ADD UNDOFILE ..
- ALTER LOGFILE GROUP name ADD REDOFILE ..
+ CREATE LOGFILE GROUP_SYM name ...
+ ALTER LOGFILE GROUP_SYM name ADD UNDOFILE ..
+ ALTER LOGFILE GROUP_SYM name ADD REDOFILE ..
DROP TABLESPACE name
- DROP LOGFILE GROUP name
+ DROP LOGFILE GROUP_SYM name
*/
change_tablespace_access:
tablespace_name
@@ -3107,7 +3242,7 @@ tablespace_info:
opt_logfile_group_name:
/* empty */ {}
- | USE_SYM LOGFILE_SYM GROUP ident
+ | USE_SYM LOGFILE_SYM GROUP_SYM ident
{
LEX *lex= Lex;
lex->alter_tablespace_info->logfile_group_name= $4.str;
@@ -3347,7 +3482,7 @@ opt_ts_nodegroup:
if (lex->alter_tablespace_info->nodegroup_id != UNDEF_NODEGROUP)
{
my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NODEGROUP");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->alter_tablespace_info->nodegroup_id= $3;
};
@@ -3359,7 +3494,7 @@ opt_ts_comment:
if (lex->alter_tablespace_info->ts_comment != NULL)
{
my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"COMMENT");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->alter_tablespace_info->ts_comment= $3.str;
};
@@ -3372,7 +3507,7 @@ opt_ts_engine:
{
my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),
"STORAGE ENGINE");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->alter_tablespace_info->storage_engine= $4;
};
@@ -3394,7 +3529,7 @@ ts_wait:
if (!(lex->alter_tablespace_info->wait_until_completed))
{
my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NO_WAIT");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->alter_tablespace_info->wait_until_completed= FALSE;
};
@@ -3428,20 +3563,20 @@ size_number:
default:
{
my_error(ER_WRONG_SIZE_NUMBER, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
if (prefix_number >> 31)
{
my_error(ER_SIZE_OVERFLOW_ERROR, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
number= prefix_number << text_shift_number;
}
else
{
my_error(ER_WRONG_SIZE_NUMBER, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
$$= number;
}
@@ -3458,26 +3593,26 @@ create2:
create3 {}
| LIKE table_ident
{
- LEX *lex=Lex;
- THD *thd= lex->thd;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
if (!(lex->like_name= $2))
- YYABORT;
+ MYSQL_YYABORT;
if ($2->db.str == NULL &&
thd->copy_db_to(&($2->db.str), &($2->db.length)))
{
- YYABORT;
+ MYSQL_YYABORT;
}
}
| '(' LIKE table_ident ')'
{
- LEX *lex=Lex;
- THD *thd= lex->thd;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
if (!(lex->like_name= $3))
- YYABORT;
+ MYSQL_YYABORT;
if ($3->db.str == NULL &&
thd->copy_db_to(&($3->db.str), &($3->db.length)))
{
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -3537,7 +3672,7 @@ partitioning:
if (!lex->part_info)
{
mem_alloc_error(sizeof(partition_info));
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->sql_command == SQLCOM_ALTER_TABLE)
{
@@ -3546,7 +3681,7 @@ partitioning:
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
"partitioning", "--with-partition");
- YYABORT;
+ MYSQL_YYABORT;
#endif
}
@@ -3559,8 +3694,8 @@ partition_entry:
LEX *lex= Lex;
if (!lex->part_info)
{
- yyerror(ER(ER_PARTITION_ENTRY_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_ENTRY_ERROR));
+ MYSQL_YYABORT;
}
/*
We enter here when opening the frm file to translate
@@ -3614,7 +3749,7 @@ part_field_item:
if (Lex->part_info->part_field_list.push_back($1.str))
{
mem_alloc_error(1);
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -3653,7 +3788,7 @@ opt_no_parts:
if (no_parts == 0)
{
my_error(ER_NO_PARTS_ERROR, MYF(0), "partitions");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->part_info->no_parts= no_parts;
@@ -3687,7 +3822,7 @@ sub_part_field_item:
if (Lex->part_info->subpart_field_list.push_back($1.str))
{
mem_alloc_error(1);
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -3701,8 +3836,8 @@ part_func_expr:
lex->safe_to_cache_query= 1;
if (not_corr_func)
{
- yyerror(ER(ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR));
+ MYSQL_YYABORT;
}
$$=$1;
}
@@ -3717,7 +3852,7 @@ opt_no_subparts:
if (no_parts == 0)
{
my_error(ER_NO_PARTS_ERROR, MYF(0), "subpartitions");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->part_info->no_subparts= no_parts;
lex->part_info->use_default_no_subpartitions= FALSE;
@@ -3737,8 +3872,8 @@ part_defs:
if (part_info->no_parts !=
count_curr_parts)
{
- yyerror(ER(ER_PARTITION_WRONG_NO_PART_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_WRONG_NO_PART_ERROR));
+ MYSQL_YYABORT;
}
}
else if (count_curr_parts > 0)
@@ -3760,12 +3895,11 @@ part_definition:
LEX *lex= Lex;
partition_info *part_info= lex->part_info;
partition_element *p_elem= new partition_element();
- uint part_id= part_info->partitions.elements;
if (!p_elem || part_info->partitions.push_back(p_elem))
{
mem_alloc_error(sizeof(partition_element));
- YYABORT;
+ MYSQL_YYABORT;
}
p_elem->part_state= PART_NORMAL;
part_info->curr_part_elem= p_elem;
@@ -3799,13 +3933,13 @@ opt_part_values:
{
my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
"RANGE", "LESS THAN");
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->part_info->part_type == LIST_PARTITION)
{
my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
"LIST", "IN");
- YYABORT;
+ MYSQL_YYABORT;
}
}
else
@@ -3820,7 +3954,7 @@ opt_part_values:
{
my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
"RANGE", "LESS THAN");
- YYABORT;
+ MYSQL_YYABORT;
}
}
else
@@ -3835,7 +3969,7 @@ opt_part_values:
{
my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
"LIST", "IN");
- YYABORT;
+ MYSQL_YYABORT;
}
}
else
@@ -3849,8 +3983,8 @@ part_func_max:
LEX *lex= Lex;
if (lex->part_info->defined_max_value)
{
- yyerror(ER(ER_PARTITION_MAXVALUE_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR));
+ MYSQL_YYABORT;
}
lex->part_info->defined_max_value= TRUE;
lex->part_info->curr_part_elem->max_value= TRUE;
@@ -3860,13 +3994,13 @@ part_func_max:
{
if (Lex->part_info->defined_max_value)
{
- yyerror(ER(ER_PARTITION_MAXVALUE_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR));
+ MYSQL_YYABORT;
}
if (Lex->part_info->curr_part_elem->has_null_value)
{
- yyerror(ER(ER_NULL_IN_VALUES_LESS_THAN));
- YYABORT;
+ my_parse_error(ER(ER_NULL_IN_VALUES_LESS_THAN));
+ MYSQL_YYABORT;
}
}
;
@@ -3903,7 +4037,7 @@ part_list_item:
list_val_list.push_back(value_ptr))
{
mem_alloc_error(sizeof(part_elem_value));
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -3912,9 +4046,8 @@ part_bit_expr:
bit_expr
{
Item *part_expr= $1;
- int part_expression_ok= 1;
- LEX *lex= Lex;
THD *thd= YYTHD;
+ LEX *lex= thd->lex;
Name_resolution_context *context= &lex->current_select->context;
TABLE_LIST *save_list= context->table_list;
const char *save_where= thd->where;
@@ -3927,13 +4060,13 @@ part_bit_expr:
if (!value_ptr)
{
mem_alloc_error(sizeof(part_elem_value));
- YYABORT;
+ MYSQL_YYABORT;
}
if (part_expr->walk(&Item::check_partition_func_processor, 0,
NULL))
{
my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
if (part_expr->fix_fields(YYTHD, (Item**)0) ||
((context->table_list= save_list), FALSE) ||
@@ -3941,7 +4074,7 @@ part_bit_expr:
(!lex->safe_to_cache_query))
{
my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
thd->where= save_where;
value_ptr->value= part_expr->val_int();
@@ -3954,15 +4087,15 @@ part_bit_expr:
if (Lex->part_info->curr_part_elem->has_null_value)
{
my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
Lex->part_info->curr_part_elem->has_null_value= TRUE;
}
else if (part_expr->result_type() != INT_RESULT &&
!part_expr->null_value)
{
- yyerror(ER(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR));
+ MYSQL_YYABORT;
}
$$= value_ptr;
}
@@ -3974,8 +4107,8 @@ opt_sub_partition:
if (Lex->part_info->no_subparts != 0 &&
!Lex->part_info->use_default_subpartitions)
{
- yyerror(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
+ MYSQL_YYABORT;
}
}
| '(' sub_part_list ')'
@@ -3987,16 +4120,16 @@ opt_sub_partition:
if (part_info->no_subparts !=
part_info->count_curr_subparts)
{
- yyerror(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
+ MYSQL_YYABORT;
}
}
else if (part_info->count_curr_subparts > 0)
{
if (part_info->partitions.elements > 1)
{
- yyerror(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
+ MYSQL_YYABORT;
}
part_info->no_subparts= part_info->count_curr_subparts;
}
@@ -4020,7 +4153,7 @@ sub_part_definition:
curr_part->subpartitions.push_back(sub_p_elem))
{
mem_alloc_error(sizeof(partition_element));
- YYABORT;
+ MYSQL_YYABORT;
}
part_info->curr_part_elem= sub_p_elem;
part_info->use_default_subpartitions= FALSE;
@@ -4172,8 +4305,8 @@ create_table_option:
Lex->create_info.table_options|= HA_OPTION_PACK_KEYS;
break;
default:
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;
}
@@ -4228,7 +4361,7 @@ default_charset:
my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
"CHARACTER SET ", cinfo->default_table_charset->csname,
"CHARACTER SET ", $4->csname);
- YYABORT;
+ MYSQL_YYABORT;
}
Lex->create_info.default_table_charset= $4;
Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
@@ -4244,7 +4377,7 @@ default_collation:
{
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
$4->name, cinfo->default_table_charset->csname);
- YYABORT;
+ MYSQL_YYABORT;
}
Lex->create_info.default_table_charset= $4;
Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
@@ -4257,7 +4390,7 @@ known_storage_engines:
if ($$ == NULL)
{
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -4271,7 +4404,7 @@ storage_engines:
if (YYTHD->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION)
{
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_WARN,
@@ -4331,8 +4464,8 @@ key_def:
LEX *lex=Lex;
if ($1 != Key::FULLTEXT && lex->key_create_info.parser_name.str)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->key_list.push_back(new Key($1,$2, &lex->key_create_info, 0,
lex->col_list));
@@ -4411,7 +4544,7 @@ field_spec:
&lex->comment,
lex->change,&lex->interval_list,lex->charset,
lex->uint_geom_type))
- YYABORT;
+ MYSQL_YYABORT;
};
type:
@@ -4480,7 +4613,7 @@ type:
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
sym_group_geom.name, sym_group_geom.needed_define);
- YYABORT;
+ MYSQL_YYABORT;
#endif
}
| MEDIUMBLOB { Lex->charset=&my_charset_bin;
@@ -4641,7 +4774,7 @@ attribute:
{
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
$2->name,Lex->charset->csname);
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -4666,7 +4799,7 @@ charset_name:
if (!($$=get_charset_by_csname($1.str,MY_CS_PRIMARY,MYF(0))))
{
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
}
| BINARY { $$= &my_charset_bin; }
@@ -4676,6 +4809,10 @@ charset_name_or_default:
charset_name { $$=$1; }
| DEFAULT { $$=NULL; } ;
+opt_load_data_charset:
+ /* Empty */ { $$= NULL; }
+ | charset charset_name_or_default { $$= $2; }
+ ;
old_or_new_charset_name:
ident_or_text
@@ -4684,7 +4821,7 @@ old_or_new_charset_name:
!($$=get_old_charset_by_name($1.str)))
{
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
}
| BINARY { $$= &my_charset_bin; }
@@ -4700,7 +4837,7 @@ collation_name:
if (!($$=get_charset_by_name($1.str,MYF(0))))
{
my_error(ER_UNKNOWN_COLLATION, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
};
@@ -4727,7 +4864,7 @@ opt_binary:
MY_CS_PRIMARY,MYF(0))))
{
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2");
- YYABORT;
+ MYSQL_YYABORT;
}
}
| charset charset_name opt_bin_mod { Lex->charset=$2; }
@@ -4746,7 +4883,7 @@ opt_bin_charset:
MY_CS_PRIMARY,MYF(0))))
{
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2");
- YYABORT;
+ MYSQL_YYABORT;
}
}
| charset charset_name { Lex->charset=$2; } ;
@@ -4809,7 +4946,7 @@ key_type:
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
sym_group_geom.name, sym_group_geom.needed_define);
- YYABORT;
+ MYSQL_YYABORT;
#endif
};
@@ -4842,7 +4979,7 @@ opt_unique_or_fulltext:
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
sym_group_geom.name, sym_group_geom.needed_define);
- YYABORT;
+ MYSQL_YYABORT;
#endif
}
;
@@ -4890,7 +5027,7 @@ key_opt:
else
{
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -4947,7 +5084,7 @@ alter:
lex->duplicates= DUP_ERROR;
if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
TL_OPTION_UPDATING))
- YYABORT;
+ MYSQL_YYABORT;
lex->create_list.empty();
lex->key_list.empty();
lex->col_list.empty();
@@ -4973,13 +5110,13 @@ alter:
}
opt_create_database_options
{
- LEX *lex=Lex;
- THD *thd= Lex->thd;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
lex->sql_command=SQLCOM_ALTER_DB;
lex->name= $3;
if (lex->name.str == NULL &&
thd->copy_db_to(&lex->name.str, &lex->name.length))
- YYABORT;
+ MYSQL_YYABORT;
}
| ALTER PROCEDURE sp_name
{
@@ -4988,7 +5125,7 @@ alter:
if (lex->sphead)
{
my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
- YYABORT;
+ MYSQL_YYABORT;
}
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
}
@@ -5006,7 +5143,7 @@ alter:
if (lex->sphead)
{
my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
- YYABORT;
+ MYSQL_YYABORT;
}
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
}
@@ -5029,7 +5166,7 @@ alter:
}
view_list_opt AS view_select view_check_option
{}
- | ALTER EVENT_SYM sp_name
+ | ALTER definer EVENT_SYM sp_name
/*
BE CAREFUL when you add a new rule to update the block where
YYTHD->client_capabilities is set back to original value
@@ -5044,8 +5181,8 @@ alter:
*/
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
- YYABORT;
- Lex->event_parse_data->identifier= $3;
+ MYSQL_YYABORT;
+ Lex->event_parse_data->identifier= $4;
/*
We have to turn off CLIENT_MULTI_QUERIES while parsing a
@@ -5065,16 +5202,17 @@ alter:
{
/*
$1 - ALTER
- $2 - EVENT_SYM
- $3 - sp_name
- $4 - the block above
+ $2 - definer
+ $3 - EVENT_SYM
+ $4 - sp_name
+ $5 - the block above
*/
- YYTHD->client_capabilities |= $<ulong_num>4;
+ YYTHD->client_capabilities |= $<ulong_num>5;
- if (!($5 || $6 || $7 || $8 || $9))
+ if (!($6 || $7 || $8 || $9 || $10))
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
/*
sql_command is set here because some rules in ev_sql_stmt
@@ -5087,7 +5225,7 @@ alter:
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= ALTER_TABLESPACE;
}
- | ALTER LOGFILE_SYM GROUP alter_logfile_group_info
+ | ALTER LOGFILE_SYM GROUP_SYM alter_logfile_group_info
{
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= ALTER_LOGFILE_GROUP;
@@ -5105,9 +5243,9 @@ alter:
| ALTER SERVER_SYM ident_or_text OPTIONS_SYM '(' server_options_list ')'
{
LEX *lex= Lex;
- Lex->sql_command= SQLCOM_ALTER_SERVER;
- Lex->server_options.server_name= $3.str;
- Lex->server_options.server_name_length= $3.length;
+ lex->sql_command= SQLCOM_ALTER_SERVER;
+ lex->server_options.server_name= $3.str;
+ lex->server_options.server_name_length= $3.length;
}
;
@@ -5233,7 +5371,7 @@ add_partition_rule:
if (!lex->part_info)
{
mem_alloc_error(sizeof(partition_info));
- YYABORT;
+ MYSQL_YYABORT;
}
lex->alter_info.flags|= ALTER_ADD_PARTITION;
lex->no_write_to_binlog= $3;
@@ -5263,7 +5401,7 @@ reorg_partition_rule:
if (!lex->part_info)
{
mem_alloc_error(sizeof(partition_info));
- YYABORT;
+ MYSQL_YYABORT;
}
lex->no_write_to_binlog= $3;
}
@@ -5298,7 +5436,7 @@ alt_part_name_item:
if (Lex->alter_info.partition_names.push_back($1.str))
{
mem_alloc_error(1);
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -5356,7 +5494,7 @@ alter_list_item:
&lex->comment,
$3.str, &lex->interval_list, lex->charset,
lex->uint_geom_type))
- YYABORT;
+ MYSQL_YYABORT;
}
opt_place
| DROP opt_column field_ident opt_restrict
@@ -5411,20 +5549,20 @@ alter_list_item:
}
| RENAME opt_to table_ident
{
- LEX *lex=Lex;
- THD *thd= lex->thd;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
uint dummy;
lex->select_lex.db=$3->db.str;
if (lex->select_lex.db == NULL &&
thd->copy_db_to(&lex->select_lex.db, &dummy))
{
- YYABORT;
+ MYSQL_YYABORT;
}
if (check_table_name($3->table.str,$3->table.length) ||
$3->db.str && check_db_name(&$3->db))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), $3->table.str);
- YYABORT;
+ MYSQL_YYABORT;
}
lex->name= $3->table;
lex->alter_info.flags|= ALTER_RENAME;
@@ -5441,7 +5579,7 @@ alter_list_item:
{
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
$5->name, $4->csname);
- YYABORT;
+ MYSQL_YYABORT;
}
LEX *lex= Lex;
lex->create_info.table_charset=
@@ -5579,7 +5717,7 @@ slave_until:
{
my_message(ER_BAD_SLAVE_UNTIL_COND,
ER(ER_BAD_SLAVE_UNTIL_COND), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
@@ -5683,7 +5821,7 @@ check:
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "CHECK");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_CHECK;
lex->check_opt.init();
@@ -5750,12 +5888,12 @@ rename_list:
user TO_SYM user
{
if (Lex->users_list.push_back($1) || Lex->users_list.push_back($3))
- YYABORT;
+ MYSQL_YYABORT;
}
| rename_list ',' user TO_SYM user
{
if (Lex->users_list.push_back($3) || Lex->users_list.push_back($5))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -5772,18 +5910,18 @@ table_to_table:
TL_IGNORE) ||
!sl->add_table_to_list(lex->thd, $3,NULL,TL_OPTION_UPDATING,
TL_IGNORE))
- YYABORT;
+ MYSQL_YYABORT;
};
db_to_db:
ident TO_SYM ident
{
LEX *lex=Lex;
- if (Lex->db_list.push_back((LEX_STRING*)
+ if (lex->db_list.push_back((LEX_STRING*)
sql_memdup(&$1, sizeof(LEX_STRING))) ||
- Lex->db_list.push_back((LEX_STRING*)
+ lex->db_list.push_back((LEX_STRING*)
sql_memdup(&$3, sizeof(LEX_STRING))))
- YYABORT;
+ MYSQL_YYABORT;
};
keycache:
@@ -5808,7 +5946,7 @@ assign_to_keycache:
TL_READ,
sel->get_use_index(),
(List<String> *)0))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -5840,7 +5978,7 @@ preload_keys:
TL_READ,
sel->get_use_index(),
(List<String> *)0))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -5895,16 +6033,16 @@ select_paren:
SELECT_LEX * sel= lex->current_select;
if (sel->set_braces(1))
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
if (sel->linkage == UNION_TYPE &&
!sel->master_unit()->first_select()->braces &&
sel->master_unit()->first_select()->linkage ==
UNION_TYPE)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
/* select in braces, can't contain global parameters */
if (sel->master_unit()->fake_select_lex)
@@ -5920,14 +6058,14 @@ select_init2:
SELECT_LEX * sel= lex->current_select;
if (lex->current_select->set_braces(0))
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
if (sel->linkage == UNION_TYPE &&
sel->master_unit()->first_select()->braces)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
}
union_clause
@@ -5955,8 +6093,13 @@ select_into:
| select_from into;
select_from:
- FROM join_table_list where_clause group_clause having_clause
+ FROM join_table_list where_clause group_clause having_clause
opt_order_clause opt_limit_clause procedure_clause
+ {
+ Select->context.table_list=
+ Select->context.first_name_resolution_table=
+ (TABLE_LIST *) Select->table_list.first;
+ }
| FROM DUAL_SYM where_clause opt_limit_clause
/* oracle compatibility: oracle always requires FROM clause,
and DUAL is system table without fields.
@@ -5971,7 +6114,7 @@ select_options:
if (Select->options & SELECT_DISTINCT && Select->options & SELECT_ALL)
{
my_error(ER_WRONG_USAGE, MYF(0), "ALL", "DISTINCT");
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -5985,7 +6128,7 @@ select_option:
| HIGH_PRIORITY
{
if (check_simple_select())
- YYABORT;
+ MYSQL_YYABORT;
Lex->lock_option= TL_READ_HIGH_PRIORITY;
}
| DISTINCT { Select->options|= SELECT_DISTINCT; }
@@ -5994,13 +6137,13 @@ select_option:
| SQL_BUFFER_RESULT
{
if (check_simple_select())
- YYABORT;
+ MYSQL_YYABORT;
Select->options|= OPTION_BUFFER_RESULT;
}
| SQL_CALC_FOUND_ROWS
{
if (check_simple_select())
- YYABORT;
+ MYSQL_YYABORT;
Select->options|= OPTION_FOUND_ROWS;
}
| SQL_NO_CACHE_SYM
@@ -6049,7 +6192,7 @@ select_item_list:
new Item_field(&thd->lex->current_select->
context,
NULL, NULL, "*")))
- YYABORT;
+ MYSQL_YYABORT;
(thd->lex->current_select->with_wild)++;
};
@@ -6058,7 +6201,7 @@ select_item:
remember_name select_item2 remember_end select_alias
{
if (add_item_to_list(YYTHD, $2))
- YYABORT;
+ MYSQL_YYABORT;
if ($4.str)
{
$2->is_autogenerated_name= FALSE;
@@ -6149,13 +6292,18 @@ bool_factor:
| bool_test ;
bool_test:
- bool_pri IS TRUE_SYM { $$= is_truth_value(YYTHD, $1,1,0); }
- | bool_pri IS not TRUE_SYM { $$= is_truth_value(YYTHD, $1,0,0); }
- | bool_pri IS FALSE_SYM { $$= is_truth_value(YYTHD, $1,0,1); }
- | bool_pri IS not FALSE_SYM { $$= is_truth_value(YYTHD, $1,1,1); }
- | bool_pri IS UNKNOWN_SYM { $$= new Item_func_isnull($1); }
- | bool_pri IS not UNKNOWN_SYM { $$= new Item_func_isnotnull($1); }
- | bool_pri ;
+ bool_pri IS TRUE_SYM
+ { $$= new (YYTHD->mem_root) Item_func_istrue($1); }
+ | bool_pri IS not TRUE_SYM
+ { $$= new (YYTHD->mem_root) Item_func_isnottrue($1); }
+ | bool_pri IS FALSE_SYM
+ { $$= new (YYTHD->mem_root) Item_func_isfalse($1); }
+ | bool_pri IS not FALSE_SYM
+ { $$= new (YYTHD->mem_root) Item_func_isnotfalse($1); }
+ | bool_pri IS UNKNOWN_SYM { $$= new Item_func_isnull($1); }
+ | bool_pri IS not UNKNOWN_SYM { $$= new Item_func_isnotnull($1); }
+ | bool_pri
+ ;
bool_pri:
bool_pri IS NULL_SYM { $$= new Item_func_isnull($1); }
@@ -6168,31 +6316,37 @@ bool_pri:
| predicate ;
predicate:
- bit_expr IN_SYM '(' subselect ')'
- { $$= new Item_in_subselect($1, $4); }
- | bit_expr not IN_SYM '(' subselect ')'
- { $$= negate_expression(YYTHD, new Item_in_subselect($1, $5)); }
+ bit_expr IN_SYM '(' subselect ')'
+ {
+ $$= new (YYTHD->mem_root) Item_in_subselect($1, $4);
+ }
+ | bit_expr not IN_SYM '(' subselect ')'
+ {
+ THD *thd= YYTHD;
+ Item *item= new (thd->mem_root) Item_in_subselect($1, $5);
+ $$= negate_expression(thd, item);
+ }
| bit_expr IN_SYM '(' expr ')'
{
- $$= new Item_func_eq($1, $4);
+ $$= handle_sql2003_note184_exception(YYTHD, $1, true, $4);
}
- | bit_expr IN_SYM '(' expr ',' expr_list ')'
- {
- $6->push_front($4);
- $6->push_front($1);
- $$= new Item_func_in(*$6);
+ | bit_expr IN_SYM '(' expr ',' expr_list ')'
+ {
+ $6->push_front($4);
+ $6->push_front($1);
+ $$= new (YYTHD->mem_root) Item_func_in(*$6);
}
| bit_expr not IN_SYM '(' expr ')'
{
- $$= new Item_func_ne($1, $5);
+ $$= handle_sql2003_note184_exception(YYTHD, $1, false, $5);
}
- | bit_expr not IN_SYM '(' expr ',' expr_list ')'
+ | bit_expr not IN_SYM '(' expr ',' expr_list ')'
{
- $7->push_front($5);
- $7->push_front($1);
- Item_func_in *item = new Item_func_in(*$7);
- item->negate();
- $$= item;
+ $7->push_front($5);
+ $7->push_front($1);
+ Item_func_in *item = new (YYTHD->mem_root) Item_func_in(*$7);
+ item->negate();
+ $$= item;
}
| bit_expr BETWEEN_SYM bit_expr AND_SYM predicate
{ $$= new Item_func_between($1,$3,$5); }
@@ -6338,7 +6492,7 @@ simple_expr:
lex->dec ? atoi(lex->dec) : 0,
lex->charset);
if (!$$)
- YYABORT;
+ MYSQL_YYABORT;
}
| CASE_SYM opt_expr when_list opt_else END
{ $$= new (YYTHD->mem_root) Item_func_case(* $3, $2, $4 ); }
@@ -6349,7 +6503,7 @@ simple_expr:
Lex->dec ? atoi(Lex->dec) : 0,
Lex->charset);
if (!$$)
- YYABORT;
+ MYSQL_YYABORT;
}
| CONVERT_SYM '(' expr USING charset_name ')'
{ $$= new (YYTHD->mem_root) Item_func_conv_charset($3,$5); }
@@ -6360,7 +6514,7 @@ simple_expr:
Item_splocal *il= static_cast<Item_splocal *>($3);
my_error(ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str);
- YYABORT;
+ MYSQL_YYABORT;
}
$$= new (YYTHD->mem_root) Item_default_value(Lex->current_context(),
$3);
@@ -6375,8 +6529,8 @@ simple_expr:
{
if ($1->type() != Item::ROW_ITEM)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
$$= new (YYTHD->mem_root) Item_func_interval((Item_row *)$1);
}
@@ -6617,7 +6771,7 @@ function_call_conflict:
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
sym_group_geom.name, sym_group_geom.needed_define);
- YYABORT;
+ MYSQL_YYABORT;
#endif
}
;
@@ -6696,8 +6850,8 @@ function_call_generic:
{
if (lex->current_select->inc_in_sum_expr())
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
}
/* Temporary placing the result of find_udf in $3 */
@@ -6707,7 +6861,6 @@ function_call_generic:
udf_expr_list ')'
{
THD *thd= YYTHD;
- LEX *lex= Lex;
Create_func *builder;
Item *item= NULL;
@@ -6730,7 +6883,6 @@ function_call_generic:
#ifdef HAVE_DLOPEN
/* Retrieving the result of find_udf */
udf_func *udf= $<udf>3;
- LEX *lex= Lex;
if (udf)
{
@@ -6752,7 +6904,7 @@ function_call_generic:
if (! ($$= item))
{
- YYABORT;
+ MYSQL_YYABORT;
}
}
| ident '.' ident '(' opt_expr_list ')'
@@ -6781,7 +6933,7 @@ function_call_generic:
if (! ($$= item))
{
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -6910,7 +7062,7 @@ variable:
if (! Lex->parsing_options.allows_variable)
{
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
variable_aux
@@ -6936,11 +7088,11 @@ variable_aux:
{
if ($3.str && $4.str && check_reserved_words(&$3))
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
if (!($$= get_system_var(YYTHD, $2, $3, $4)))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -6974,8 +7126,8 @@ in_sum_expr:
LEX *lex= Lex;
if (lex->current_select->inc_in_sum_expr())
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
}
expr
@@ -7055,12 +7207,12 @@ table_ref:
{
LEX *lex= Lex;
if (!($$= lex->current_select->nest_last_join(lex->thd)))
- YYABORT;
+ MYSQL_YYABORT;
}
;
join_table_list:
- derived_table_list { YYERROR_UNLESS($$=$1); }
+ derived_table_list { MYSQL_YYABORT_UNLESS($$=$1); }
;
/* Warning - may return NULL in case of incomplete SELECT */
@@ -7068,7 +7220,7 @@ derived_table_list:
table_ref { $$=$1; }
| derived_table_list ',' table_ref
{
- YYERROR_UNLESS($1 && ($$=$3));
+ MYSQL_YYABORT_UNLESS($1 && ($$=$3));
}
;
@@ -7087,16 +7239,16 @@ join_table:
left-associative joins.
*/
table_ref %prec TABLE_REF_PRIORITY normal_join table_ref
- { YYERROR_UNLESS($1 && ($$=$3)); }
+ { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); }
| table_ref STRAIGHT_JOIN table_factor
- { YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; }
+ { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=1; }
| table_ref normal_join table_ref
ON
{
- YYERROR_UNLESS($1 && $3);
+ MYSQL_YYABORT_UNLESS($1 && $3);
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $1, $3))
- YYABORT;
+ MYSQL_YYABORT;
Select->parsing_place= IN_ON;
}
expr
@@ -7108,10 +7260,10 @@ join_table:
| table_ref STRAIGHT_JOIN table_factor
ON
{
- YYERROR_UNLESS($1 && $3);
+ MYSQL_YYABORT_UNLESS($1 && $3);
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $1, $3))
- YYABORT;
+ MYSQL_YYABORT;
Select->parsing_place= IN_ON;
}
expr
@@ -7124,25 +7276,24 @@ join_table:
| table_ref normal_join table_ref
USING
{
- SELECT_LEX *sel= Select;
- YYERROR_UNLESS($1 && $3);
+ MYSQL_YYABORT_UNLESS($1 && $3);
}
'(' using_list ')'
- { add_join_natural($1,$3,$7); $$=$3; }
+ { add_join_natural($1,$3,$7,Select); $$=$3; }
| table_ref NATURAL JOIN_SYM table_factor
{
- YYERROR_UNLESS($1 && ($$=$4));
- add_join_natural($1,$4,NULL);
+ MYSQL_YYABORT_UNLESS($1 && ($$=$4));
+ add_join_natural($1,$4,NULL,Select);
}
/* LEFT JOIN variants */
| table_ref LEFT opt_outer JOIN_SYM table_ref
ON
{
- YYERROR_UNLESS($1 && $5);
+ MYSQL_YYABORT_UNLESS($1 && $5);
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $1, $5))
- YYABORT;
+ MYSQL_YYABORT;
Select->parsing_place= IN_ON;
}
expr
@@ -7155,15 +7306,18 @@ join_table:
}
| table_ref LEFT opt_outer JOIN_SYM table_factor
{
- SELECT_LEX *sel= Select;
- YYERROR_UNLESS($1 && $5);
+ MYSQL_YYABORT_UNLESS($1 && $5);
}
USING '(' using_list ')'
- { add_join_natural($1,$5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
+ {
+ add_join_natural($1,$5,$9,Select);
+ $5->outer_join|=JOIN_TYPE_LEFT;
+ $$=$5;
+ }
| table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
{
- YYERROR_UNLESS($1 && $6);
- add_join_natural($1,$6,NULL);
+ MYSQL_YYABORT_UNLESS($1 && $6);
+ add_join_natural($1,$6,NULL,Select);
$6->outer_join|=JOIN_TYPE_LEFT;
$$=$6;
}
@@ -7172,40 +7326,39 @@ join_table:
| table_ref RIGHT opt_outer JOIN_SYM table_ref
ON
{
- YYERROR_UNLESS($1 && $5);
+ MYSQL_YYABORT_UNLESS($1 && $5);
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $1, $5))
- YYABORT;
+ MYSQL_YYABORT;
Select->parsing_place= IN_ON;
}
expr
{
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
- YYABORT;
+ MYSQL_YYABORT;
add_join_on($$, $8);
Lex->pop_context();
Select->parsing_place= NO_MATTER;
}
| table_ref RIGHT opt_outer JOIN_SYM table_factor
{
- SELECT_LEX *sel= Select;
- YYERROR_UNLESS($1 && $5);
+ MYSQL_YYABORT_UNLESS($1 && $5);
}
USING '(' using_list ')'
{
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
- YYABORT;
- add_join_natural($$,$5,$9);
+ MYSQL_YYABORT;
+ add_join_natural($$,$5,$9,Select);
}
| table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
{
- YYERROR_UNLESS($1 && $6);
- add_join_natural($6,$1,NULL);
+ MYSQL_YYABORT_UNLESS($1 && $6);
+ add_join_natural($6,$1,NULL,Select);
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
- YYABORT;
+ MYSQL_YYABORT;
};
normal_join:
@@ -7230,7 +7383,7 @@ table_factor:
lex->lock_option,
sel->get_use_index(),
sel->get_ignore_index())))
- YYABORT;
+ MYSQL_YYABORT;
sel->add_joined_table($$);
}
| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref
@@ -7238,19 +7391,19 @@ table_factor:
{
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $3, $7))
- YYABORT;
+ MYSQL_YYABORT;
}
expr '}'
{
LEX *lex= Lex;
- YYERROR_UNLESS($3 && $7);
+ MYSQL_YYABORT_UNLESS($3 && $7);
add_join_on($7,$10);
Lex->pop_context();
$7->outer_join|=JOIN_TYPE_LEFT;
$$=$7;
if (!($$= lex->current_select->nest_last_join(lex->thd)))
- YYABORT;
+ MYSQL_YYABORT;
}
| select_derived_init get_select_lex select_derived2
{
@@ -7260,8 +7413,8 @@ table_factor:
{
if (sel->set_braces(1))
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
/* select in braces, can't contain global parameters */
if (sel->master_unit()->fake_select_lex)
@@ -7269,7 +7422,7 @@ table_factor:
sel->master_unit()->fake_select_lex;
}
if ($2->init_nested_join(lex->thd))
- YYABORT;
+ MYSQL_YYABORT;
$$= 0;
/* incomplete derived tables return NULL, we must be
nested in select_derived rule to be here. */
@@ -7303,7 +7456,7 @@ table_factor:
TL_READ,(List<String> *)0,
(List<String> *)0)))
- YYABORT;
+ MYSQL_YYABORT;
sel->add_joined_table($$);
lex->pop_context();
}
@@ -7311,8 +7464,8 @@ table_factor:
if ($4 || $6)
{
/* simple nested joins cannot have aliases or unions */
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
else
$$= $3;
@@ -7325,7 +7478,7 @@ select_derived:
{
LEX *lex= Lex;
if ($1->init_nested_join(lex->thd))
- YYABORT;
+ MYSQL_YYABORT;
}
derived_table_list
{
@@ -7334,11 +7487,11 @@ select_derived:
for derived tables, both must equal NULL */
if (!($$= $1->end_nested_join(lex->thd)) && $3)
- YYABORT;
+ MYSQL_YYABORT;
if (!$3 && $$)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
}
;
@@ -7349,12 +7502,12 @@ select_derived2:
lex->derived_tables|= DERIVED_SUBQUERY;
if (!lex->expr_allows_subselect)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE ||
mysql_new_select(lex, 1))
- YYABORT;
+ MYSQL_YYABORT;
mysql_init_select(lex);
lex->current_select->linkage= DERIVED_TABLE_TYPE;
lex->current_select->parsing_place= SELECT_LIST;
@@ -7378,7 +7531,7 @@ select_derived_init:
if (! lex->parsing_options.allows_derived)
{
my_error(ER_VIEW_SELECT_DERIVED, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
SELECT_LEX *sel= lex->current_select;
@@ -7386,8 +7539,8 @@ select_derived_init:
if (!sel->embedding || sel->end_nested_join(lex->thd))
{
/* we are not in parentheses */
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
embedding= Select->embedding;
$$= embedding &&
@@ -7451,7 +7604,7 @@ using_list:
ident
{
if (!($$= new List<String>))
- YYABORT;
+ MYSQL_YYABORT;
$$->push_back(new (YYTHD->mem_root)
String((const char *) $1.str, $1.length,
system_charset_info));
@@ -7567,13 +7720,13 @@ opt_escape:
group_clause:
/* empty */
- | GROUP BY group_list olap_opt;
+ | GROUP_SYM BY group_list olap_opt;
group_list:
group_list ',' order_ident order_dir
- { if (add_group_to_list(YYTHD, $3,(bool) $4)) YYABORT; }
+ { if (add_group_to_list(YYTHD, $3,(bool) $4)) MYSQL_YYABORT; }
| order_ident order_dir
- { if (add_group_to_list(YYTHD, $1,(bool) $2)) YYABORT; };
+ { if (add_group_to_list(YYTHD, $1,(bool) $2)) MYSQL_YYABORT; };
olap_opt:
/* empty */ {}
@@ -7584,11 +7737,11 @@ olap_opt:
{
my_error(ER_WRONG_USAGE, MYF(0), "WITH CUBE",
"global union parameters");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->current_select->olap= CUBE_TYPE;
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "CUBE");
- YYABORT; /* To be deleted in 5.1 */
+ MYSQL_YYABORT; /* To be deleted in 5.1 */
}
| WITH ROLLUP_SYM
{
@@ -7597,7 +7750,7 @@ olap_opt:
{
my_error(ER_WRONG_USAGE, MYF(0), "WITH ROLLUP",
"global union parameters");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->current_select->olap= ROLLUP_TYPE;
}
@@ -7622,7 +7775,7 @@ alter_order_item:
THD *thd= YYTHD;
bool ascending= ($2 == 1) ? true : false;
if (add_order_to_list(thd, $1, ascending))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -7645,7 +7798,7 @@ order_clause:
{
my_error(ER_WRONG_USAGE, MYF(0),
"CUBE/ROLLUP", "ORDER BY");
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->sql_command != SQLCOM_ALTER_TABLE && !unit->fake_select_lex)
{
@@ -7662,15 +7815,15 @@ order_clause:
(first_sl->order_list.elements ||
first_sl->select_limit) &&
unit->add_fake_select_lex(lex->thd))
- YYABORT;
+ MYSQL_YYABORT;
}
} order_list;
order_list:
order_list ',' order_ident order_dir
- { if (add_order_to_list(YYTHD, $3,(bool) $4)) YYABORT; }
+ { if (add_order_to_list(YYTHD, $3,(bool) $4)) MYSQL_YYABORT; }
| order_ident order_dir
- { if (add_order_to_list(YYTHD, $1,(bool) $2)) YYABORT; };
+ { if (add_order_to_list(YYTHD, $1,(bool) $2)) MYSQL_YYABORT; };
order_dir:
/* empty */ { $$ = 1; }
@@ -7755,7 +7908,7 @@ real_ulong_num:
| HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); }
| LONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
| ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
- | dec_num_error { YYABORT; }
+ | dec_num_error { MYSQL_YYABORT; }
;
ulonglong_num:
@@ -7770,12 +7923,12 @@ real_ulonglong_num:
NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
| ULONGLONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
| LONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
- | dec_num_error { YYABORT; }
+ | dec_num_error { MYSQL_YYABORT; }
;
dec_num_error:
dec_num
- { yyerror(ER(ER_ONLY_INTEGERS_ALLOWED)); }
+ { my_parse_error(ER(ER_ONLY_INTEGERS_ALLOWED)); }
;
dec_num:
@@ -7792,13 +7945,13 @@ procedure_clause:
if (! lex->parsing_options.allows_select_procedure)
{
my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "PROCEDURE");
- YYABORT;
+ MYSQL_YYABORT;
}
if (&lex->select_lex != lex->current_select)
{
my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->proc_list.elements=0;
lex->proc_list.first=0;
@@ -7807,7 +7960,7 @@ procedure_clause:
current_select->
context,
NULL,NULL,$2.str)))
- YYABORT;
+ MYSQL_YYABORT;
Lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
}
'(' procedure_list ')';
@@ -7826,7 +7979,7 @@ procedure_item:
{
LEX *lex= Lex;
if (add_proc_to_list(lex->thd, $2))
- YYABORT;
+ MYSQL_YYABORT;
if (!$2->name)
$2->set_name($1,(uint) ((char*) lex->tok_end - $1),
YYTHD->charset());
@@ -7838,7 +7991,7 @@ select_var_list_init:
{
LEX *lex=Lex;
if (!lex->describe && (!(lex->result= new select_dumpvar())))
- YYABORT;
+ MYSQL_YYABORT;
}
select_var_list
{}
@@ -7870,7 +8023,7 @@ select_var_ident:
if (!lex->spcont || !(t=lex->spcont->find_variable(&$1)))
{
my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->result)
{
@@ -7899,7 +8052,7 @@ into:
if (! Lex->parsing_options.allows_select_into)
{
my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "INTO");
- YYABORT;
+ MYSQL_YYABORT;
}
}
into_destination
@@ -7912,7 +8065,7 @@ into_destination:
lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
if (!(lex->exchange= new sql_exchange($2.str, 0)) ||
!(lex->result= new select_export(lex->exchange)))
- YYABORT;
+ MYSQL_YYABORT;
}
opt_field_term opt_line_term
| DUMPFILE TEXT_STRING_filesystem
@@ -7922,9 +8075,9 @@ into_destination:
{
lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
if (!(lex->exchange= new sql_exchange($2.str,1)))
- YYABORT;
+ MYSQL_YYABORT;
if (!(lex->result= new select_dump(lex->exchange)))
- YYABORT;
+ MYSQL_YYABORT;
}
}
| select_var_list_init
@@ -7970,7 +8123,7 @@ drop:
$3.str));
if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL,
TL_OPTION_UPDATING))
- YYABORT;
+ MYSQL_YYABORT;
}
| DROP DATABASE if_exists ident
{
@@ -7985,7 +8138,7 @@ drop:
if (lex->sphead)
{
my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_DROP_FUNCTION;
lex->drop_if_exists= $3;
@@ -7997,7 +8150,7 @@ drop:
if (lex->sphead)
{
my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_DROP_PROCEDURE;
lex->drop_if_exists= $3;
@@ -8031,7 +8184,7 @@ drop:
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= DROP_TABLESPACE;
}
- | DROP LOGFILE_SYM GROUP logfile_group_name opt_ts_engine opt_ts_wait
+ | DROP LOGFILE_SYM GROUP_SYM logfile_group_name opt_ts_engine opt_ts_wait
{
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= DROP_LOGFILE_GROUP;
@@ -8053,7 +8206,7 @@ table_name:
table_ident
{
if (!Select->add_table_to_list(YYTHD, $1, NULL, TL_OPTION_UPDATING))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -8151,7 +8304,7 @@ insert_field_spec:
LEX *lex=Lex;
if (!(lex->insert_list = new List_item) ||
lex->many_values.push_back(lex->insert_list))
- YYABORT;
+ MYSQL_YYABORT;
}
ident_eq_list;
@@ -8181,7 +8334,7 @@ ident_eq_value:
LEX *lex=Lex;
if (lex->field_list.push_back($1) ||
lex->insert_list->push_back($3))
- YYABORT;
+ MYSQL_YYABORT;
};
equal: EQ {}
@@ -8197,13 +8350,13 @@ no_braces:
'('
{
if (!(Lex->insert_list = new List_item))
- YYABORT;
+ MYSQL_YYABORT;
}
opt_values ')'
{
LEX *lex=Lex;
if (lex->many_values.push_back(lex->insert_list))
- YYABORT;
+ MYSQL_YYABORT;
};
opt_values:
@@ -8214,12 +8367,12 @@ values:
values ',' expr_or_default
{
if (Lex->insert_list->push_back($3))
- YYABORT;
+ MYSQL_YYABORT;
}
| expr_or_default
{
if (Lex->insert_list->push_back($1))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -8256,7 +8409,7 @@ update:
/* it is single table update and it is update of derived table */
my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
lex->select_lex.get_table_list()->alias, "UPDATE");
- YYABORT;
+ MYSQL_YYABORT;
}
/*
In case of multi-update setting write lock for all tables may
@@ -8276,7 +8429,7 @@ update_elem:
simple_ident_nospvar equal expr_or_default
{
if (add_item_to_list(YYTHD, $1) || add_value_to_list(YYTHD, $3))
- YYABORT;
+ MYSQL_YYABORT;
};
insert_update_list:
@@ -8289,7 +8442,7 @@ insert_update_elem:
LEX *lex= Lex;
if (lex->update_list.push_back($1) ||
lex->value_list.push_back($3))
- YYABORT;
+ MYSQL_YYABORT;
};
opt_low_priority:
@@ -8316,7 +8469,7 @@ single_multi:
{
if (!Select->add_table_to_list(YYTHD, $2, NULL, TL_OPTION_UPDATING,
Lex->lock_option))
- YYABORT;
+ MYSQL_YYABORT;
}
where_clause opt_order_clause
delete_limit_clause {}
@@ -8325,14 +8478,14 @@ single_multi:
FROM join_table_list where_clause
{
if (multi_delete_set_locks_and_link_aux_tables(Lex))
- YYABORT;
+ MYSQL_YYABORT;
}
| FROM table_wild_list
{ mysql_init_multi_delete(Lex); }
USING join_table_list where_clause
{
if (multi_delete_set_locks_and_link_aux_tables(Lex))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -8346,7 +8499,7 @@ table_wild_one:
if (!Select->add_table_to_list(YYTHD, new Table_ident($1), $3,
TL_OPTION_UPDATING |
TL_OPTION_ALIAS, Lex->lock_option))
- YYABORT;
+ MYSQL_YYABORT;
}
| ident '.' ident opt_wild opt_table_alias
{
@@ -8356,7 +8509,7 @@ table_wild_one:
TL_OPTION_UPDATING |
TL_OPTION_ALIAS,
Lex->lock_option))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -8410,7 +8563,7 @@ show_param:
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_DATABASES;
if (prepare_schema_table(YYTHD, lex, 0, SCH_SCHEMATA))
- YYABORT;
+ MYSQL_YYABORT;
}
| opt_full TABLES opt_db wild_and_where
{
@@ -8418,7 +8571,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_TABLES;
lex->select_lex.db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES))
- YYABORT;
+ MYSQL_YYABORT;
}
| opt_full TRIGGERS_SYM opt_db wild_and_where
{
@@ -8426,7 +8579,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_TRIGGERS;
lex->select_lex.db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_TRIGGERS))
- YYABORT;
+ MYSQL_YYABORT;
}
| EVENTS_SYM opt_db wild_and_where
{
@@ -8434,7 +8587,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_EVENTS;
lex->select_lex.db= $2;
if (prepare_schema_table(YYTHD, lex, 0, SCH_EVENTS))
- YYABORT;
+ MYSQL_YYABORT;
}
| TABLE_SYM STATUS_SYM opt_db wild_and_where
{
@@ -8442,7 +8595,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_TABLE_STATUS;
lex->select_lex.db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLES))
- YYABORT;
+ MYSQL_YYABORT;
}
| OPEN_SYM TABLES opt_db wild_and_where
{
@@ -8450,7 +8603,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
lex->select_lex.db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_OPEN_TABLES))
- YYABORT;
+ MYSQL_YYABORT;
}
| opt_full PLUGIN_SYM
{
@@ -8458,14 +8611,14 @@ show_param:
WARN_DEPRECATED(yythd, "5.2", "SHOW PLUGIN", "'SHOW PLUGINS'");
lex->sql_command= SQLCOM_SHOW_PLUGINS;
if (prepare_schema_table(YYTHD, lex, 0, SCH_PLUGINS))
- YYABORT;
+ MYSQL_YYABORT;
}
| PLUGINS_SYM
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_PLUGINS;
if (prepare_schema_table(YYTHD, lex, 0, SCH_PLUGINS))
- YYABORT;
+ MYSQL_YYABORT;
}
| ENGINE_SYM known_storage_engines show_engine_param
{ Lex->create_info.db_type= $2; }
@@ -8478,7 +8631,7 @@ show_param:
if ($5)
$4->change_db($5);
if (prepare_schema_table(YYTHD, lex, $4, SCH_COLUMNS))
- YYABORT;
+ MYSQL_YYABORT;
}
| NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ
TEXT_STRING_sys AND_SYM MASTER_LOG_POS_SYM EQ ulonglong_num
@@ -8510,7 +8663,7 @@ show_param:
if ($4)
$3->change_db($4);
if (prepare_schema_table(YYTHD, lex, $3, SCH_STATISTICS))
- YYABORT;
+ MYSQL_YYABORT;
}
| COLUMN_SYM TYPES_SYM
{
@@ -8528,7 +8681,7 @@ show_param:
LEX *lex=Lex;
lex->sql_command= SQLCOM_SHOW_STORAGE_ENGINES;
if (prepare_schema_table(YYTHD, lex, 0, SCH_ENGINES))
- YYABORT;
+ MYSQL_YYABORT;
}
| AUTHORS_SYM
{
@@ -8559,7 +8712,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_STATUS;
lex->option_type= $1;
if (prepare_schema_table(YYTHD, lex, 0, SCH_STATUS))
- YYABORT;
+ MYSQL_YYABORT;
}
| INNOBASE_SYM STATUS_SYM
{
@@ -8569,7 +8722,7 @@ show_param:
ha_resolve_by_legacy_type(YYTHD, DB_TYPE_INNODB)))
{
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), "InnoDB");
- YYABORT;
+ MYSQL_YYABORT;
}
WARN_DEPRECATED(yythd, "5.2", "SHOW INNODB STATUS", "'SHOW ENGINE INNODB STATUS'");
}
@@ -8581,7 +8734,7 @@ show_param:
ha_resolve_by_legacy_type(YYTHD, DB_TYPE_INNODB)))
{
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), "InnoDB");
- YYABORT;
+ MYSQL_YYABORT;
}
WARN_DEPRECATED(yythd, "5.2", "SHOW MUTEX STATUS", "'SHOW ENGINE INNODB MUTEX'");
}
@@ -8593,21 +8746,21 @@ show_param:
lex->sql_command= SQLCOM_SHOW_VARIABLES;
lex->option_type= $1;
if (prepare_schema_table(YYTHD, lex, 0, SCH_VARIABLES))
- YYABORT;
+ MYSQL_YYABORT;
}
| charset wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_CHARSETS;
if (prepare_schema_table(YYTHD, lex, 0, SCH_CHARSETS))
- YYABORT;
+ MYSQL_YYABORT;
}
| COLLATION_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_COLLATIONS;
if (prepare_schema_table(YYTHD, lex, 0, SCH_COLLATIONS))
- YYABORT;
+ MYSQL_YYABORT;
}
| GRANTS
{
@@ -8615,7 +8768,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_GRANTS;
LEX_USER *curr_user;
if (!(curr_user= (LEX_USER*) lex->thd->alloc(sizeof(st_lex_user))))
- YYABORT;
+ MYSQL_YYABORT;
bzero(curr_user, sizeof(st_lex_user));
lex->grant_user= curr_user;
}
@@ -8637,7 +8790,7 @@ show_param:
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE;
if (!lex->select_lex.add_table_to_list(YYTHD, $3, NULL,0))
- YYABORT;
+ MYSQL_YYABORT;
lex->only_view= 0;
lex->create_info.storage_media= HA_SM_DEFAULT;
}
@@ -8646,7 +8799,7 @@ show_param:
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE;
if (!lex->select_lex.add_table_to_list(YYTHD, $3, NULL, 0))
- YYABORT;
+ MYSQL_YYABORT;
lex->only_view= 1;
}
| MASTER_SYM STATUS_SYM
@@ -8676,24 +8829,24 @@ show_param:
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_STATUS_PROC;
if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ))
- YYABORT;
+ MYSQL_YYABORT;
if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
- YYABORT;
+ MYSQL_YYABORT;
}
| FUNCTION_SYM STATUS_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_STATUS_FUNC;
if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ))
- YYABORT;
+ MYSQL_YYABORT;
if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
- YYABORT;
+ MYSQL_YYABORT;
}
| PROCEDURE CODE_SYM sp_name
{
#ifdef DBUG_OFF
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
#else
Lex->sql_command= SQLCOM_SHOW_PROC_CODE;
Lex->spname= $3;
@@ -8702,8 +8855,8 @@ show_param:
| FUNCTION_SYM CODE_SYM sp_name
{
#ifdef DBUG_OFF
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
#else
Lex->sql_command= SQLCOM_SHOW_FUNC_CODE;
Lex->spname= $3;
@@ -8778,7 +8931,7 @@ describe:
lex->select_lex.db= 0;
lex->verbose= 0;
if (prepare_schema_table(YYTHD, lex, $2, SCH_COLUMNS))
- YYABORT;
+ MYSQL_YYABORT;
}
opt_describe_column {}
| describe_command opt_extended_describe
@@ -8923,7 +9076,7 @@ load: LOAD DATA_SYM
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD DATA");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->fname_start= lex->ptr;
}
@@ -8938,11 +9091,11 @@ load: LOAD DATA_SYM
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD TABLE");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
if (!Select->add_table_to_list(YYTHD, $3, NULL, TL_OPTION_UPDATING))
- YYABORT;
+ MYSQL_YYABORT;
};
load_data:
@@ -8955,7 +9108,7 @@ load_data:
lex->duplicates= DUP_ERROR;
lex->ignore= 0;
if (!(lex->exchange= new sql_exchange($4.str, 0)))
- YYABORT;
+ MYSQL_YYABORT;
}
opt_duplicate INTO
{
@@ -8967,11 +9120,13 @@ load_data:
LEX *lex=Lex;
if (!Select->add_table_to_list(YYTHD, $10, NULL, TL_OPTION_UPDATING,
lex->lock_option))
- YYABORT;
+ MYSQL_YYABORT;
lex->field_list.empty();
lex->update_list.empty();
lex->value_list.empty();
}
+ opt_load_data_charset
+ { Lex->exchange->cs= $12; }
opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
opt_load_data_set_spec
{}
@@ -9138,19 +9293,19 @@ text_string:
param_marker:
PARAM_MARKER
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
Item_param *item;
if (! lex->parsing_options.allows_variable)
{
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
item= new Item_param((uint) (lex->tok_start - (uchar *) thd->query));
if (!($$= item) || lex->param_list.push_back(item))
{
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -9216,7 +9371,7 @@ NUM_literal:
$$= new Item_decimal($1.str, $1.length, YYTHD->charset());
if (YYTHD->net.report_error)
{
- YYABORT;
+ MYSQL_YYABORT;
}
}
| FLOAT_NUM
@@ -9224,7 +9379,7 @@ NUM_literal:
$$ = new Item_float($1.str, $1.length);
if (YYTHD->net.report_error)
{
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -9269,7 +9424,7 @@ simple_ident:
if (! lex->parsing_options.allows_variable)
{
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
Item_splocal *splocal;
@@ -9329,14 +9484,14 @@ simple_ident_q:
!new_row)
{
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT");
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->trg_chistics.event == TRG_EVENT_DELETE &&
new_row)
{
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE");
- YYABORT;
+ MYSQL_YYABORT;
}
DBUG_ASSERT(!new_row ||
@@ -9351,7 +9506,7 @@ simple_ident_q:
$3.str,
SELECT_ACL,
read_only)))
- YYABORT;
+ MYSQL_YYABORT;
/*
Let us add this item to list of all Item_trigger_field objects
@@ -9422,13 +9577,13 @@ field_ident:
if (my_strcasecmp(table_alias_charset, $1.str, table->db))
{
my_error(ER_WRONG_DB_NAME, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
if (my_strcasecmp(table_alias_charset, $3.str,
table->table_name))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
$$=$5;
}
@@ -9438,7 +9593,7 @@ field_ident:
if (my_strcasecmp(table_alias_charset, $1.str, table->alias))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
$$=$3;
}
@@ -9470,7 +9625,7 @@ IDENT_sys:
{
my_error(ER_INVALID_CHARACTER_STRING, MYF(0),
cs->csname, $1.str + wlen);
- YYABORT;
+ MYSQL_YYABORT;
}
$$= $1;
}
@@ -9553,32 +9708,32 @@ user:
{
THD *thd= YYTHD;
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
- YYABORT;
+ MYSQL_YYABORT;
$$->user = $1;
$$->host.str= (char *) "%";
$$->host.length= 1;
if (check_string_length(&$$->user,
ER(ER_USERNAME), USERNAME_LENGTH))
- YYABORT;
+ MYSQL_YYABORT;
}
| ident_or_text '@' ident_or_text
{
THD *thd= YYTHD;
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
- YYABORT;
+ MYSQL_YYABORT;
$$->user = $1; $$->host=$3;
if (check_string_length(&$$->user,
ER(ER_USERNAME), USERNAME_LENGTH) ||
check_string_length(&$$->host,
ER(ER_HOSTNAME), HOSTNAME_LENGTH))
- YYABORT;
+ MYSQL_YYABORT;
}
| CURRENT_USER optional_braces
{
if (!($$=(LEX_USER*) YYTHD->alloc(sizeof(st_lex_user))))
- YYABORT;
+ MYSQL_YYABORT;
/*
empty LEX_USER means current_user and
will be handled in the get_current_user() function
@@ -9680,6 +9835,7 @@ keyword_sp:
| COMPLETION_SYM {}
| COMPRESSED_SYM {}
| CONCURRENT {}
+ | CONNECTION_SYM {}
| CONSISTENT_SYM {}
| CONTRIBUTORS_SYM {}
| CUBE_SYM {}
@@ -9966,7 +10122,7 @@ option_type_value:
if (!(i= new sp_instr_stmt(sp->instructions(), lex->spcont,
lex)))
- YYABORT;
+ MYSQL_YYABORT;
/*
Extract the query statement from the tokenizer. The
@@ -9979,7 +10135,7 @@ option_type_value:
qbuff.length= lex->tok_end - sp->m_tmp_query;
if (!(qbuff.str= alloc_root(YYTHD->mem_root, qbuff.length + 5)))
- YYABORT;
+ MYSQL_YYABORT;
strmake(strmake(qbuff.str, "SET ", 4), (char *)sp->m_tmp_query,
qbuff.length);
@@ -10035,8 +10191,8 @@ sys_option_value:
LINT_INIT(sp_fld);
if ($1)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
if ($4)
it= $4;
@@ -10058,7 +10214,7 @@ sys_option_value:
lex->spcont,
trg_fld,
it, lex)))
- YYABORT;
+ MYSQL_YYABORT;
/*
Let us add this item to list of all Item_trigger_field
@@ -10085,8 +10241,8 @@ sys_option_value:
Item *it;
if ($1)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
spv= ctx->find_variable(&$2.base_name);
@@ -10126,7 +10282,7 @@ option_value:
| charset old_or_new_charset_name_or_default
{
THD *thd= YYTHD;
- LEX *lex= Lex;
+ LEX *lex= thd->lex;
$2= $2 ? $2: global_system_variables.character_set_client;
lex->var_list.push_back(new set_var_collation_client($2,thd->variables.collation_database,$2));
}
@@ -10141,9 +10297,9 @@ option_value:
if (spc && spc->find_variable(&names))
my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str);
else
- yyerror(ER(ER_SYNTAX_ERROR));
+ my_parse_error(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ MYSQL_YYABORT;
}
| NAMES_SYM charset_name_or_default opt_collate
{
@@ -10154,15 +10310,15 @@ option_value:
{
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
$3->name, $2->csname);
- YYABORT;
+ MYSQL_YYABORT;
}
lex->var_list.push_back(new set_var_collation_client($3,$3,$3));
}
| PASSWORD equal text_or_password
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
LEX_USER *user;
- LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
LEX_STRING pw;
@@ -10171,10 +10327,10 @@ option_value:
if (spc && spc->find_variable(&pw))
{
my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str);
- YYABORT;
+ MYSQL_YYABORT;
}
if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
- YYABORT;
+ MYSQL_YYABORT;
user->host=null_lex_str;
user->user.str=thd->security_ctx->priv_user;
thd->lex->var_list.push_back(new set_var_password(user, $3));
@@ -10198,7 +10354,7 @@ internal_variable_name:
/* Not an SP local variable */
sys_var *tmp=find_sys_var($1.str, $1.length);
if (!tmp)
- YYABORT;
+ MYSQL_YYABORT;
$$.var= tmp;
$$.base_name= null_lex_str;
/*
@@ -10207,7 +10363,7 @@ internal_variable_name:
*/
if (tmp == &sys_time_zone &&
lex->add_time_zone_tables_to_query_tables(YYTHD))
- YYABORT;
+ MYSQL_YYABORT;
else if (spc && tmp == &sys_autocommit)
{
/*
@@ -10229,8 +10385,8 @@ internal_variable_name:
LEX *lex= Lex;
if (check_reserved_words(&$1))
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER &&
(!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
@@ -10239,18 +10395,18 @@ internal_variable_name:
if ($1.str[0]=='O' || $1.str[0]=='o')
{
my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", "");
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->trg_chistics.event == TRG_EVENT_DELETE)
{
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0),
"NEW", "on DELETE");
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->trg_chistics.action_time == TRG_ACTION_AFTER)
{
my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after ");
- YYABORT;
+ MYSQL_YYABORT;
}
/* This special combination will denote field of NEW row */
$$.var= trg_new_row_fake_var;
@@ -10260,7 +10416,7 @@ internal_variable_name:
{
sys_var *tmp=find_sys_var($3.str, $3.length);
if (!tmp)
- YYABORT;
+ MYSQL_YYABORT;
if (!tmp->is_struct())
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), $3.str);
$$.var= tmp;
@@ -10271,7 +10427,7 @@ internal_variable_name:
{
sys_var *tmp=find_sys_var($3.str, $3.length);
if (!tmp)
- YYABORT;
+ MYSQL_YYABORT;
if (!tmp->is_struct())
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), $3.str);
$$.var= tmp;
@@ -10323,7 +10479,7 @@ lock:
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "LOCK");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_LOCK_TABLES;
}
@@ -10343,7 +10499,7 @@ table_lock:
table_ident opt_table_alias lock_option
{
if (!Select->add_table_to_list(YYTHD, $1, $2, 0, (thr_lock_type) $3))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -10362,7 +10518,7 @@ unlock:
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "UNLOCK");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_UNLOCK_TABLES;
}
@@ -10382,11 +10538,11 @@ handler:
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_HA_OPEN;
if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0))
- YYABORT;
+ MYSQL_YYABORT;
}
| HANDLER_SYM table_ident_nodb CLOSE_SYM
{
@@ -10394,11 +10550,11 @@ handler:
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_HA_CLOSE;
if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
- YYABORT;
+ MYSQL_YYABORT;
}
| HANDLER_SYM table_ident_nodb READ_SYM
{
@@ -10406,7 +10562,7 @@ handler:
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->expr_allows_subselect= FALSE;
lex->sql_command = SQLCOM_HA_READ;
@@ -10414,7 +10570,7 @@ handler:
lex->current_select->select_limit= new Item_int((int32) 1);
lex->current_select->offset_limit= 0;
if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
- YYABORT;
+ MYSQL_YYABORT;
}
handler_read_or_scan where_clause opt_limit_clause
{
@@ -10443,7 +10599,7 @@ handler_rkey_function:
lex->ha_read_mode = RKEY;
lex->ha_rkey_mode=$1;
if (!(lex->insert_list = new List_item))
- YYABORT;
+ MYSQL_YYABORT;
} '(' values ')' { }
;
@@ -10475,8 +10631,8 @@ revoke_command:
LEX *lex= Lex;
if (lex->columns.elements)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_FUNCTION;
@@ -10488,8 +10644,8 @@ revoke_command:
LEX *lex= Lex;
if (lex->columns.elements)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_PROCEDURE;
@@ -10521,8 +10677,8 @@ grant_command:
LEX *lex= Lex;
if (lex->columns.elements)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_FUNCTION;
@@ -10534,8 +10690,8 @@ grant_command:
LEX *lex= Lex;
if (lex->columns.elements)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_PROCEDURE;
@@ -10614,7 +10770,7 @@ require_list_element:
if (lex->x509_subject)
{
my_error(ER_DUP_ARGUMENT, MYF(0), "SUBJECT");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->x509_subject=$2.str;
}
@@ -10624,7 +10780,7 @@ require_list_element:
if (lex->x509_issuer)
{
my_error(ER_DUP_ARGUMENT, MYF(0), "ISSUER");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->x509_issuer=$2.str;
}
@@ -10634,7 +10790,7 @@ require_list_element:
if (lex->ssl_cipher)
{
my_error(ER_DUP_ARGUMENT, MYF(0), "CIPHER");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->ssl_cipher=$2.str;
}
@@ -10643,18 +10799,18 @@ require_list_element:
grant_ident:
'*'
{
- LEX *lex= Lex;
- THD *thd= lex->thd;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
uint dummy;
if (thd->copy_db_to(&lex->current_select->db, &dummy))
- YYABORT;
+ MYSQL_YYABORT;
if (lex->grant == GLOBAL_ACLS)
lex->grant = DB_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
{
my_message(ER_ILLEGAL_GRANT_FOR_TABLE,
ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
| ident '.' '*'
@@ -10667,7 +10823,7 @@ grant_ident:
{
my_message(ER_ILLEGAL_GRANT_FOR_TABLE,
ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
| '*' '.' '*'
@@ -10680,14 +10836,14 @@ grant_ident:
{
my_message(ER_ILLEGAL_GRANT_FOR_TABLE,
ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
| table_ident
{
LEX *lex=Lex;
if (!lex->current_select->add_table_to_list(lex->thd, $1,NULL,0))
- YYABORT;
+ MYSQL_YYABORT;
if (lex->grant == GLOBAL_ACLS)
lex->grant = TABLE_ACLS & ~GRANT_ACL;
}
@@ -10695,21 +10851,21 @@ grant_ident:
user_list:
- user { if (Lex->users_list.push_back($1)) YYABORT;}
+ user { if (Lex->users_list.push_back($1)) MYSQL_YYABORT;}
| user_list ',' user
{
if (Lex->users_list.push_back($3))
- YYABORT;
+ MYSQL_YYABORT;
}
;
grant_list:
- grant_user { if (Lex->users_list.push_back($1)) YYABORT;}
+ grant_user { if (Lex->users_list.push_back($1)) MYSQL_YYABORT;}
| grant_list ',' grant_user
{
if (Lex->users_list.push_back($3))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -10932,17 +11088,17 @@ union_list:
{
/* Only the last SELECT can have INTO...... */
my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO");
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
/* This counter shouldn't be incremented for UNION parts */
Lex->nest_level--;
if (mysql_new_select(lex, 0))
- YYABORT;
+ MYSQL_YYABORT;
mysql_init_select(lex);
lex->current_select->linkage=UNION_TYPE;
if ($2) /* UNION DISTINCT - remember position */
@@ -11007,7 +11163,6 @@ subselect:
}
| '(' subselect_start subselect ')'
{
- LEX *lex= Lex;
THD *thd= YYTHD;
/*
note that a local variable can't be used for
@@ -11036,8 +11191,8 @@ subselect_start:
LEX *lex=Lex;
if (!lex->expr_allows_subselect)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
/*
we are making a "derived table" for the parenthesis
@@ -11047,7 +11202,7 @@ subselect_start:
SELECT * FROM ((SELECT ...) UNION ...)
*/
if (mysql_new_select(Lex, 1))
- YYABORT;
+ MYSQL_YYABORT;
};
subselect_end:
@@ -11058,6 +11213,12 @@ subselect_end:
lex->current_select = lex->current_select->return_after_parsing();
lex->nest_level--;
lex->current_select->n_child_sum_items += child->n_sum_items;
+ /*
+ A subselect can add fields to an outer select. Reserve space for
+ them.
+ */
+ lex->current_select->select_n_where_fields+=
+ child->select_n_where_fields;
};
/**************************************************************************
@@ -11161,7 +11322,7 @@ view_tail:
lex->sql_command= SQLCOM_CREATE_VIEW;
/* first table in list is target VIEW name */
if (!lex->select_lex.add_table_to_list(thd, $3, NULL, TL_OPTION_UPDATING))
- YYABORT;
+ MYSQL_YYABORT;
}
view_list_opt AS view_select view_check_option
{}
@@ -11207,7 +11368,7 @@ view_select:
view_select_aux:
SELECT_SYM remember_name select_init2
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
char *stmt_beg= (lex->sphead ?
(char *)lex->sphead->m_tmp_query :
@@ -11216,7 +11377,7 @@ view_select_aux:
}
| '(' remember_name select_paren ')' union_opt
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
char *stmt_beg= (lex->sphead ?
(char *)lex->sphead->m_tmp_query :
@@ -11252,11 +11413,11 @@ trigger_tail:
if (lex->sphead)
{
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER");
- YYABORT;
+ MYSQL_YYABORT;
}
if (!(sp= new sp_head()))
- YYABORT;
+ MYSQL_YYABORT;
sp->reset_thd_mem_root(YYTHD);
sp->init(lex);
sp->init_sp_name(YYTHD, $3);
@@ -11294,7 +11455,7 @@ trigger_tail:
sp->restore_thd_mem_root(YYTHD);
if (sp->is_not_allowed_in_function("trigger"))
- YYABORT;
+ MYSQL_YYABORT;
/*
We have to do it after parsing trigger body, because some of
@@ -11305,7 +11466,7 @@ trigger_tail:
(LEX_STRING*) 0,
TL_OPTION_UPDATING,
TL_IGNORE))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -11333,7 +11494,7 @@ sp_tail:
if (lex->sphead)
{
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->stmt_definition_begin= $2;
@@ -11422,23 +11583,23 @@ xa: XA_SYM begin_or_start xid opt_join_or_resume
xid: text_string
{
- YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE);
+ MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE);
if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
- YYABORT;
+ MYSQL_YYABORT;
Lex->xid->set(1L, $1->ptr(), $1->length(), 0, 0);
}
| text_string ',' text_string
{
- YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
+ MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
- YYABORT;
+ MYSQL_YYABORT;
Lex->xid->set(1L, $1->ptr(), $1->length(), $3->ptr(), $3->length());
}
| text_string ',' text_string ',' ulong_num
{
- YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
+ MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
- YYABORT;
+ MYSQL_YYABORT;
Lex->xid->set($5, $1->ptr(), $1->length(), $3->ptr(), $3->length());
}
;
diff --git a/sql/table.cc b/sql/table.cc
index cf2eb1705a5..560f53bae26 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -120,7 +120,6 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
share->normalized_path.length= path_length;
share->version= refresh_version;
- share->flush_version= flush_version;
/*
This constant is used to mark that no table map version has been
@@ -1237,17 +1236,17 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if (share->blob_fields)
{
Field **ptr;
- uint i, *save;
+ uint k, *save;
/* Store offsets to blob fields to find them fast */
if (!(share->blob_field= save=
(uint*) alloc_root(&share->mem_root,
(uint) (share->blob_fields* sizeof(uint)))))
goto err;
- for (i=0, ptr= share->field ; *ptr ; ptr++, i++)
+ for (k=0, ptr= share->field ; *ptr ; ptr++, k++)
{
if ((*ptr)->flags & BLOB_FLAG)
- (*save++)= i;
+ (*save++)= k;
}
}
@@ -1263,7 +1262,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
share->column_bitmap_size= bitmap_buffer_size(share->fields);
if (!(bitmaps= (my_bitmap_map*) alloc_root(&share->mem_root,
- share->column_bitmap_size)))
+ share->column_bitmap_size)))
goto err;
bitmap_init(&share->all_set, bitmaps, share->fields, FALSE);
bitmap_set_all(&share->all_set);
@@ -2891,7 +2890,9 @@ void st_table_list::hide_view_error(THD *thd)
thd->net.last_errno == ER_SP_DOES_NOT_EXIST ||
thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR ||
thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR ||
- thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR)
+ thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR ||
+ thd->net.last_errno == ER_TABLE_NOT_LOCKED ||
+ thd->net.last_errno == ER_NO_SUCH_TABLE)
{
TABLE_LIST *top= top_table();
thd->clear_error();
@@ -2972,19 +2973,17 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure)
{
if (check_option && check_option->val_int() == 0)
{
- TABLE_LIST *view= top_table();
+ TABLE_LIST *main_view= top_table();
if (ignore_failure)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_VIEW_CHECK_FAILED, ER(ER_VIEW_CHECK_FAILED),
- view->view_db.str, view->view_name.str);
+ main_view->view_db.str, main_view->view_name.str);
return(VIEW_CHECK_SKIP);
}
- else
- {
- my_error(ER_VIEW_CHECK_FAILED, MYF(0), view->view_db.str, view->view_name.str);
- return(VIEW_CHECK_ERROR);
- }
+ my_error(ER_VIEW_CHECK_FAILED, MYF(0), main_view->view_db.str,
+ main_view->view_name.str);
+ return(VIEW_CHECK_ERROR);
}
return(VIEW_CHECK_OK);
}
@@ -2996,19 +2995,20 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure)
SYNOPSIS
st_table_list::check_single_table()
- table reference on variable where to store found table
+ table_arg reference on variable where to store found table
(should be 0 on call, to find table, or point to table for
unique test)
map bit mask of tables
- view view for which we are looking table
+ view_arg view for which we are looking table
RETURN
FALSE table not found or found only one
TRUE found several tables
*/
-bool st_table_list::check_single_table(st_table_list **table, table_map map,
- st_table_list *view)
+bool st_table_list::check_single_table(st_table_list **table_arg,
+ table_map map,
+ st_table_list *view_arg)
{
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
{
@@ -3016,13 +3016,13 @@ bool st_table_list::check_single_table(st_table_list **table, table_map map,
{
if (tbl->table->map & map)
{
- if (*table)
+ if (*table_arg)
return TRUE;
- *table= tbl;
- tbl->check_option= view->check_option;
+ *table_arg= tbl;
+ tbl->check_option= view_arg->check_option;
}
}
- else if (tbl->check_single_table(table, map, view))
+ else if (tbl->check_single_table(table_arg, map, view_arg))
return TRUE;
}
return FALSE;
@@ -3347,18 +3347,19 @@ bool st_table_list::prepare_security(THD *thd)
while ((tbl= tb++))
{
DBUG_ASSERT(tbl->referencing_view);
- char *db, *table_name;
+ char *local_db, *local_table_name;
if (tbl->view)
{
- db= tbl->view_db.str;
- table_name= tbl->view_name.str;
+ local_db= tbl->view_db.str;
+ local_table_name= tbl->view_name.str;
}
else
{
- db= tbl->db;
- table_name= tbl->table_name;
+ local_db= tbl->db;
+ local_table_name= tbl->table_name;
}
- fill_effective_table_privileges(thd, &tbl->grant, db, table_name);
+ fill_effective_table_privileges(thd, &tbl->grant, local_db,
+ local_table_name);
if (tbl->table)
tbl->table->grant= grant;
}
@@ -3430,6 +3431,7 @@ Field *Natural_join_column::field()
const char *Natural_join_column::table_name()
{
+ DBUG_ASSERT(table_ref);
return table_ref->alias;
}
@@ -3717,13 +3719,13 @@ Field_iterator_table_ref::get_or_create_column_ref(TABLE_LIST *parent_table_ref)
uint field_count;
TABLE_LIST *add_table_ref= parent_table_ref ?
parent_table_ref : table_ref;
-
LINT_INIT(field_count);
+
if (field_it == &table_field_it)
{
/* The field belongs to a stored table. */
- Field *field= table_field_it.field();
- nj_col= new Natural_join_column(field, table_ref);
+ Field *tmp_field= table_field_it.field();
+ nj_col= new Natural_join_column(tmp_field, table_ref);
field_count= table_ref->table->s->fields;
}
else if (field_it == &view_field_it)
@@ -4085,19 +4087,19 @@ void st_table_list::reinit_before_use(THD *thd)
*/
table= 0;
/* Reset is_schema_table_processed value(needed for I_S tables */
- is_schema_table_processed= FALSE;
+ schema_table_state= NOT_PROCESSED;
TABLE_LIST *embedded; /* The table at the current level of nesting. */
- TABLE_LIST *embedding= this; /* The parent nested table reference. */
+ TABLE_LIST *parent_embedding= this; /* The parent nested table reference. */
do
{
- embedded= embedding;
+ embedded= parent_embedding;
if (embedded->prep_on_expr)
embedded->on_expr= embedded->prep_on_expr->copy_andor_structure(thd);
- embedding= embedded->embedding;
+ parent_embedding= embedded->embedding;
}
- while (embedding &&
- embedding->nested_join->join_list.head() == embedded);
+ while (parent_embedding &&
+ parent_embedding->nested_join->join_list.head() == embedded);
}
/*
diff --git a/sql/table.cc.rej b/sql/table.cc.rej
deleted file mode 100644
index fd728ba9965..00000000000
--- a/sql/table.cc.rej
+++ /dev/null
@@ -1,17 +0,0 @@
-***************
-*** 2246,2252 ****
-
- bool check_db_name(char *name)
- {
-! char *start=name;
- /* Used to catch empty names and names with end space */
- bool last_char_is_space= TRUE;
-
---- 2257,2263 ----
-
- bool check_db_name(char *name)
- {
-! char *start= name;
- /* Used to catch empty names and names with end space */
- bool last_char_is_space= TRUE;
-
diff --git a/sql/table.h b/sql/table.h
index 80add0e0b91..54c820d391c 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -158,12 +158,17 @@ typedef struct st_table_share
LEX_STRING path; /* Path to .frm file (from datadir) */
LEX_STRING normalized_path; /* unpack_filename(path) */
LEX_STRING connect_string;
- key_map keys_in_use; /* Keys in use for table */
+
+ /*
+ Set of keys in use, implemented as a Bitmap.
+ Excludes keys disabled by ALTER TABLE ... DISABLE KEYS.
+ */
+ key_map keys_in_use;
key_map keys_for_keyread;
ha_rows min_rows, max_rows; /* create information */
ulong avg_row_length; /* create information */
ulong raid_chunksize;
- ulong version, flush_version, mysql_version;
+ ulong version, mysql_version;
ulong timestamp_offset; /* Set to offset+1 of record */
ulong reclength; /* Recordlength */
@@ -313,7 +318,21 @@ struct st_table {
byte *write_row_record; /* Used as optimisation in
THD::write_row */
byte *insert_values; /* used by INSERT ... UPDATE */
- key_map quick_keys, used_keys, keys_in_use_for_query, merge_keys;
+ key_map quick_keys, used_keys;
+
+ /*
+ A set of keys that can be used in the query that references this
+ table.
+
+ All indexes disabled on the table's TABLE_SHARE (see TABLE::s) will be
+ subtracted from this set upon instantiation. Thus for any TABLE t it holds
+ that t.keys_in_use_for_query is a subset of t.s.keys_in_use. Generally we
+ must not introduce any new keys here (see setup_tables).
+
+ The set is implemented as a bitmap.
+ */
+ key_map keys_in_use_for_query;
+ key_map merge_keys;
KEY *key_info; /* data of keys in database */
Field *next_number_field; /* Set if next_number is activated */
@@ -389,6 +408,10 @@ struct st_table {
/*
If true, the current table row is considered to have all columns set to
NULL, including columns declared as "not null" (see maybe_null).
+
+ TODO: Each of these flags take up 8 bits. They can just as easily
+ be put into one single unsigned long and instead of taking up 18
+ bytes, it would take up 4.
*/
my_bool null_row;
my_bool force_index;
@@ -396,6 +419,7 @@ struct st_table {
my_bool key_read, no_keyread;
my_bool locked_by_flush;
my_bool locked_by_logger;
+ my_bool no_replicate;
my_bool locked_by_name;
my_bool fulltext_searched;
my_bool no_cache;
@@ -452,6 +476,12 @@ struct st_table {
};
+enum enum_schema_table_state
+{
+ NOT_PROCESSED= 0,
+ PROCESSED_BY_CREATE_SORT_INDEX,
+ PROCESSED_BY_JOIN_EXEC
+};
typedef struct st_foreign_key_info
{
@@ -460,6 +490,7 @@ typedef struct st_foreign_key_info
LEX_STRING *referenced_table;
LEX_STRING *update_method;
LEX_STRING *delete_method;
+ LEX_STRING *referenced_key_name;
List<LEX_STRING> foreign_fields;
List<LEX_STRING> referenced_fields;
} FOREIGN_KEY_INFO;
@@ -710,7 +741,6 @@ typedef struct st_table_list
st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
st_select_lex *schema_select_lex;
- bool is_schema_table_processed;
/*
True when the view field translation table is used to convert
schema table fields for backwards compatibility with SHOW command.
@@ -820,12 +850,13 @@ typedef struct st_table_list
*/
bool prelocking_placeholder;
+ enum enum_schema_table_state schema_table_state;
void calc_md5(char *buffer);
void set_underlying_merge();
int view_check_option(THD *thd, bool ignore_failure);
bool setup_underlying(THD *thd);
void cleanup_items();
- bool placeholder() {return derived || view; }
+ bool placeholder() {return derived || view || schema_table || !table; }
void print(THD *thd, String *str);
bool check_single_table(st_table_list **table, table_map map,
st_table_list *view);
diff --git a/sql/tztime.cc b/sql/tztime.cc
index fe91aa71272..e236ceb11d7 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -546,8 +546,8 @@ sec_to_TIME(TIME * tmp, my_time_t t, long offset)
int yleap;
const uint *ip;
- days= t / SECS_PER_DAY;
- rem= t % SECS_PER_DAY;
+ days= (long) (t / SECS_PER_DAY);
+ rem= (long) (t % SECS_PER_DAY);
/*
We do this as separate step after dividing t, because this
@@ -1769,8 +1769,8 @@ end_with_setting_default_tz:
/* If we have default time zone try to load it */
if (default_tzname)
{
- String tmp_tzname(default_tzname, &my_charset_latin1);
- if (!(global_system_variables.time_zone= my_tz_find(&tmp_tzname, tables)))
+ String tmp_tzname2(default_tzname, &my_charset_latin1);
+ if (!(global_system_variables.time_zone= my_tz_find(&tmp_tzname2, tables)))
{
sql_print_error("Fatal error: Illegal or unknown default time zone '%s'",
default_tzname);
diff --git a/sql/udf_example.c b/sql/udf_example.c
index 2bb4fe92d2f..d37c6505ced 100644
--- a/sql/udf_example.c
+++ b/sql/udf_example.c
@@ -684,7 +684,7 @@ longlong sequence(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
****************************************************************************/
#ifdef __WIN__
-#include <winsock.h>
+#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
diff --git a/sql/udf_example.def b/sql/udf_example.def
index ee107d58e51..7a87147d7b6 100644
--- a/sql/udf_example.def
+++ b/sql/udf_example.def
@@ -1,5 +1,4 @@
LIBRARY udf_example
-DESCRIPTION 'MySQL Sample for UDF'
VERSION 1.0
EXPORTS
lookup
diff --git a/sql/unireg.cc b/sql/unireg.cc
index b1c29c885d9..d90420313a6 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -82,7 +82,7 @@ bool mysql_create_frm(THD *thd, const char *file_name,
uchar fileinfo[64],forminfo[288],*keybuff;
TYPELIB formnames;
uchar *screen_buff;
- char buff[32];
+ char buff[128];
#ifdef WITH_PARTITION_STORAGE_ENGINE
partition_info *part_info= thd->work_part_info;
#endif
@@ -175,7 +175,6 @@ bool mysql_create_frm(THD *thd, const char *file_name,
create_info->comment.length, 60);
if (tmp_len < create_info->comment.length)
{
- char buff[128];
(void) my_snprintf(buff, sizeof(buff), "Too long comment for table '%s'",
table);
if ((thd->variables.sql_mode &
@@ -549,11 +548,11 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
create_field *field;
while ((field=it++))
{
-
uint tmp_len= system_charset_info->cset->charpos(system_charset_info,
field->comment.str,
field->comment.str +
- field->comment.length, 255);
+ field->comment.length,
+ 255);
if (tmp_len < field->comment.length)
{
char buff[128];
@@ -622,8 +621,9 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
for (uint pos= 0; pos < field->interval->count; pos++)
{
char *dst;
- uint length= field->save_interval->type_lengths[pos], hex_length;
const char *src= field->save_interval->type_names[pos];
+ uint hex_length;
+ length= field->save_interval->type_lengths[pos];
hex_length= length * 2;
field->interval->type_lengths[pos]= hex_length;
field->interval->type_names[pos]= dst= sql_alloc(hex_length + 1);
@@ -913,7 +913,10 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
field->interval,
field->field_name);
if (!regfield)
+ {
+ error= 1;
goto err; // End of memory
+ }
/* save_in_field() will access regfield->table->in_use */
regfield->init(&table);