diff options
author | Michael Widenius <monty@mysql.com> | 2008-10-10 18:28:41 +0300 |
---|---|---|
committer | Michael Widenius <monty@mysql.com> | 2008-10-10 18:28:41 +0300 |
commit | f47e003e1bfc56c2bf5d0f144a35517f526b538b (patch) | |
tree | e2bfb9834c6e558381465ed2f57a9d873a9b2c90 /sql | |
parent | 51a92bbb03cc58ab8688fa9d8226afe32e6156ca (diff) | |
parent | 9daa56fd5ce3ccd33c32b5a505ac1d2b2c437460 (diff) | |
download | mariadb-git-f47e003e1bfc56c2bf5d0f144a35517f526b538b.tar.gz |
Merged 5.1 with maria 5.1
Diffstat (limited to 'sql')
94 files changed, 17307 insertions, 3622 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 25223f41b21..5da1285f29a 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -39,11 +39,11 @@ SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/sql/message.rc ${PROJECT_SOURCE_DIR}/include/sql_state.h PROPERTIES GENERATED 1) -ADD_DEFINITIONS(-DMYSQL_SERVER -D_CONSOLE -DHAVE_DLOPEN) +ADD_DEFINITIONS(-DMYSQL_SERVER -D_CONSOLE -DHAVE_DLOPEN -DHAVE_EVENT_SCHEDULER) ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc - discover.cc ../libmysql/errmsg.c field.cc stacktrace.c stacktrace.h field_conv.cc + discover.cc ../libmysql/errmsg.c field.cc field_conv.cc filesort.cc gstream.cc ha_partition.cc handler.cc hash_filo.cc hash_filo.h @@ -75,7 +75,7 @@ ADD_EXECUTABLE(mysqld 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 - sql_profile.cc + sql_profile.cc event_parse_data.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 3a6f4bcb7a2..b9de9b279a3 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -54,7 +54,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ procedure.h sql_class.h sql_lex.h sql_list.h \ sql_map.h sql_string.h unireg.h \ sql_error.h field.h handler.h mysqld_suffix.h \ - sql_profile.h \ + sql_profile.h \ ha_ndbcluster.h ha_ndbcluster_cond.h \ ha_ndbcluster_binlog.h ha_ndbcluster_tables.h \ ha_partition.h rpl_constants.h \ @@ -66,14 +66,14 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ sql_repl.h slave.h rpl_filter.h rpl_injector.h \ log_event.h rpl_record.h \ log_event_old.h rpl_record_old.h \ - stacktrace.h sql_sort.h sql_cache.h set_var.h \ + sql_sort.h sql_cache.h set_var.h \ spatial.h gstream.h client_settings.h tzfile.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 scheduler.h \ event_db_repository.h event_queue.h \ - sql_plugin.h authors.h \ + sql_plugin.h authors.h event_parse_data.h \ event_data_objects.h event_scheduler.h \ sql_partition.h partition_info.h partition_element.h \ contributors.h sql_servers.h @@ -110,7 +110,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ rpl_reporting.cc \ sql_union.cc sql_derived.cc \ sql_client.cc \ - stacktrace.c repl_failsafe.h repl_failsafe.cc \ + repl_failsafe.h repl_failsafe.cc \ sql_olap.cc sql_view.cc \ gstream.cc spatial.cc sql_help.cc sql_cursor.cc \ tztime.cc my_decimal.cc\ @@ -120,7 +120,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ event_queue.cc event_db_repository.cc events.cc \ sql_plugin.cc sql_binlog.cc \ sql_builtin.cc sql_tablespace.cc partition_info.cc \ - sql_servers.cc + sql_servers.cc event_parse_data.cc nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c @@ -140,6 +140,7 @@ DEFS = -DMYSQL_SERVER \ -DDATADIR="\"$(MYSQLDATAdir)\"" \ -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \ -DPLUGINDIR="\"$(pkgplugindir)\"" \ + -DHAVE_EVENT_SCHEDULER \ @DEFS@ BUILT_MAINT_SRC = sql_yacc.cc sql_yacc.h @@ -178,6 +179,12 @@ lex_hash.h: gen_lex_hash.cc lex.h udf_example_la_SOURCES= udf_example.c udf_example_la_LDFLAGS= -module -rpath $(pkglibdir) +# We might have some stuff not built in this build, but that we want to install +install-exec-hook: + $(mkinstalldirs) $(DESTDIR)$(libexecdir) $(DESTDIR)$(pkglibdir) + test ! -x mysqld-debug$(EXEEXT) || $(INSTALL_PROGRAM) mysqld-debug$(EXEEXT) $(DESTDIR)$(libexecdir) + test ! -f mysqld-debug.sym.gz || $(INSTALL_DATA) mysqld-debug.sym.gz $(DESTDIR)$(pkglibdir) + test ! -f mysqld.sym.gz || $(INSTALL_DATA) mysqld.sym.gz $(DESTDIR)$(pkglibdir) # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index f4962fb35ff..b98922e2408 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -25,8 +25,6 @@ @{ */ -#define EVEX_MAX_INTERVAL_VALUE 1000000000L - /*************************************************************************/ /** @@ -188,524 +186,6 @@ Event_queue_element_for_exec::~Event_queue_element_for_exec() /* - Returns a new instance - - SYNOPSIS - Event_parse_data::new_instance() - - RETURN VALUE - Address or NULL in case of error - - NOTE - Created on THD's mem_root -*/ - -Event_parse_data * -Event_parse_data::new_instance(THD *thd) -{ - return new (thd->mem_root) Event_parse_data; -} - - -/* - Constructor - - SYNOPSIS - Event_parse_data::Event_parse_data() -*/ - -Event_parse_data::Event_parse_data() - :on_completion(Event_basic::ON_COMPLETION_DROP), - status(Event_basic::ENABLED), - do_not_create(FALSE), - body_changed(FALSE), - item_starts(NULL), item_ends(NULL), item_execute_at(NULL), - starts_null(TRUE), ends_null(TRUE), execute_at_null(TRUE), - item_expression(NULL), expression(0) -{ - DBUG_ENTER("Event_parse_data::Event_parse_data"); - - /* Actually in the parser STARTS is always set */ - starts= ends= execute_at= 0; - - comment.str= NULL; - comment.length= 0; - - DBUG_VOID_RETURN; -} - - -/* - Set a name of the event - - SYNOPSIS - Event_parse_data::init_name() - thd THD - spn the name extracted in the parser -*/ - -void -Event_parse_data::init_name(THD *thd, sp_name *spn) -{ - DBUG_ENTER("Event_parse_data::init_name"); - - /* We have to copy strings to get them into the right memroot */ - dbname.length= spn->m_db.length; - dbname.str= thd->strmake(spn->m_db.str, spn->m_db.length); - name.length= spn->m_name.length; - name.str= thd->strmake(spn->m_name.str, spn->m_name.length); - - if (spn->m_qname.length == 0) - spn->init_qname(thd); - - DBUG_VOID_RETURN; -} - - -/* - This function is called on CREATE EVENT or ALTER EVENT. When either - ENDS or AT is in the past, we are trying to create an event that - will never be executed. If it has ON COMPLETION NOT PRESERVE - (default), then it would normally be dropped already, so on CREATE - EVENT we give a warning, and do not create anyting. On ALTER EVENT - we give a error, and do not change the event. - - If the event has ON COMPLETION PRESERVE, then we see if the event is - created or altered to the ENABLED (default) state. If so, then we - give a warning, and change the state to DISABLED. - - Otherwise it is a valid event in ON COMPLETION PRESERVE DISABLE - state. -*/ - -void -Event_parse_data::check_if_in_the_past(THD *thd, my_time_t ltime_utc) -{ - if (ltime_utc >= (my_time_t) thd->query_start()) - return; - - if (on_completion == Event_basic::ON_COMPLETION_DROP) - { - switch (thd->lex->sql_command) { - case SQLCOM_CREATE_EVENT: - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_EVENT_CANNOT_CREATE_IN_THE_PAST, - ER(ER_EVENT_CANNOT_CREATE_IN_THE_PAST)); - break; - case SQLCOM_ALTER_EVENT: - my_error(ER_EVENT_CANNOT_ALTER_IN_THE_PAST, MYF(0)); - break; - default: - DBUG_ASSERT(0); - } - - do_not_create= TRUE; - } - else if (status == Event_basic::ENABLED) - { - status= Event_basic::DISABLED; - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_EVENT_EXEC_TIME_IN_THE_PAST, - ER(ER_EVENT_EXEC_TIME_IN_THE_PAST)); - } -} - - -/* - Sets time for execution for one-time event. - - SYNOPSIS - Event_parse_data::init_execute_at() - thd Thread - - RETURN VALUE - 0 OK - ER_WRONG_VALUE Wrong value for execute at (reported) -*/ - -int -Event_parse_data::init_execute_at(THD *thd) -{ - my_bool not_used; - MYSQL_TIME ltime; - my_time_t ltime_utc; - - DBUG_ENTER("Event_parse_data::init_execute_at"); - - if (!item_execute_at) - DBUG_RETURN(0); - - if (item_execute_at->fix_fields(thd, &item_execute_at)) - goto wrong_value; - - /* no starts and/or ends in case of execute_at */ - DBUG_PRINT("info", ("starts_null && ends_null should be 1 is %d", - (starts_null && ends_null))); - DBUG_ASSERT(starts_null && ends_null); - - if ((not_used= item_execute_at->get_date(<ime, TIME_NO_ZERO_DATE))) - goto wrong_value; - - ltime_utc= TIME_to_timestamp(thd,<ime,¬_used); - if (!ltime_utc) - { - DBUG_PRINT("error", ("Execute AT after year 2037")); - goto wrong_value; - } - - check_if_in_the_past(thd, ltime_utc); - - execute_at_null= FALSE; - execute_at= ltime_utc; - DBUG_RETURN(0); - -wrong_value: - report_bad_value("AT", item_execute_at); - DBUG_RETURN(ER_WRONG_VALUE); -} - - -/* - Sets time for execution of multi-time event.s - - SYNOPSIS - Event_parse_data::init_interval() - thd Thread - - RETURN VALUE - 0 OK - EVEX_BAD_PARAMS Interval is not positive or MICROSECOND (reported) - ER_WRONG_VALUE Wrong value for interval (reported) -*/ - -int -Event_parse_data::init_interval(THD *thd) -{ - String value; - INTERVAL interval_tmp; - - DBUG_ENTER("Event_parse_data::init_interval"); - if (!item_expression) - DBUG_RETURN(0); - - switch (interval) { - case INTERVAL_MINUTE_MICROSECOND: - case INTERVAL_HOUR_MICROSECOND: - case INTERVAL_DAY_MICROSECOND: - case INTERVAL_SECOND_MICROSECOND: - case INTERVAL_MICROSECOND: - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND"); - DBUG_RETURN(EVEX_BAD_PARAMS); - default: - break; - } - - if (item_expression->fix_fields(thd, &item_expression)) - goto wrong_value; - - value.alloc(MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN); - if (get_interval_value(item_expression, interval, &value, &interval_tmp)) - goto wrong_value; - - expression= 0; - - switch (interval) { - case INTERVAL_YEAR: - expression= interval_tmp.year; - break; - case INTERVAL_QUARTER: - case INTERVAL_MONTH: - expression= interval_tmp.month; - break; - case INTERVAL_WEEK: - case INTERVAL_DAY: - expression= interval_tmp.day; - break; - case INTERVAL_HOUR: - expression= interval_tmp.hour; - break; - case INTERVAL_MINUTE: - expression= interval_tmp.minute; - break; - case INTERVAL_SECOND: - expression= interval_tmp.second; - break; - case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM - expression= interval_tmp.year* 12 + interval_tmp.month; - break; - case INTERVAL_DAY_HOUR: - expression= interval_tmp.day* 24 + interval_tmp.hour; - break; - case INTERVAL_DAY_MINUTE: - expression= (interval_tmp.day* 24 + interval_tmp.hour) * 60 + - interval_tmp.minute; - break; - case INTERVAL_HOUR_SECOND: /* day is anyway 0 */ - case INTERVAL_DAY_SECOND: - /* DAY_SECOND having problems because of leap seconds? */ - expression= ((interval_tmp.day* 24 + interval_tmp.hour) * 60 + - interval_tmp.minute)*60 - + interval_tmp.second; - break; - case INTERVAL_HOUR_MINUTE: - expression= interval_tmp.hour * 60 + interval_tmp.minute; - break; - case INTERVAL_MINUTE_SECOND: - expression= interval_tmp.minute * 60 + interval_tmp.second; - break; - case INTERVAL_LAST: - DBUG_ASSERT(0); - default: - ;/* these are the microsec stuff */ - } - if (interval_tmp.neg || expression == 0 || - expression > EVEX_MAX_INTERVAL_VALUE) - { - my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0)); - DBUG_RETURN(EVEX_BAD_PARAMS); - } - - DBUG_RETURN(0); - -wrong_value: - report_bad_value("INTERVAL", item_expression); - DBUG_RETURN(ER_WRONG_VALUE); -} - - -/* - Sets STARTS. - - SYNOPSIS - Event_parse_data::init_starts() - expr how much? - - NOTES - Note that activation time is not execution time. - EVERY 5 MINUTE STARTS "2004-12-12 10:00:00" means that - the event will be executed every 5 minutes but this will - start at the date shown above. Expressions are possible : - DATE_ADD(NOW(), INTERVAL 1 DAY) -- start tommorow at - same time. - - RETURN VALUE - 0 OK - ER_WRONG_VALUE Starts before now -*/ - -int -Event_parse_data::init_starts(THD *thd) -{ - my_bool not_used; - MYSQL_TIME ltime; - my_time_t ltime_utc; - - DBUG_ENTER("Event_parse_data::init_starts"); - if (!item_starts) - DBUG_RETURN(0); - - if (item_starts->fix_fields(thd, &item_starts)) - goto wrong_value; - - if ((not_used= item_starts->get_date(<ime, TIME_NO_ZERO_DATE))) - goto wrong_value; - - ltime_utc= TIME_to_timestamp(thd, <ime, ¬_used); - if (!ltime_utc) - goto wrong_value; - - DBUG_PRINT("info",("now: %ld starts: %ld", - (long) thd->query_start(), (long) ltime_utc)); - - starts_null= FALSE; - starts= ltime_utc; - DBUG_RETURN(0); - -wrong_value: - report_bad_value("STARTS", item_starts); - DBUG_RETURN(ER_WRONG_VALUE); -} - - -/* - Sets ENDS (deactivation time). - - SYNOPSIS - Event_parse_data::init_ends() - thd THD - - NOTES - Note that activation time is not execution time. - EVERY 5 MINUTE ENDS "2004-12-12 10:00:00" means that - the event will be executed every 5 minutes but this will - end at the date shown above. Expressions are possible : - DATE_ADD(NOW(), INTERVAL 1 DAY) -- end tommorow at - same time. - - RETURN VALUE - 0 OK - EVEX_BAD_PARAMS Error (reported) -*/ - -int -Event_parse_data::init_ends(THD *thd) -{ - my_bool not_used; - MYSQL_TIME ltime; - my_time_t ltime_utc; - - DBUG_ENTER("Event_parse_data::init_ends"); - if (!item_ends) - DBUG_RETURN(0); - - if (item_ends->fix_fields(thd, &item_ends)) - goto error_bad_params; - - DBUG_PRINT("info", ("convert to TIME")); - if ((not_used= item_ends->get_date(<ime, TIME_NO_ZERO_DATE))) - goto error_bad_params; - - ltime_utc= TIME_to_timestamp(thd, <ime, ¬_used); - if (!ltime_utc) - goto error_bad_params; - - /* Check whether ends is after starts */ - DBUG_PRINT("info", ("ENDS after STARTS?")); - if (!starts_null && starts >= ltime_utc) - goto error_bad_params; - - check_if_in_the_past(thd, ltime_utc); - - ends_null= FALSE; - ends= ltime_utc; - DBUG_RETURN(0); - -error_bad_params: - my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0)); - DBUG_RETURN(EVEX_BAD_PARAMS); -} - - -/* - Prints an error message about invalid value. Internally used - during input data verification - - SYNOPSIS - Event_parse_data::report_bad_value() - item_name The name of the parameter - bad_item The parameter -*/ - -void -Event_parse_data::report_bad_value(const char *item_name, Item *bad_item) -{ - char buff[120]; - String str(buff,(uint32) sizeof(buff), system_charset_info); - String *str2= bad_item->fixed? bad_item->val_str(&str):NULL; - my_error(ER_WRONG_VALUE, MYF(0), item_name, str2? str2->c_ptr_safe():"NULL"); -} - - -/* - Checks for validity the data gathered during the parsing phase. - - SYNOPSIS - Event_parse_data::check_parse_data() - thd Thread - - RETURN VALUE - FALSE OK - TRUE Error (reported) -*/ - -bool -Event_parse_data::check_parse_data(THD *thd) -{ - bool ret; - DBUG_ENTER("Event_parse_data::check_parse_data"); - DBUG_PRINT("info", ("execute_at: 0x%lx expr=0x%lx starts=0x%lx ends=0x%lx", - (long) item_execute_at, (long) item_expression, - (long) item_starts, (long) item_ends)); - - init_name(thd, identifier); - - init_definer(thd); - - ret= init_execute_at(thd) || init_interval(thd) || init_starts(thd) || - init_ends(thd); - check_originator_id(thd); - DBUG_RETURN(ret); -} - - -/* - Inits definer (definer_user and definer_host) during parsing. - - SYNOPSIS - Event_parse_data::init_definer() - thd Thread -*/ - -void -Event_parse_data::init_definer(THD *thd) -{ - DBUG_ENTER("Event_parse_data::init_definer"); - - 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; - - 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")); - definer.length= definer_user_len + definer_host_len + 1; - definer.str= (char*) thd->alloc(definer.length + 1); - - DBUG_PRINT("info",("copy the user")); - 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, definer_host, definer_host_len); - definer.str[definer.length]= '\0'; - DBUG_PRINT("info",("definer [%s] initted", definer.str)); - - DBUG_VOID_RETURN; -} - - -/** - Set the originator id of the event to the server_id if executing on - the master or set to the server_id of the master if executing on - the slave. If executing on slave, also set status to SLAVESIDE_DISABLED. - - SYNOPSIS - Event_parse_data::check_originator_id() -*/ -void Event_parse_data::check_originator_id(THD *thd) -{ - /* Disable replicated events on slave. */ - if ((thd->system_thread == SYSTEM_THREAD_SLAVE_SQL) || - (thd->system_thread == SYSTEM_THREAD_SLAVE_IO)) - { - DBUG_PRINT("info", ("Invoked object status set to SLAVESIDE_DISABLED.")); - if ((status == Event_basic::ENABLED) || - (status == Event_basic::DISABLED)) - status = Event_basic::SLAVESIDE_DISABLED; - originator = thd->server_id; - } - else - originator = server_id; -} - - -/* Constructor SYNOPSIS @@ -799,8 +279,9 @@ Event_basic::load_time_zone(THD *thd, const LEX_STRING tz_name) Event_queue_element::Event_queue_element(): status_changed(FALSE), last_executed_changed(FALSE), - on_completion(ON_COMPLETION_DROP), status(ENABLED), - expression(0), dropped(FALSE), execution_count(0) + on_completion(Event_parse_data::ON_COMPLETION_DROP), + status(Event_parse_data::ENABLED), expression(0), dropped(FALSE), + execution_count(0) { DBUG_ENTER("Event_queue_element::Event_queue_element"); @@ -1057,14 +538,14 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table) switch (ptr[0]) { case 'E' : - status = Event_queue_element::ENABLED; + status = Event_parse_data::ENABLED; break; case 'S' : - status = Event_queue_element::SLAVESIDE_DISABLED; + status = Event_parse_data::SLAVESIDE_DISABLED; break; case 'D' : default: - status = Event_queue_element::DISABLED; + status = Event_parse_data::DISABLED; break; } if ((ptr= get_field(&mem_root, table->field[ET_FIELD_ORIGINATOR])) == NullS) @@ -1076,8 +557,8 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table) table->field[ET_FIELD_ON_COMPLETION])) == NullS) DBUG_RETURN(TRUE); - on_completion= (ptr[0]=='D'? Event_queue_element::ON_COMPLETION_DROP: - Event_queue_element::ON_COMPLETION_PRESERVE); + on_completion= (ptr[0]=='D'? Event_parse_data::ON_COMPLETION_DROP: + Event_parse_data::ON_COMPLETION_PRESERVE); DBUG_RETURN(FALSE); } @@ -1422,7 +903,7 @@ Event_queue_element::compute_next_execution_time() (long) starts, (long) ends, (long) last_executed, (long) this)); - if (status != Event_queue_element::ENABLED) + if (status != Event_parse_data::ENABLED) { DBUG_PRINT("compute_next_execution_time", ("Event %s is DISABLED", name.str)); @@ -1436,10 +917,10 @@ Event_queue_element::compute_next_execution_time() { DBUG_PRINT("info",("One-time event %s.%s of was already executed", dbname.str, name.str)); - dropped= (on_completion == Event_queue_element::ON_COMPLETION_DROP); + dropped= (on_completion == Event_parse_data::ON_COMPLETION_DROP); DBUG_PRINT("info",("One-time event will be dropped: %d.", dropped)); - status= Event_queue_element::DISABLED; + status= Event_parse_data::DISABLED; status_changed= TRUE; } goto ret; @@ -1456,10 +937,10 @@ Event_queue_element::compute_next_execution_time() /* time_now is after ends. don't execute anymore */ execute_at= 0; execute_at_null= TRUE; - if (on_completion == Event_queue_element::ON_COMPLETION_DROP) + if (on_completion == Event_parse_data::ON_COMPLETION_DROP) dropped= TRUE; DBUG_PRINT("info", ("Dropped: %d", dropped)); - status= Event_queue_element::DISABLED; + status= Event_parse_data::DISABLED; status_changed= TRUE; goto ret; @@ -1520,9 +1001,9 @@ Event_queue_element::compute_next_execution_time() /* Next execution after ends. No more executions */ execute_at= 0; execute_at_null= TRUE; - if (on_completion == Event_queue_element::ON_COMPLETION_DROP) + if (on_completion == Event_parse_data::ON_COMPLETION_DROP) dropped= TRUE; - status= Event_queue_element::DISABLED; + status= Event_parse_data::DISABLED; status_changed= TRUE; } else @@ -1612,9 +1093,9 @@ Event_queue_element::compute_next_execution_time() DBUG_PRINT("info", ("Next execution after ENDS. Stop executing.")); execute_at= 0; execute_at_null= TRUE; - status= Event_queue_element::DISABLED; + status= Event_parse_data::DISABLED; status_changed= TRUE; - if (on_completion == Event_queue_element::ON_COMPLETION_DROP) + if (on_completion == Event_parse_data::ON_COMPLETION_DROP) dropped= TRUE; } else @@ -1766,14 +1247,14 @@ Event_timed::get_create_event(THD *thd, String *buf) STRING_WITH_LEN("ON SCHEDULE AT")); } - if (on_completion == Event_timed::ON_COMPLETION_DROP) + if (on_completion == Event_parse_data::ON_COMPLETION_DROP) buf->append(STRING_WITH_LEN(" ON COMPLETION NOT PRESERVE ")); else buf->append(STRING_WITH_LEN(" ON COMPLETION PRESERVE ")); - if (status == Event_timed::ENABLED) + if (status == Event_parse_data::ENABLED) buf->append(STRING_WITH_LEN("ENABLE")); - else if (status == Event_timed::SLAVESIDE_DISABLED) + else if (status == Event_parse_data::SLAVESIDE_DISABLED) buf->append(STRING_WITH_LEN("DISABLE ON SLAVE")); else buf->append(STRING_WITH_LEN("DISABLE")); @@ -1957,10 +1438,10 @@ Event_job_data::execute(THD *thd, bool drop) thd->query_length= sp_sql.length(); { - Lex_input_stream lip(thd, thd->query, thd->query_length); + Parser_state parser_state(thd, thd->query, thd->query_length); lex_start(thd); - if (parse_sql(thd, &lip, creation_ctx)) + if (parse_sql(thd, & parser_state, creation_ctx)) { sql_print_error("Event Scheduler: " "%serror during compilation of %s.%s", diff --git a/sql/event_data_objects.h b/sql/event_data_objects.h index 7a49d1597d6..e32077b9c97 100644 --- a/sql/event_data_objects.h +++ b/sql/event_data_objects.h @@ -22,10 +22,7 @@ @file event_data_objects.h */ -#define EVEX_GET_FIELD_FAILED -2 -#define EVEX_BAD_PARAMS -5 -#define EVEX_MICROSECOND_UNSUP -6 - +#include "event_parse_data.h" class Event_queue_element_for_exec { @@ -54,23 +51,6 @@ protected: MEM_ROOT mem_root; public: - /* - ENABLED = feature can function normally (is turned on) - SLAVESIDE_DISABLED = feature is turned off on slave - DISABLED = feature is turned off - */ - enum enum_status - { - ENABLED = 1, - DISABLED, - SLAVESIDE_DISABLED - }; - - enum enum_on_completion - { - ON_COMPLETION_DROP = 1, - ON_COMPLETION_PRESERVE - }; LEX_STRING dbname; LEX_STRING name; @@ -201,83 +181,6 @@ private: }; -class Event_parse_data : public Sql_alloc -{ -public: - - int on_completion; - int status; - longlong originator; - /* - do_not_create will be set if STARTS time is in the past and - on_completion == ON_COMPLETION_DROP. - */ - bool do_not_create; - - bool body_changed; - - LEX_STRING dbname; - LEX_STRING name; - LEX_STRING definer;// combination of user and host - LEX_STRING comment; - - Item* item_starts; - Item* item_ends; - Item* item_execute_at; - - my_time_t starts; - my_time_t ends; - my_time_t execute_at; - my_bool starts_null; - my_bool ends_null; - my_bool execute_at_null; - - sp_name *identifier; - Item* item_expression; - longlong expression; - interval_type interval; - - static Event_parse_data * - new_instance(THD *thd); - - bool - check_parse_data(THD *thd); - -private: - - void - init_definer(THD *thd); - - void - init_name(THD *thd, sp_name *spn); - - int - init_execute_at(THD *thd); - - int - init_interval(THD *thd); - - int - init_starts(THD *thd); - - int - init_ends(THD *thd); - - Event_parse_data(); - ~Event_parse_data(); - - void - report_bad_value(const char *item_name, Item *bad_item); - - void - check_if_in_the_past(THD *thd, my_time_t ltime_utc); - - Event_parse_data(const Event_parse_data &); /* Prevent use of these */ - void check_originator_id(THD *thd); - void operator=(Event_parse_data &); -}; - - /* Compares only the schema part of the identifier */ bool event_basic_db_equal(LEX_STRING db, Event_basic *et); diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 401f76f5d26..382fd024aa8 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -452,7 +452,7 @@ Event_db_repository::table_scan_all_for_i_s(THD *thd, TABLE *schema_table, READ_RECORD read_record_info; DBUG_ENTER("Event_db_repository::table_scan_all_for_i_s"); - init_read_record(&read_record_info, thd, event_table, NULL, 1, 0); + init_read_record(&read_record_info, thd, event_table, NULL, 1, 0, FALSE); /* rr_sequential, in read_record(), returns 137==HA_ERR_END_OF_FILE, @@ -925,7 +925,7 @@ Event_db_repository::drop_events_by_field(THD *thd, DBUG_VOID_RETURN; /* only enabled events are in memory, so we go now and delete the rest */ - init_read_record(&read_record_info, thd, table, NULL, 1, 0); + init_read_record(&read_record_info, thd, table, NULL, 1, 0, FALSE); while (!ret && !(read_record_info.read_record(&read_record_info)) ) { char *et_field= get_field(thd->mem_root, table->field[field]); diff --git a/sql/event_parse_data.cc b/sql/event_parse_data.cc new file mode 100644 index 00000000000..e87e4593f8f --- /dev/null +++ b/sql/event_parse_data.cc @@ -0,0 +1,535 @@ +/* Copyright (C) 2000-2003 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 */ + +#include "mysql_priv.h" +#include "sp_head.h" +#include "event_parse_data.h" + +/* + Returns a new instance + + SYNOPSIS + Event_parse_data::new_instance() + + RETURN VALUE + Address or NULL in case of error + + NOTE + Created on THD's mem_root +*/ + +Event_parse_data * +Event_parse_data::new_instance(THD *thd) +{ + return new (thd->mem_root) Event_parse_data; +} + + +/* + Constructor + + SYNOPSIS + Event_parse_data::Event_parse_data() +*/ + +Event_parse_data::Event_parse_data() + :on_completion(Event_parse_data::ON_COMPLETION_DROP), + status(Event_parse_data::ENABLED), + do_not_create(FALSE), + body_changed(FALSE), + item_starts(NULL), item_ends(NULL), item_execute_at(NULL), + starts_null(TRUE), ends_null(TRUE), execute_at_null(TRUE), + item_expression(NULL), expression(0) +{ + DBUG_ENTER("Event_parse_data::Event_parse_data"); + + /* Actually in the parser STARTS is always set */ + starts= ends= execute_at= 0; + + comment.str= NULL; + comment.length= 0; + + DBUG_VOID_RETURN; +} + + +/* + Set a name of the event + + SYNOPSIS + Event_parse_data::init_name() + thd THD + spn the name extracted in the parser +*/ + +void +Event_parse_data::init_name(THD *thd, sp_name *spn) +{ + DBUG_ENTER("Event_parse_data::init_name"); + + /* We have to copy strings to get them into the right memroot */ + dbname.length= spn->m_db.length; + dbname.str= thd->strmake(spn->m_db.str, spn->m_db.length); + name.length= spn->m_name.length; + name.str= thd->strmake(spn->m_name.str, spn->m_name.length); + + if (spn->m_qname.length == 0) + spn->init_qname(thd); + + DBUG_VOID_RETURN; +} + + +/* + This function is called on CREATE EVENT or ALTER EVENT. When either + ENDS or AT is in the past, we are trying to create an event that + will never be executed. If it has ON COMPLETION NOT PRESERVE + (default), then it would normally be dropped already, so on CREATE + EVENT we give a warning, and do not create anyting. On ALTER EVENT + we give a error, and do not change the event. + + If the event has ON COMPLETION PRESERVE, then we see if the event is + created or altered to the ENABLED (default) state. If so, then we + give a warning, and change the state to DISABLED. + + Otherwise it is a valid event in ON COMPLETION PRESERVE DISABLE + state. +*/ + +void +Event_parse_data::check_if_in_the_past(THD *thd, my_time_t ltime_utc) +{ + if (ltime_utc >= (my_time_t) thd->query_start()) + return; + + if (on_completion == Event_parse_data::ON_COMPLETION_DROP) + { + switch (thd->lex->sql_command) { + case SQLCOM_CREATE_EVENT: + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_EVENT_CANNOT_CREATE_IN_THE_PAST, + ER(ER_EVENT_CANNOT_CREATE_IN_THE_PAST)); + break; + case SQLCOM_ALTER_EVENT: + my_error(ER_EVENT_CANNOT_ALTER_IN_THE_PAST, MYF(0)); + break; + default: + DBUG_ASSERT(0); + } + + do_not_create= TRUE; + } + else if (status == Event_parse_data::ENABLED) + { + status= Event_parse_data::DISABLED; + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_EVENT_EXEC_TIME_IN_THE_PAST, + ER(ER_EVENT_EXEC_TIME_IN_THE_PAST)); + } +} + + +/* + Sets time for execution for one-time event. + + SYNOPSIS + Event_parse_data::init_execute_at() + thd Thread + + RETURN VALUE + 0 OK + ER_WRONG_VALUE Wrong value for execute at (reported) +*/ + +int +Event_parse_data::init_execute_at(THD *thd) +{ + my_bool not_used; + MYSQL_TIME ltime; + my_time_t ltime_utc; + + DBUG_ENTER("Event_parse_data::init_execute_at"); + + if (!item_execute_at) + DBUG_RETURN(0); + + if (item_execute_at->fix_fields(thd, &item_execute_at)) + goto wrong_value; + + /* no starts and/or ends in case of execute_at */ + DBUG_PRINT("info", ("starts_null && ends_null should be 1 is %d", + (starts_null && ends_null))); + DBUG_ASSERT(starts_null && ends_null); + + if ((not_used= item_execute_at->get_date(<ime, TIME_NO_ZERO_DATE))) + goto wrong_value; + + ltime_utc= TIME_to_timestamp(thd,<ime,¬_used); + if (!ltime_utc) + { + DBUG_PRINT("error", ("Execute AT after year 2037")); + goto wrong_value; + } + + check_if_in_the_past(thd, ltime_utc); + + execute_at_null= FALSE; + execute_at= ltime_utc; + DBUG_RETURN(0); + +wrong_value: + report_bad_value("AT", item_execute_at); + DBUG_RETURN(ER_WRONG_VALUE); +} + + +/* + Sets time for execution of multi-time event.s + + SYNOPSIS + Event_parse_data::init_interval() + thd Thread + + RETURN VALUE + 0 OK + EVEX_BAD_PARAMS Interval is not positive or MICROSECOND (reported) + ER_WRONG_VALUE Wrong value for interval (reported) +*/ + +int +Event_parse_data::init_interval(THD *thd) +{ + String value; + INTERVAL interval_tmp; + + DBUG_ENTER("Event_parse_data::init_interval"); + if (!item_expression) + DBUG_RETURN(0); + + switch (interval) { + case INTERVAL_MINUTE_MICROSECOND: + case INTERVAL_HOUR_MICROSECOND: + case INTERVAL_DAY_MICROSECOND: + case INTERVAL_SECOND_MICROSECOND: + case INTERVAL_MICROSECOND: + my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND"); + DBUG_RETURN(EVEX_BAD_PARAMS); + default: + break; + } + + if (item_expression->fix_fields(thd, &item_expression)) + goto wrong_value; + + value.alloc(MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN); + if (get_interval_value(item_expression, interval, &value, &interval_tmp)) + goto wrong_value; + + expression= 0; + + switch (interval) { + case INTERVAL_YEAR: + expression= interval_tmp.year; + break; + case INTERVAL_QUARTER: + case INTERVAL_MONTH: + expression= interval_tmp.month; + break; + case INTERVAL_WEEK: + case INTERVAL_DAY: + expression= interval_tmp.day; + break; + case INTERVAL_HOUR: + expression= interval_tmp.hour; + break; + case INTERVAL_MINUTE: + expression= interval_tmp.minute; + break; + case INTERVAL_SECOND: + expression= interval_tmp.second; + break; + case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM + expression= interval_tmp.year* 12 + interval_tmp.month; + break; + case INTERVAL_DAY_HOUR: + expression= interval_tmp.day* 24 + interval_tmp.hour; + break; + case INTERVAL_DAY_MINUTE: + expression= (interval_tmp.day* 24 + interval_tmp.hour) * 60 + + interval_tmp.minute; + break; + case INTERVAL_HOUR_SECOND: /* day is anyway 0 */ + case INTERVAL_DAY_SECOND: + /* DAY_SECOND having problems because of leap seconds? */ + expression= ((interval_tmp.day* 24 + interval_tmp.hour) * 60 + + interval_tmp.minute)*60 + + interval_tmp.second; + break; + case INTERVAL_HOUR_MINUTE: + expression= interval_tmp.hour * 60 + interval_tmp.minute; + break; + case INTERVAL_MINUTE_SECOND: + expression= interval_tmp.minute * 60 + interval_tmp.second; + break; + case INTERVAL_LAST: + DBUG_ASSERT(0); + default: + ;/* these are the microsec stuff */ + } + if (interval_tmp.neg || expression == 0 || + expression > EVEX_MAX_INTERVAL_VALUE) + { + my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0)); + DBUG_RETURN(EVEX_BAD_PARAMS); + } + + DBUG_RETURN(0); + +wrong_value: + report_bad_value("INTERVAL", item_expression); + DBUG_RETURN(ER_WRONG_VALUE); +} + + +/* + Sets STARTS. + + SYNOPSIS + Event_parse_data::init_starts() + expr how much? + + NOTES + Note that activation time is not execution time. + EVERY 5 MINUTE STARTS "2004-12-12 10:00:00" means that + the event will be executed every 5 minutes but this will + start at the date shown above. Expressions are possible : + DATE_ADD(NOW(), INTERVAL 1 DAY) -- start tommorow at + same time. + + RETURN VALUE + 0 OK + ER_WRONG_VALUE Starts before now +*/ + +int +Event_parse_data::init_starts(THD *thd) +{ + my_bool not_used; + MYSQL_TIME ltime; + my_time_t ltime_utc; + + DBUG_ENTER("Event_parse_data::init_starts"); + if (!item_starts) + DBUG_RETURN(0); + + if (item_starts->fix_fields(thd, &item_starts)) + goto wrong_value; + + if ((not_used= item_starts->get_date(<ime, TIME_NO_ZERO_DATE))) + goto wrong_value; + + ltime_utc= TIME_to_timestamp(thd, <ime, ¬_used); + if (!ltime_utc) + goto wrong_value; + + DBUG_PRINT("info",("now: %ld starts: %ld", + (long) thd->query_start(), (long) ltime_utc)); + + starts_null= FALSE; + starts= ltime_utc; + DBUG_RETURN(0); + +wrong_value: + report_bad_value("STARTS", item_starts); + DBUG_RETURN(ER_WRONG_VALUE); +} + + +/* + Sets ENDS (deactivation time). + + SYNOPSIS + Event_parse_data::init_ends() + thd THD + + NOTES + Note that activation time is not execution time. + EVERY 5 MINUTE ENDS "2004-12-12 10:00:00" means that + the event will be executed every 5 minutes but this will + end at the date shown above. Expressions are possible : + DATE_ADD(NOW(), INTERVAL 1 DAY) -- end tommorow at + same time. + + RETURN VALUE + 0 OK + EVEX_BAD_PARAMS Error (reported) +*/ + +int +Event_parse_data::init_ends(THD *thd) +{ + my_bool not_used; + MYSQL_TIME ltime; + my_time_t ltime_utc; + + DBUG_ENTER("Event_parse_data::init_ends"); + if (!item_ends) + DBUG_RETURN(0); + + if (item_ends->fix_fields(thd, &item_ends)) + goto error_bad_params; + + DBUG_PRINT("info", ("convert to TIME")); + if ((not_used= item_ends->get_date(<ime, TIME_NO_ZERO_DATE))) + goto error_bad_params; + + ltime_utc= TIME_to_timestamp(thd, <ime, ¬_used); + if (!ltime_utc) + goto error_bad_params; + + /* Check whether ends is after starts */ + DBUG_PRINT("info", ("ENDS after STARTS?")); + if (!starts_null && starts >= ltime_utc) + goto error_bad_params; + + check_if_in_the_past(thd, ltime_utc); + + ends_null= FALSE; + ends= ltime_utc; + DBUG_RETURN(0); + +error_bad_params: + my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0)); + DBUG_RETURN(EVEX_BAD_PARAMS); +} + + +/* + Prints an error message about invalid value. Internally used + during input data verification + + SYNOPSIS + Event_parse_data::report_bad_value() + item_name The name of the parameter + bad_item The parameter +*/ + +void +Event_parse_data::report_bad_value(const char *item_name, Item *bad_item) +{ + char buff[120]; + String str(buff,(uint32) sizeof(buff), system_charset_info); + String *str2= bad_item->fixed? bad_item->val_str(&str):NULL; + my_error(ER_WRONG_VALUE, MYF(0), item_name, str2? str2->c_ptr_safe():"NULL"); +} + + +/* + Checks for validity the data gathered during the parsing phase. + + SYNOPSIS + Event_parse_data::check_parse_data() + thd Thread + + RETURN VALUE + FALSE OK + TRUE Error (reported) +*/ + +bool +Event_parse_data::check_parse_data(THD *thd) +{ + bool ret; + DBUG_ENTER("Event_parse_data::check_parse_data"); + DBUG_PRINT("info", ("execute_at: 0x%lx expr=0x%lx starts=0x%lx ends=0x%lx", + (long) item_execute_at, (long) item_expression, + (long) item_starts, (long) item_ends)); + + init_name(thd, identifier); + + init_definer(thd); + + ret= init_execute_at(thd) || init_interval(thd) || init_starts(thd) || + init_ends(thd); + check_originator_id(thd); + DBUG_RETURN(ret); +} + + +/* + Inits definer (definer_user and definer_host) during parsing. + + SYNOPSIS + Event_parse_data::init_definer() + thd Thread +*/ + +void +Event_parse_data::init_definer(THD *thd) +{ + DBUG_ENTER("Event_parse_data::init_definer"); + + 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; + + 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")); + definer.length= definer_user_len + definer_host_len + 1; + definer.str= (char*) thd->alloc(definer.length + 1); + + DBUG_PRINT("info",("copy the user")); + 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, definer_host, definer_host_len); + definer.str[definer.length]= '\0'; + DBUG_PRINT("info",("definer [%s] initted", definer.str)); + + DBUG_VOID_RETURN; +} + + +/** + Set the originator id of the event to the server_id if executing on + the master or set to the server_id of the master if executing on + the slave. If executing on slave, also set status to SLAVESIDE_DISABLED. + + SYNOPSIS + Event_parse_data::check_originator_id() +*/ +void Event_parse_data::check_originator_id(THD *thd) +{ + /* Disable replicated events on slave. */ + if ((thd->system_thread == SYSTEM_THREAD_SLAVE_SQL) || + (thd->system_thread == SYSTEM_THREAD_SLAVE_IO)) + { + DBUG_PRINT("info", ("Invoked object status set to SLAVESIDE_DISABLED.")); + if ((status == Event_parse_data::ENABLED) || + (status == Event_parse_data::DISABLED)) + status = Event_parse_data::SLAVESIDE_DISABLED; + originator = thd->server_id; + } + else + originator = server_id; +} diff --git a/sql/event_parse_data.h b/sql/event_parse_data.h new file mode 100644 index 00000000000..221bf92664f --- /dev/null +++ b/sql/event_parse_data.h @@ -0,0 +1,116 @@ +/* Copyright (C) 2000-2003 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 */ + +#ifndef _EVENT_PARSE_DATA_H_ +#define _EVENT_PARSE_DATA_H_ + +#define EVEX_GET_FIELD_FAILED -2 +#define EVEX_BAD_PARAMS -5 +#define EVEX_MICROSECOND_UNSUP -6 +#define EVEX_MAX_INTERVAL_VALUE 1000000000L + +class Event_parse_data : public Sql_alloc +{ +public: + /* + ENABLED = feature can function normally (is turned on) + SLAVESIDE_DISABLED = feature is turned off on slave + DISABLED = feature is turned off + */ + enum enum_status + { + ENABLED = 1, + DISABLED, + SLAVESIDE_DISABLED + }; + + enum enum_on_completion + { + ON_COMPLETION_DROP = 1, + ON_COMPLETION_PRESERVE + }; + + int on_completion; + int status; + longlong originator; + /* + do_not_create will be set if STARTS time is in the past and + on_completion == ON_COMPLETION_DROP. + */ + bool do_not_create; + + bool body_changed; + + LEX_STRING dbname; + LEX_STRING name; + LEX_STRING definer;// combination of user and host + LEX_STRING comment; + + Item* item_starts; + Item* item_ends; + Item* item_execute_at; + + my_time_t starts; + my_time_t ends; + my_time_t execute_at; + my_bool starts_null; + my_bool ends_null; + my_bool execute_at_null; + + sp_name *identifier; + Item* item_expression; + longlong expression; + interval_type interval; + + static Event_parse_data * + new_instance(THD *thd); + + bool + check_parse_data(THD *thd); + +private: + + void + init_definer(THD *thd); + + void + init_name(THD *thd, sp_name *spn); + + int + init_execute_at(THD *thd); + + int + init_interval(THD *thd); + + int + init_starts(THD *thd); + + int + init_ends(THD *thd); + + Event_parse_data(); + ~Event_parse_data(); + + void + report_bad_value(const char *item_name, Item *bad_item); + + void + check_if_in_the_past(THD *thd, my_time_t ltime_utc); + + Event_parse_data(const Event_parse_data &); /* Prevent use of these */ + void check_originator_id(THD *thd); + void operator=(Event_parse_data &); +}; +#endif diff --git a/sql/event_queue.cc b/sql/event_queue.cc index 719a837cbfb..04d4f858b43 100644 --- a/sql/event_queue.cc +++ b/sql/event_queue.cc @@ -65,10 +65,10 @@ int event_queue_element_compare_q(void *vptr, uchar* a, uchar *b) my_time_t lhs = left->execute_at; my_time_t rhs = right->execute_at; - if (left->status == Event_queue_element::DISABLED) - return right->status != Event_queue_element::DISABLED; + if (left->status == Event_parse_data::DISABLED) + return right->status != Event_parse_data::DISABLED; - if (right->status == Event_queue_element::DISABLED) + if (right->status == Event_parse_data::DISABLED) return 1; return (lhs < rhs ? -1 : (lhs > rhs ? 1 : 0)); @@ -198,7 +198,7 @@ Event_queue::create_event(THD *thd, Event_queue_element *new_element, /* Will do nothing if the event is disabled */ new_element->compute_next_execution_time(); - if (new_element->status != Event_queue_element::ENABLED) + if (new_element->status != Event_parse_data::ENABLED) { delete new_element; *created= FALSE; @@ -236,8 +236,8 @@ Event_queue::update_event(THD *thd, LEX_STRING dbname, LEX_STRING name, DBUG_ENTER("Event_queue::update_event"); DBUG_PRINT("enter", ("thd: 0x%lx et=[%s.%s]", (long) thd, dbname.str, name.str)); - if ((new_element->status == Event_queue_element::DISABLED) || - (new_element->status == Event_queue_element::SLAVESIDE_DISABLED)) + if ((new_element->status == Event_parse_data::DISABLED) || + (new_element->status == Event_parse_data::SLAVESIDE_DISABLED)) { DBUG_PRINT("info", ("The event is disabled.")); /* @@ -452,7 +452,7 @@ Event_queue::recalculate_activation_times(THD *thd) for (i= queue.elements; i > 0; i--) { Event_queue_element *element = (Event_queue_element*)queue_element(&queue, i - 1); - if (element->status != Event_queue_element::DISABLED) + if (element->status != Event_parse_data::DISABLED) break; /* This won't cause queue re-order, because we remove @@ -615,14 +615,14 @@ Event_queue::get_top_for_execution_if_time(THD *thd, DBUG_PRINT("info", ("Ready for execution")); top->mark_last_executed(thd); if (top->compute_next_execution_time()) - top->status= Event_queue_element::DISABLED; + top->status= Event_parse_data::DISABLED; DBUG_PRINT("info", ("event %s status is %d", top->name.str, top->status)); top->execution_count++; (*event_name)->dropped= top->dropped; top->update_timing_fields(thd); - if (top->status == Event_queue_element::DISABLED) + if (top->status == Event_parse_data::DISABLED) { DBUG_PRINT("info", ("removing from the queue")); sql_print_information("Event Scheduler: Last execution of %s.%s. %s", diff --git a/sql/events.cc b/sql/events.cc index 309b6b1ac71..df49b7db773 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -860,6 +860,7 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) bool Events::init(my_bool opt_noacl) { + THD *thd; bool res= FALSE; @@ -953,7 +954,6 @@ end: DBUG_RETURN(res); } - /* Cleans up scheduler's resources. Called at server shutdown. @@ -1148,7 +1148,7 @@ Events::load_events_from_db(THD *thd) DBUG_RETURN(TRUE); } - init_read_record(&read_record_info, thd, table, NULL, 0, 1); + init_read_record(&read_record_info, thd, table, NULL, 0, 1, FALSE); while (!(read_record_info.read_record(&read_record_info))) { Event_queue_element *et; @@ -1169,7 +1169,7 @@ Events::load_events_from_db(THD *thd) goto end; } drop_on_completion= (et->on_completion == - Event_queue_element::ON_COMPLETION_DROP); + Event_parse_data::ON_COMPLETION_DROP); if (event_queue->create_event(thd, et, &created)) diff --git a/sql/field.cc b/sql/field.cc index cac5a117b8d..6af2ea97b2d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -27,6 +27,8 @@ #include "mysql_priv.h" #include "sql_select.h" +#include "rpl_rli.h" // Pull in Relay_log_info +#include "slave.h" // Pull in rpl_master_has_bug() #include <m_ctype.h> #include <errno.h> #ifdef HAVE_FCONVERT @@ -1375,7 +1377,8 @@ bool Field::send_binary(Protocol *protocol) @retval 0 if this field's size is < the source field's size @retval 1 if this field's size is >= the source field's size */ -int Field::compatible_field_size(uint field_metadata) +int Field::compatible_field_size(uint field_metadata, + const Relay_log_info *rli_arg __attribute__((unused))) { uint const source_size= pack_length_from_metadata(field_metadata); uint const destination_size= row_pack_length(); @@ -2837,7 +2840,8 @@ uint Field_new_decimal::pack_length_from_metadata(uint field_metadata) @retval 0 if this field's size is < the source field's size @retval 1 if this field's size is >= the source field's size */ -int Field_new_decimal::compatible_field_size(uint field_metadata) +int Field_new_decimal::compatible_field_size(uint field_metadata, + const Relay_log_info * __attribute__((unused))) { int compatible= 0; uint const source_precision= (field_metadata >> 8U) & 0x00ff; @@ -4037,7 +4041,6 @@ Field_real::pack(uchar *to, const uchar *from, { DBUG_ENTER("Field_real::pack"); DBUG_ASSERT(max_length >= pack_length()); - DBUG_PRINT("debug", ("pack_length(): %u", pack_length())); #ifdef WORDS_BIGENDIAN if (low_byte_first != table->s->db_low_byte_first) { @@ -4056,7 +4059,6 @@ Field_real::unpack(uchar *to, const uchar *from, uint param_data, bool low_byte_first) { DBUG_ENTER("Field_real::unpack"); - DBUG_PRINT("debug", ("pack_length(): %u", pack_length())); #ifdef WORDS_BIGENDIAN if (low_byte_first != table->s->db_low_byte_first) { @@ -6326,6 +6328,7 @@ check_string_copy_error(Field_str *field, Field_longstr::report_if_important_data() ptr - Truncated rest of string end - End of truncated string + count_spaces - Treat traling spaces as important data RETURN VALUES 0 - None was truncated (or we don't count cut fields) @@ -6335,10 +6338,12 @@ check_string_copy_error(Field_str *field, Check if we lost any important data (anything in a binary string, or any non-space in others). If only trailing spaces was lost, send a truncation note, otherwise send a truncation error. + Silently ignore traling spaces if the count_space parameter is FALSE. */ int -Field_longstr::report_if_important_data(const char *ptr, const char *end) +Field_longstr::report_if_important_data(const char *ptr, const char *end, + bool count_spaces) { if ((ptr < end) && table->in_use->count_cuted_fields) { @@ -6348,10 +6353,13 @@ Field_longstr::report_if_important_data(const char *ptr, const char *end) set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); else set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + return 2; } - else /* If we lost only spaces then produce a NOTE, not a WARNING */ + else if (count_spaces) + { /* If we lost only spaces then produce a NOTE, not a WARNING */ set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); - return 2; + return 2; + } } return 0; } @@ -6388,7 +6396,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) cannot_convert_error_pos, from + length, cs)) return 2; - return report_if_important_data(from_end_pos, from + length); + return report_if_important_data(from_end_pos, from + length, FALSE); } @@ -6630,6 +6638,37 @@ my_decimal *Field_string::val_decimal(my_decimal *decimal_value) } +struct Check_field_param { + Field *field; +}; + +#ifdef HAVE_REPLICATION +static bool +check_field_for_37426(const void *param_arg) +{ + Check_field_param *param= (Check_field_param*) param_arg; + DBUG_ASSERT(param->field->real_type() == MYSQL_TYPE_STRING); + DBUG_PRINT("debug", ("Field %s - type: %d, size: %d", + param->field->field_name, + param->field->real_type(), + param->field->row_pack_length())); + return param->field->row_pack_length() > 255; +} +#endif + +int Field_string::compatible_field_size(uint field_metadata, + const Relay_log_info *rli_arg) +{ +#ifdef HAVE_REPLICATION + const Check_field_param check_param = { this }; + if (rpl_master_has_bug(rli_arg, 37426, TRUE, + check_field_for_37426, &check_param)) + return FALSE; // Not compatible field sizes +#endif + return Field::compatible_field_size(field_metadata, rli_arg); +} + + int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr) { uint a_len, b_len; @@ -6716,6 +6755,9 @@ uchar *Field_string::pack(uchar *to, const uchar *from, @c param_data argument contains the result of field->real_type() from the master. + @note For information about how the length is packed, see @c + Field_string::do_save_field_metadata + @param to Destination of the data @param from Source of the data @param param_data Real type (upper) and length (lower) values @@ -6728,10 +6770,24 @@ Field_string::unpack(uchar *to, uint param_data, bool low_byte_first __attribute__((unused))) { - uint from_length= - param_data ? min(param_data & 0x00ff, field_length) : field_length; - uint length; + uint from_length, length; + + /* + Compute the declared length of the field on the master. This is + used to decide if one or two bytes should be read as length. + */ + if (param_data) + from_length= (((param_data >> 4) & 0x300) ^ 0x300) + (param_data & 0x00ff); + else + from_length= field_length; + DBUG_PRINT("debug", + ("param_data: 0x%x, field_length: %u, from_length: %u", + param_data, field_length, from_length)); + /* + Compute the actual length of the data by reading one or two bits + (depending on the declared field length on the master). + */ if (from_length > 255) { length= uint2korr(from); @@ -6754,14 +6810,37 @@ Field_string::unpack(uchar *to, second byte of the field metadata array at index of *metadata_ptr and *(metadata_ptr + 1). + @note In order to be able to handle lengths exceeding 255 and be + backwards-compatible with pre-5.1.26 servers, an extra two bits of + the length has been added to the metadata in such a way that if + they are set, a new unrecognized type is generated. This will + cause pre-5.1-26 servers to stop due to a field type mismatch, + while new servers will be able to extract the extra bits. If the + length is <256, there will be no difference and both a new and an + old server will be able to handle it. + + @note The extra two bits are added to bits 13 and 14 of the + parameter data (with 1 being the least siginficant bit and 16 the + most significant bit of the word) by xoring the extra length bits + with the real type. Since all allowable types have 0xF as most + significant bits of the metadata word, lengths <256 will not affect + the real type at all, while all other values will result in a + non-existant type in the range 17-244. + + @see Field_string::unpack + @param metadata_ptr First byte of field metadata @returns number of bytes written to metadata_ptr */ int Field_string::do_save_field_metadata(uchar *metadata_ptr) { - *metadata_ptr= real_type(); - *(metadata_ptr + 1)= field_length; + DBUG_ASSERT(field_length < 1024); + DBUG_ASSERT((real_type() & 0xF0) == 0xF0); + DBUG_PRINT("debug", ("field_length: %u, real_type: %u", + field_length, real_type())); + *metadata_ptr= (real_type() ^ ((field_length & 0x300) >> 4)); + *(metadata_ptr + 1)= field_length & 0xFF; return 2; } @@ -6963,7 +7042,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) cannot_convert_error_pos, from + length, cs)) return 2; - return report_if_important_data(from_end_pos, from + length); + return report_if_important_data(from_end_pos, from + length, TRUE); } @@ -7566,6 +7645,7 @@ uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg, bool low_by return (uint32) tmp; } } + /* When expanding this, see also MAX_FIELD_BLOBLENGTH. */ return 0; // Impossible } @@ -7666,7 +7746,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) cannot_convert_error_pos, from + length, cs)) return 2; - return report_if_important_data(from_end_pos, from + length); + return report_if_important_data(from_end_pos, from + length, TRUE); oom_error: /* Fatal OOM error */ @@ -9109,7 +9189,8 @@ uint Field_bit::pack_length_from_metadata(uint field_metadata) @retval 0 if this field's size is < the source field's size @retval 1 if this field's size is >= the source field's size */ -int Field_bit::compatible_field_size(uint field_metadata) +int Field_bit::compatible_field_size(uint field_metadata, + const Relay_log_info * __attribute__((unused))) { int compatible= 0; uint const source_size= pack_length_from_metadata(field_metadata); @@ -9447,8 +9528,20 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, (fld_type_modifier & NOT_NULL_FLAG) && fld_type != MYSQL_TYPE_TIMESTAMP) flags|= NO_DEFAULT_VALUE_FLAG; - if (fld_length && !(length= (uint) atoi(fld_length))) - fld_length= 0; /* purecov: inspected */ + if (fld_length != NULL) + { + errno= 0; + length= strtoul(fld_length, NULL, 10); + if ((errno != 0) || (length > MAX_FIELD_BLOBLENGTH)) + { + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), fld_name, MAX_FIELD_BLOBLENGTH); + DBUG_RETURN(TRUE); + } + + if (length == 0) + fld_length= 0; /* purecov: inspected */ + } + sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1; switch (fld_type) { @@ -9596,7 +9689,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, } break; case MYSQL_TYPE_TIMESTAMP: - if (!fld_length) + if (fld_length == NULL) { /* Compressed date YYYYMMDDHHMMSS */ length= MAX_DATETIME_COMPRESSED_WIDTH; @@ -9605,12 +9698,21 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, { /* We support only even TIMESTAMP lengths less or equal than 14 - and 19 as length of 4.1 compatible representation. + and 19 as length of 4.1 compatible representation. Silently + shrink it to MAX_DATETIME_COMPRESSED_WIDTH. */ - length= ((length+1)/2)*2; /* purecov: inspected */ - length= min(length, MAX_DATETIME_COMPRESSED_WIDTH); /* purecov: inspected */ + DBUG_ASSERT(MAX_DATETIME_COMPRESSED_WIDTH < UINT_MAX); + if (length != UINT_MAX) /* avoid overflow; is safe because of min() */ + length= ((length+1)/2)*2; + length= min(length, MAX_DATETIME_COMPRESSED_WIDTH); } flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; + /* + Since we silently rewrite down to MAX_DATETIME_COMPRESSED_WIDTH bytes, + the parser should not raise errors unless bizzarely large. + */ + max_field_charlength= UINT_MAX; + if (fld_default_value) { /* Grammar allows only NOW() value for ON UPDATE clause */ @@ -9716,7 +9818,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, ((length > max_field_charlength && fld_type != MYSQL_TYPE_SET && fld_type != MYSQL_TYPE_ENUM && (fld_type != MYSQL_TYPE_VARCHAR || fld_default_value)) || - (!length && + ((length == 0) && fld_type != MYSQL_TYPE_STRING && fld_type != MYSQL_TYPE_VARCHAR && fld_type != MYSQL_TYPE_GEOMETRY))) { diff --git a/sql/field.h b/sql/field.h index 61ad2c39235..6152cfccaba 100644 --- a/sql/field.h +++ b/sql/field.h @@ -13,7 +13,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - /* Because of the function new_field() all field classes that have static variables must declare the size_of() member function. @@ -30,6 +29,8 @@ const uint32 max_field_size= (uint32) 4294967295U; class Send_field; class Protocol; class Create_field; +class Relay_log_info; + struct st_cache_field; int field_conv(Field *to,Field *from); @@ -49,7 +50,8 @@ class Field Field(const Item &); /* Prevent use of these */ void operator=(Field &); public: - static void *operator new(size_t size) {return sql_alloc(size); } + static void *operator new(size_t size) throw () + { return sql_alloc(size); } static void operator delete(void *ptr_arg, size_t size) { TRASH(ptr_arg, size); } uchar *ptr; // Position to field in record @@ -145,7 +147,7 @@ public: virtual bool eq(Field *field) { return (ptr == field->ptr && null_ptr == field->null_ptr && - null_bit == field->null_bit); + null_bit == field->null_bit && field->type() == type()); } virtual bool eq_def(Field *field); @@ -162,7 +164,8 @@ public: table, which is located on disk). */ virtual uint32 pack_length_in_rec() const { return pack_length(); } - virtual int compatible_field_size(uint field_metadata); + virtual int compatible_field_size(uint field_metadata, + const Relay_log_info *); virtual uint pack_length_from_metadata(uint field_metadata) { return field_metadata; } /* @@ -529,6 +532,77 @@ private: */ virtual int do_save_field_metadata(uchar *metadata_ptr) { return 0; } + +protected: + /* + Helper function to pack()/unpack() int32 values + */ + static void handle_int32(uchar *to, const uchar *from, + bool low_byte_first_from, bool low_byte_first_to) + { + int32 val; +#ifdef WORDS_BIGENDIAN + if (low_byte_first_from) + val = sint4korr(from); + else +#endif + longget(val, from); + +#ifdef WORDS_BIGENDIAN + if (low_byte_first_to) + int4store(to, val); + else +#endif + longstore(to, val); + } + + /* + Helper function to pack()/unpack() int64 values + */ + static void handle_int64(uchar* to, const uchar *from, + bool low_byte_first_from, bool low_byte_first_to) + { + int64 val; +#ifdef WORDS_BIGENDIAN + if (low_byte_first_from) + val = sint8korr(from); + else +#endif + longlongget(val, from); + +#ifdef WORDS_BIGENDIAN + if (low_byte_first_to) + int8store(to, val); + else +#endif + longlongstore(to, val); + } + + uchar *pack_int32(uchar *to, const uchar *from, bool low_byte_first_to) + { + handle_int32(to, from, table->s->db_low_byte_first, low_byte_first_to); + return to + sizeof(int32); + } + + const uchar *unpack_int32(uchar* to, const uchar *from, + bool low_byte_first_from) + { + handle_int32(to, from, low_byte_first_from, table->s->db_low_byte_first); + return from + sizeof(int32); + } + + uchar *pack_int64(uchar* to, const uchar *from, bool low_byte_first_to) + { + handle_int64(to, from, table->s->db_low_byte_first, low_byte_first_to); + return to + sizeof(int64); + } + + const uchar *unpack_int64(uchar* to, const uchar *from, + bool low_byte_first_from) + { + handle_int64(to, from, low_byte_first_from, table->s->db_low_byte_first); + return from + sizeof(int64); + } }; @@ -594,7 +668,8 @@ public: class Field_longstr :public Field_str { protected: - int report_if_important_data(const char *ptr, const char *end); + int report_if_important_data(const char *ptr, const char *end, + bool count_spaces); public: Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, @@ -715,7 +790,8 @@ public: uint32 pack_length() const { return (uint32) bin_size; } uint pack_length_from_metadata(uint field_metadata); uint row_pack_length() { return pack_length(); } - int compatible_field_size(uint field_metadata); + int compatible_field_size(uint field_metadata, + const Relay_log_info *rli); uint is_equal(Create_field *new_field); virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data, bool low_byte_first); @@ -915,43 +991,16 @@ public: void sql_type(String &str) const; uint32 max_display_length() { return MY_INT32_NUM_DECIMAL_DIGITS; } virtual uchar *pack(uchar* to, const uchar *from, - uint max_length, bool low_byte_first) + uint max_length __attribute__((unused)), + bool low_byte_first) { - int32 val; -#ifdef WORDS_BIGENDIAN - if (table->s->db_low_byte_first) - val = sint4korr(from); - else -#endif - longget(val, from); - -#ifdef WORDS_BIGENDIAN - if (low_byte_first) - int4store(to, val); - else -#endif - longstore(to, val); - return to + sizeof(val); + return pack_int32(to, from, low_byte_first); } - virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data, bool low_byte_first) + uint param_data __attribute__((unused)), + bool low_byte_first) { - int32 val; -#ifdef WORDS_BIGENDIAN - if (low_byte_first) - val = sint4korr(from); - else -#endif - longget(val, from); - -#ifdef WORDS_BIGENDIAN - if (table->s->db_low_byte_first) - int4store(to, val); - else -#endif - longstore(to, val); - return from + sizeof(val); + return unpack_int32(to, from, low_byte_first); } }; @@ -996,43 +1045,16 @@ public: bool can_be_compared_as_longlong() const { return TRUE; } uint32 max_display_length() { return 20; } virtual uchar *pack(uchar* to, const uchar *from, - uint max_length, bool low_byte_first) + uint max_length __attribute__((unused)), + bool low_byte_first) { - int64 val; -#ifdef WORDS_BIGENDIAN - if (table->s->db_low_byte_first) - val = sint8korr(from); - else -#endif - longlongget(val, from); - -#ifdef WORDS_BIGENDIAN - if (low_byte_first) - int8store(to, val); - else -#endif - longlongstore(to, val); - return to + sizeof(val); + return pack_int64(to, from, low_byte_first); } - virtual const uchar *unpack(uchar* to, const uchar *from, - uint param_data, bool low_byte_first) + uint param_data __attribute__((unused)), + bool low_byte_first) { - int64 val; -#ifdef WORDS_BIGENDIAN - if (low_byte_first) - val = sint8korr(from); - else -#endif - longlongget(val, from); - -#ifdef WORDS_BIGENDIAN - if (table->s->db_low_byte_first) - int8store(to, val); - else -#endif - longlongstore(to, val); - return from + sizeof(val); + return unpack_int64(to, from, low_byte_first); } }; #endif @@ -1206,6 +1228,17 @@ public: bool get_date(MYSQL_TIME *ltime,uint fuzzydate); bool get_time(MYSQL_TIME *ltime); timestamp_auto_set_type get_auto_set_type() const; + uchar *pack(uchar *to, const uchar *from, + uint max_length __attribute__((unused)), bool low_byte_first) + { + return pack_int32(to, from, low_byte_first); + } + const uchar *unpack(uchar* to, const uchar *from, + uint param_data __attribute__((unused)), + bool low_byte_first) + { + return unpack_int32(to, from, low_byte_first); + } }; @@ -1260,6 +1293,17 @@ public: void sql_type(String &str) const; bool can_be_compared_as_longlong() const { return TRUE; } bool zero_pack() const { return 1; } + uchar *pack(uchar* to, const uchar *from, + uint max_length __attribute__((unused)), bool low_byte_first) + { + return pack_int32(to, from, low_byte_first); + } + const uchar *unpack(uchar* to, const uchar *from, + uint param_data __attribute__((unused)), + bool low_byte_first) + { + return unpack_int32(to, from, low_byte_first); + } }; @@ -1373,6 +1417,17 @@ public: bool zero_pack() const { return 1; } bool get_date(MYSQL_TIME *ltime,uint fuzzydate); bool get_time(MYSQL_TIME *ltime); + uchar *pack(uchar* to, const uchar *from, + uint max_length __attribute__((unused)), bool low_byte_first) + { + return pack_int64(to, from, low_byte_first); + } + const uchar *unpack(uchar* to, const uchar *from, + uint param_data __attribute__((unused)), + bool low_byte_first) + { + return unpack_int64(to, from, low_byte_first); + } }; @@ -1424,7 +1479,14 @@ public: virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data, bool low_byte_first); uint pack_length_from_metadata(uint field_metadata) - { return (field_metadata & 0x00ff); } + { + DBUG_PRINT("debug", ("field_metadata: 0x%04x", field_metadata)); + if (field_metadata == 0) + return row_pack_length(); + return (((field_metadata >> 4) & 0x300) ^ 0x300) + (field_metadata & 0x00ff); + } + int compatible_field_size(uint field_metadata, + const Relay_log_info *rli); uint row_pack_length() { return (field_length + 1); } int pack_cmp(const uchar *a,const uchar *b,uint key_length, my_bool insert_or_update); @@ -1607,6 +1669,7 @@ public: } int reset(void) { bzero(ptr, packlength+sizeof(uchar*)); return 0; } void reset_fields() { bzero((uchar*) &value,sizeof(value)); } + uint32 get_field_buffer_size(void) { return value.alloced_length(); } #ifndef WORDS_BIGENDIAN static #endif @@ -1877,7 +1940,8 @@ public: uint pack_length_from_metadata(uint field_metadata); uint row_pack_length() { return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); } - int compatible_field_size(uint field_metadata); + int compatible_field_size(uint field_metadata, + const Relay_log_info *rli); void sql_type(String &str) const; virtual uchar *pack(uchar *to, const uchar *from, uint max_length, bool low_byte_first); @@ -1896,7 +1960,6 @@ public: bool eq(Field *field) { return (Field::eq(field) && - field->type() == type() && bit_ptr == ((Field_bit *)field)->bit_ptr && bit_ofs == ((Field_bit *)field)->bit_ofs); } diff --git a/sql/filesort.cc b/sql/filesort.cc index 66a1bf87d25..0ddb9ae5b10 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -410,6 +410,56 @@ static uchar *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count, DBUG_RETURN(tmp); } +#ifndef DBUG_OFF +/* + Print a text, SQL-like record representation into dbug trace. + + Note: this function is a work in progress: at the moment + - column read bitmap is ignored (can print garbage for unused columns) + - there is no quoting +*/ +static void dbug_print_record(TABLE *table, bool print_rowid) +{ + char buff[1024]; + Field **pfield; + String tmp(buff,sizeof(buff),&my_charset_bin); + DBUG_LOCK_FILE; + + fprintf(DBUG_FILE, "record ("); + for (pfield= table->field; *pfield ; pfield++) + fprintf(DBUG_FILE, "%s%s", (*pfield)->field_name, (pfield[1])? ", ":""); + fprintf(DBUG_FILE, ") = "); + + fprintf(DBUG_FILE, "("); + for (pfield= table->field; *pfield ; pfield++) + { + Field *field= *pfield; + + if (field->is_null()) + fwrite("NULL", sizeof(char), 4, DBUG_FILE); + + if (field->type() == MYSQL_TYPE_BIT) + (void) field->val_int_as_str(&tmp, 1); + else + field->val_str(&tmp); + + fwrite(tmp.ptr(),sizeof(char),tmp.length(),DBUG_FILE); + if (pfield[1]) + fwrite(", ", sizeof(char), 2, DBUG_FILE); + } + fprintf(DBUG_FILE, ")"); + if (print_rowid) + { + fprintf(DBUG_FILE, " rowid "); + for (uint i=0; i < table->file->ref_length; i++) + { + fprintf(DBUG_FILE, "%x", (uchar)table->file->ref[i]); + } + } + fprintf(DBUG_FILE, "\n"); + DBUG_UNLOCK_FILE; +} +#endif /** Search after sort_keys and write them into tempfile. @@ -488,13 +538,10 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, current_thd->variables.read_buff_size); } - READ_RECORD read_record_info; if (quick_select) { if (select->quick->reset()) DBUG_RETURN(HA_POS_ERROR); - init_read_record(&read_record_info, current_thd, select->quick->head, - select, 1, 1); } /* Remember original bitmaps */ @@ -514,12 +561,13 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, { if (quick_select) { - if ((error= read_record_info.read_record(&read_record_info))) + if ((error= select->quick->get_next())) { error= HA_ERR_END_OF_FILE; break; } file->position(sort_form->record[0]); + DBUG_EXECUTE_IF("debug_filesort", dbug_print_record(sort_form, TRUE);); } else /* Not quick-select */ { @@ -576,15 +624,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, if (thd->is_error()) break; } - if (quick_select) - { - /* - index_merge quick select uses table->sort when retrieving rows, so free - resoures it has allocated. - */ - end_read_record(&read_record_info); - } - else + if (!quick_select) { (void) file->extra(HA_EXTRA_NO_CACHE); /* End cacheing of records */ if (!next_pos) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index b239253fbc7..0eb36be2f3b 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -593,6 +593,12 @@ int ha_partition::drop_partitions(const char *path) int error= 0; DBUG_ENTER("ha_partition::drop_partitions"); + /* + Assert that it works without HA_FILE_BASED and lower_case_table_name = 2. + We use m_file[0] as long as all partitions have the same storage engine. + */ + DBUG_ASSERT(!strcmp(path, get_canonical_filename(m_file[0], path, + part_name_buff))); do { partition_element *part_elem= part_it++; @@ -682,6 +688,13 @@ int ha_partition::rename_partitions(const char *path) partition_element *part_elem, *sub_elem; DBUG_ENTER("ha_partition::rename_partitions"); + /* + Assert that it works without HA_FILE_BASED and lower_case_table_name = 2. + We use m_file[0] as long as all partitions have the same storage engine. + */ + DBUG_ASSERT(!strcmp(path, get_canonical_filename(m_file[0], path, + norm_name_buff))); + if (temp_partitions) { /* @@ -841,6 +854,9 @@ int ha_partition::rename_partitions(const char *path) #define CHECK_PARTS 3 #define REPAIR_PARTS 4 +static const char *opt_op_name[]= {NULL, + "optimize", "analyze", "check", "repair" }; + /* Optimize table @@ -858,8 +874,10 @@ int ha_partition::optimize(THD *thd, HA_CHECK_OPT *check_opt) { DBUG_ENTER("ha_partition::optimize"); - DBUG_RETURN(handle_opt_partitions(thd, &thd->lex->check_opt, - OPTIMIZE_PARTS, TRUE)); + DBUG_RETURN(handle_opt_partitions(thd, check_opt, + OPTIMIZE_PARTS, + thd->lex->alter_info.flags & + ALTER_OPTIMIZE_PARTITION ? FALSE : TRUE)); } @@ -880,8 +898,10 @@ int ha_partition::analyze(THD *thd, HA_CHECK_OPT *check_opt) { DBUG_ENTER("ha_partition::analyze"); - DBUG_RETURN(handle_opt_partitions(thd, &thd->lex->check_opt, - ANALYZE_PARTS, TRUE)); + DBUG_RETURN(handle_opt_partitions(thd, check_opt, + ANALYZE_PARTS, + thd->lex->alter_info.flags & + ALTER_ANALYZE_PARTITION ? FALSE : TRUE)); } @@ -902,8 +922,10 @@ int ha_partition::check(THD *thd, HA_CHECK_OPT *check_opt) { DBUG_ENTER("ha_partition::check"); - DBUG_RETURN(handle_opt_partitions(thd, &thd->lex->check_opt, - CHECK_PARTS, TRUE)); + DBUG_RETURN(handle_opt_partitions(thd, check_opt, + CHECK_PARTS, + thd->lex->alter_info.flags & + ALTER_CHECK_PARTITION ? FALSE : TRUE)); } @@ -924,96 +946,13 @@ int ha_partition::repair(THD *thd, HA_CHECK_OPT *check_opt) { DBUG_ENTER("ha_partition::repair"); - DBUG_RETURN(handle_opt_partitions(thd, &thd->lex->check_opt, - REPAIR_PARTS, TRUE)); -} - -/* - Optimize partitions - - SYNOPSIS - optimize_partitions() - thd Thread object - RETURN VALUE - >0 Failure - 0 Success - DESCRIPTION - Call optimize on each partition marked with partition state PART_CHANGED -*/ - -int ha_partition::optimize_partitions(THD *thd) -{ - DBUG_ENTER("ha_partition::optimize_partitions"); - - DBUG_RETURN(handle_opt_partitions(thd, &thd->lex->check_opt, - OPTIMIZE_PARTS, FALSE)); -} - -/* - Analyze partitions - - SYNOPSIS - analyze_partitions() - thd Thread object - RETURN VALUE - >0 Failure - 0 Success - DESCRIPTION - Call analyze on each partition marked with partition state PART_CHANGED -*/ - -int ha_partition::analyze_partitions(THD *thd) -{ - DBUG_ENTER("ha_partition::analyze_partitions"); - - DBUG_RETURN(handle_opt_partitions(thd, &thd->lex->check_opt, - ANALYZE_PARTS, FALSE)); + DBUG_RETURN(handle_opt_partitions(thd, check_opt, + REPAIR_PARTS, + thd->lex->alter_info.flags & + ALTER_REPAIR_PARTITION ? FALSE : TRUE)); } /* - Check partitions - - SYNOPSIS - check_partitions() - thd Thread object - RETURN VALUE - >0 Failure - 0 Success - DESCRIPTION - Call check on each partition marked with partition state PART_CHANGED -*/ - -int ha_partition::check_partitions(THD *thd) -{ - DBUG_ENTER("ha_partition::check_partitions"); - - DBUG_RETURN(handle_opt_partitions(thd, &thd->lex->check_opt, - CHECK_PARTS, FALSE)); -} - -/* - Repair partitions - - SYNOPSIS - repair_partitions() - thd Thread object - RETURN VALUE - >0 Failure - 0 Success - DESCRIPTION - Call repair on each partition marked with partition state PART_CHANGED -*/ - -int ha_partition::repair_partitions(THD *thd) -{ - DBUG_ENTER("ha_partition::repair_partitions"); - - DBUG_RETURN(handle_opt_partitions(thd, &thd->lex->check_opt, - REPAIR_PARTS, FALSE)); -} - - -/* Handle optimize/analyze/check/repair of one partition SYNOPSIS @@ -1028,7 +967,6 @@ int ha_partition::repair_partitions(THD *thd) 0 Success */ -#ifdef WL4176_IS_DONE static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, handler *file, uint flag) { @@ -1036,12 +974,6 @@ static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, DBUG_ENTER("handle_opt_part"); DBUG_PRINT("enter", ("flag = %u", flag)); - /* - TODO: - Rewrite the code for ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION WL4176 - */ - DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); - if (flag == OPTIMIZE_PARTS) error= file->ha_optimize(thd, check_opt); else if (flag == ANALYZE_PARTS) @@ -1059,7 +991,59 @@ static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, error= 0; DBUG_RETURN(error); } -#endif + + +/* + print a message row formatted for ANALYZE/CHECK/OPTIMIZE/REPAIR TABLE + (modelled after mi_check_print_msg) + TODO: move this into the handler, or rewrite mysql_admin_table. +*/ +static bool print_admin_msg(THD* thd, const char* msg_type, + const char* db_name, const char* table_name, + const char* op_name, const char *fmt, ...) +{ + va_list args; + Protocol *protocol= thd->protocol; + uint length, msg_length; + char msgbuf[HA_MAX_MSG_BUF]; + char name[NAME_LEN*2+2]; + + va_start(args, fmt); + msg_length= my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); + va_end(args); + msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia + + + if (!thd->vio_ok()) + { + sql_print_error(msgbuf); + return TRUE; + } + + length=(uint) (strxmov(name, db_name, ".", table_name,NullS) - name); + /* + TODO: switch from protocol to push_warning here. The main reason we didn't + it yet is parallel repair. Due to following trace: + mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr. + + Also we likely need to lock mutex here (in both cases with protocol and + push_warning). + */ + DBUG_PRINT("info",("print_admin_msg: %s, %s, %s, %s", name, op_name, + msg_type, msgbuf)); + protocol->prepare_for_resend(); + protocol->store(name, length, system_charset_info); + protocol->store(op_name, system_charset_info); + protocol->store(msg_type, system_charset_info); + protocol->store(msgbuf, msg_length, system_charset_info); + if (protocol->write()) + { + sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n", + msgbuf); + return TRUE; + } + return FALSE; +} /* @@ -1080,55 +1064,152 @@ static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, uint flag, bool all_parts) { -#ifdef WL4176_IS_DONE List_iterator<partition_element> part_it(m_part_info->partitions); uint no_parts= m_part_info->no_parts; uint no_subparts= m_part_info->no_subparts; uint i= 0; int error; -#endif DBUG_ENTER("ha_partition::handle_opt_partitions"); DBUG_PRINT("enter", ("all_parts %u, flag= %u", all_parts, flag)); - /* - TODO: - Rewrite the code for ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION WL4176 - */ - DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); -#ifdef WL4176_IS_DONE do { partition_element *part_elem= part_it++; - if (all_parts || part_elem->part_state == PART_CHANGED) + /* + when ALTER TABLE <CMD> PARTITION ... + it should only do named partitions, otherwise all partitions + */ + if (all_parts || + part_elem->part_state == PART_CHANGED) { if (m_is_sub_partitioned) { + List_iterator<partition_element> subpart_it(part_elem->subpartitions); + partition_element *sub_elem; uint j= 0, part; do { + sub_elem= subpart_it++; part= i * no_subparts + j; - DBUG_PRINT("info", ("Optimize subpartition %u", - part)); + DBUG_PRINT("info", ("Optimize subpartition %u (%s)", + part, sub_elem->partition_name)); +#ifdef NOT_USED + if (print_admin_msg(thd, "note", table_share->db.str, table->alias, + opt_op_name[flag], + "Start to operate on subpartition %s", + sub_elem->partition_name)) + DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR); +#endif if ((error= handle_opt_part(thd, check_opt, m_file[part], flag))) { + /* print a line which partition the error belongs to */ + if (error != HA_ADMIN_NOT_IMPLEMENTED && + error != HA_ADMIN_ALREADY_DONE && + error != HA_ADMIN_TRY_ALTER) + { + print_admin_msg(thd, "error", table_share->db.str, table->alias, + opt_op_name[flag], + "Subpartition %s returned error", + sub_elem->partition_name); + } DBUG_RETURN(error); } } while (++j < no_subparts); } else { - DBUG_PRINT("info", ("Optimize partition %u", i)); + DBUG_PRINT("info", ("Optimize partition %u (%s)", i, + part_elem->partition_name)); +#ifdef NOT_USED + if (print_admin_msg(thd, "note", table_share->db.str, table->alias, + opt_op_name[flag], + "Start to operate on partition %s", + part_elem->partition_name)) + DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR); +#endif if ((error= handle_opt_part(thd, check_opt, m_file[i], flag))) { + /* print a line which partition the error belongs to */ + if (error != HA_ADMIN_NOT_IMPLEMENTED && + error != HA_ADMIN_ALREADY_DONE && + error != HA_ADMIN_TRY_ALTER) + { + print_admin_msg(thd, "error", table_share->db.str, table->alias, + opt_op_name[flag], "Partition %s returned error", + part_elem->partition_name); + } DBUG_RETURN(error); } } } } while (++i < no_parts); DBUG_RETURN(FALSE); -#endif } + +/** + @brief Check and repair the table if neccesary + + @param thd Thread object + + @retval TRUE Error/Not supported + @retval FALSE Success +*/ + +bool ha_partition::check_and_repair(THD *thd) +{ + handler **file= m_file; + DBUG_ENTER("ha_partition::check_and_repair"); + + do + { + if ((*file)->ha_check_and_repair(thd)) + DBUG_RETURN(TRUE); + } while (*(++file)); + DBUG_RETURN(FALSE); +} + + +/** + @breif Check if the table can be automatically repaired + + @retval TRUE Can be auto repaired + @retval FALSE Cannot be auto repaired +*/ + +bool ha_partition::auto_repair() const +{ + DBUG_ENTER("ha_partition::auto_repair"); + + /* + As long as we only support one storage engine per table, + we can use the first partition for this function. + */ + DBUG_RETURN(m_file[0]->auto_repair()); +} + + +/** + @breif Check if the table is crashed + + @retval TRUE Crashed + @retval FALSE Not crashed +*/ + +bool ha_partition::is_crashed() const +{ + handler **file= m_file; + DBUG_ENTER("ha_partition::is_crashed"); + + do + { + if ((*file)->is_crashed()) + DBUG_RETURN(TRUE); + } while (*(++file)); + DBUG_RETURN(FALSE); +} + + /* Prepare by creating a new partition @@ -1276,6 +1357,12 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, THD *thd= current_thd; DBUG_ENTER("ha_partition::change_partitions"); + /* + Assert that it works without HA_FILE_BASED and lower_case_table_name = 2. + We use m_file[0] as long as all partitions have the same storage engine. + */ + DBUG_ASSERT(!strcmp(path, get_canonical_filename(m_file[0], path, + part_name_buff))); m_reorged_parts= 0; if (!m_part_info->is_sub_partitioned()) no_subparts= 1; @@ -1708,8 +1795,11 @@ uint ha_partition::del_ren_cre_table(const char *from, { int save_error= 0; int error; - char from_buff[FN_REFLEN], to_buff[FN_REFLEN]; + char from_buff[FN_REFLEN], to_buff[FN_REFLEN], from_lc_buff[FN_REFLEN], + to_lc_buff[FN_REFLEN]; char *name_buffer_ptr; + const char *from_path; + const char *to_path= NULL; uint i; handler **file, **abort_file; DBUG_ENTER("del_ren_cre_table()"); @@ -1717,17 +1807,29 @@ uint ha_partition::del_ren_cre_table(const char *from, if (get_from_handler_file(from, current_thd->mem_root)) DBUG_RETURN(TRUE); DBUG_ASSERT(m_file_buffer); + DBUG_PRINT("enter", ("from: (%s) to: (%s)", from, to)); name_buffer_ptr= m_name_buffer_ptr; file= m_file; + /* + Since ha_partition has HA_FILE_BASED, it must alter underlying table names + if they do not have HA_FILE_BASED and lower_case_table_names == 2. + See Bug#37402, for Mac OS X. + The appended #P#<partname>[#SP#<subpartname>] will remain in current case. + Using the first partitions handler, since mixing handlers is not allowed. + */ + from_path= get_canonical_filename(*file, from, from_lc_buff); + if (to != NULL) + to_path= get_canonical_filename(*file, to, to_lc_buff); i= 0; do { - create_partition_name(from_buff, from, name_buffer_ptr, NORMAL_PART_NAME, - FALSE); + create_partition_name(from_buff, from_path, name_buffer_ptr, + NORMAL_PART_NAME, FALSE); + if (to != NULL) { // Rename branch - create_partition_name(to_buff, to, name_buffer_ptr, NORMAL_PART_NAME, - FALSE); + create_partition_name(to_buff, to_path, name_buffer_ptr, + NORMAL_PART_NAME, FALSE); error= (*file)->ha_rename_table(from_buff, to_buff); } else if (table_arg == NULL) // delete branch @@ -1749,7 +1851,7 @@ create_error: name_buffer_ptr= m_name_buffer_ptr; for (abort_file= file, file= m_file; file < abort_file; file++) { - create_partition_name(from_buff, from, name_buffer_ptr, NORMAL_PART_NAME, + create_partition_name(from_buff, from_path, name_buffer_ptr, NORMAL_PART_NAME, FALSE); VOID((*file)->ha_delete_table((const char*) from_buff)); name_buffer_ptr= strend(name_buffer_ptr) + 1; @@ -2392,6 +2494,8 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) err_handler: while (file-- != m_file) (*file)->close(); + if (!is_clone) + bitmap_free(&(m_part_info->used_partitions)); DBUG_RETURN(error); } @@ -2724,6 +2828,7 @@ int ha_partition::write_row(uchar * buf) bool autoincrement_lock= FALSE; my_bitmap_map *old_map; THD *thd= ha_thd(); + timestamp_auto_set_type orig_timestamp_type= table->timestamp_field_type; #ifdef NOT_NEEDED uchar *rec0= m_rec0; #endif @@ -2733,6 +2838,7 @@ int ha_partition::write_row(uchar * buf) /* If we have a timestamp column, update it to the current time */ if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) table->timestamp_field->set_time(); + table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; /* If we have an auto_increment column and we are writing a changed row @@ -2799,6 +2905,7 @@ int ha_partition::write_row(uchar * buf) error= m_file[part_id]->ha_write_row(buf); reenable_binlog(thd); exit: + table->timestamp_field_type= orig_timestamp_type; if (autoincrement_lock) pthread_mutex_unlock(&table_share->mutex); DBUG_RETURN(error); @@ -2851,10 +2958,8 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data) inside m_file[*]->update_row() methods */ if (orig_timestamp_type & TIMESTAMP_AUTO_SET_ON_UPDATE) - { table->timestamp_field->set_time(); - table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; - } + table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; if ((error= get_parts_for_update(old_data, new_data, table->record[0], m_part_info, &old_part_id, &new_part_id, @@ -3285,6 +3390,8 @@ int ha_partition::rnd_next(uchar *buf) result= HA_ERR_END_OF_FILE; break; } + m_last_part= part_id; + m_part_spec.start_part= part_id; file= m_file[part_id]; DBUG_PRINT("info", ("rnd_init on partition %d", part_id)); if ((result= file->ha_rnd_init(1))) @@ -4046,7 +4153,7 @@ int ha_partition::handle_unordered_next(uchar *buf, bool is_next_same) } else if (!(error= file->index_next(buf))) { - if (!(file->ha_table_flags() & HA_READ_ORDER) || + if (!(file->index_flags(active_index, 0, 1) & HA_READ_ORDER) || compare_key(end_range) <= 0) { m_last_part= m_part_spec.start_part; @@ -4124,7 +4231,7 @@ int ha_partition::handle_unordered_scan_next_partition(uchar * buf) } if (!error) { - if (!(file->ha_table_flags() & HA_READ_ORDER) || + if (!(file->index_flags(active_index, 0, 1) & HA_READ_ORDER) || compare_key(end_range) <= 0) { m_last_part= i; @@ -5364,6 +5471,34 @@ ha_rows ha_partition::estimate_rows_upper_bound() } +/** + Number of rows in table. see handler.h + + SYNOPSIS + records() + + RETURN VALUE + Number of total rows in a partitioned table. +*/ + +ha_rows ha_partition::records() +{ + ha_rows rows, tot_rows= 0; + handler **file; + DBUG_ENTER("ha_partition::records"); + + file= m_file; + do + { + rows= (*file)->records(); + if (rows == HA_POS_ERROR) + DBUG_RETURN(HA_POS_ERROR); + tot_rows+= rows; + } while (*(++file)); + DBUG_RETURN(tot_rows); +} + + /* Is it ok to switch to a new engine for this table diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 5a8caaeb209..99e3cb50a8f 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -531,6 +531,7 @@ public: underlying handlers must have the same implementation for it to work. */ virtual uint8 table_cache_type(); + virtual ha_rows records(); /* ------------------------------------------------------------------------- @@ -931,10 +932,9 @@ public: virtual int analyze(THD* thd, HA_CHECK_OPT *check_opt); virtual int check(THD* thd, HA_CHECK_OPT *check_opt); virtual int repair(THD* thd, HA_CHECK_OPT *check_opt); - virtual int optimize_partitions(THD *thd); - virtual int analyze_partitions(THD *thd); - virtual int check_partitions(THD *thd); - virtual int repair_partitions(THD *thd); + virtual bool check_and_repair(THD *thd); + virtual bool auto_repair() const; + virtual bool is_crashed() const; private: int handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, @@ -950,12 +950,9 @@ public: virtual int restore(THD* thd, HA_CHECK_OPT *check_opt); virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt); virtual int preload_keys(THD *thd, HA_CHECK_OPT *check_opt); - virtual bool check_and_repair(THD *thd); virtual int dump(THD* thd, int fd = -1); virtual int net_read_dump(NET* net); virtual uint checksum() const; - virtual bool is_crashed() const; - virtual bool auto_repair() const; */ /* diff --git a/sql/handler.cc b/sql/handler.cc index 68921eb2a3f..733e77b6397 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -951,16 +951,21 @@ int ha_prepare(THD *thd) A helper function to evaluate if two-phase commit is mandatory. As a side effect, propagates the read-only/read-write flags of the statement transaction to its enclosing normal transaction. - - @retval TRUE we must run a two-phase commit. Returned - if we have at least two engines with read-write changes. - @retval FALSE Don't need two-phase commit. Even if we have two - transactional engines, we can run two independent - commits if changes in one of the engines are read-only. + + If we have at least two engines with read-write changes we must + run a two-phase commit. Otherwise we can run several independent + commits as the only transactional engine has read-write changes + and others are read-only. + + @retval 0 All engines are read-only. + @retval 1 We have the only engine with read-write changes. + @retval >1 More than one engine have read-write changes. + Note: return value might NOT be the exact number of + engines with read-write changes. */ static -bool +uint ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list, bool all) { @@ -997,7 +1002,7 @@ ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list, break; } } - return rw_ha_count > 1; + return rw_ha_count; } @@ -1060,19 +1065,30 @@ int ha_commit_trans(THD *thd, bool all) #ifdef USING_TRANSACTIONS if (ha_info) { - bool must_2pc; + uint rw_ha_count; + bool rw_trans; + + DBUG_EXECUTE_IF("crash_commit_before", abort();); + + /* Close all cursors that can not survive COMMIT */ + if (is_real_trans) /* not a statement commit */ + thd->stmt_map.close_transient_cursors(); + + rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, ha_info, all); + /* rw_trans is TRUE when we in a transaction changing data */ + rw_trans= is_real_trans && (rw_ha_count > 0); - if (is_real_trans && wait_if_global_read_lock(thd, 0, 0)) + if (rw_trans && + wait_if_global_read_lock(thd, 0, 0)) { ha_rollback_trans(thd, all); DBUG_RETURN(1); } - if ( is_real_trans - && opt_readonly - && ! (thd->security_ctx->master_access & SUPER_ACL) - && ! thd->slave_thread - ) + if (rw_trans && + opt_readonly && + !(thd->security_ctx->master_access & SUPER_ACL) && + !thd->slave_thread) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); ha_rollback_trans(thd, all); @@ -1080,15 +1096,7 @@ int ha_commit_trans(THD *thd, bool all) goto end; } - DBUG_EXECUTE_IF("crash_commit_before", DBUG_ABORT();); - - /* Close all cursors that can not survive COMMIT */ - if (is_real_trans) /* not a statement commit */ - thd->stmt_map.close_transient_cursors(); - - must_2pc= ha_check_and_coalesce_trx_read_only(thd, ha_info, all); - - if (!trans->no_2pc && must_2pc) + if (!trans->no_2pc && (rw_ha_count > 1)) { for (; ha_info && !error; ha_info= ha_info->next()) { @@ -1128,7 +1136,7 @@ int ha_commit_trans(THD *thd, bool all) tc_log->unlog(cookie, xid); DBUG_EXECUTE_IF("crash_commit_after", DBUG_ABORT();); end: - if (is_real_trans) + if (rw_trans) start_waiting_global_read_lock(thd); } #endif /* USING_TRANSACTIONS */ @@ -1609,23 +1617,23 @@ bool mysql_xa_recover(THD *thd) @return always 0 */ -static my_bool release_temporary_latches(THD *thd, plugin_ref plugin, - void *unused) -{ - handlerton *hton= plugin_data(plugin, handlerton *); - - if (hton->state == SHOW_OPTION_YES && hton->release_temporary_latches) - hton->release_temporary_latches(hton, thd); - - return FALSE; -} - int ha_release_temporary_latches(THD *thd) { - plugin_foreach(thd, release_temporary_latches, MYSQL_STORAGE_ENGINE_PLUGIN, - NULL); + Ha_trx_info *info; + /* + Note that below we assume that only transactional storage engines + may need release_temporary_latches(). If this will ever become false, + we could iterate on thd->open_tables instead (and remove duplicates + as if (!seen[hton->slot]) { seen[hton->slot]=1; ... }). + */ + for (info= thd->transaction.stmt.ha_list; info; info= info->next()) + { + handlerton *hton= info->ht(); + if (hton && hton->release_temporary_latches) + hton->release_temporary_latches(hton, thd); + } return 0; } @@ -1805,8 +1813,8 @@ bool ha_flush_logs(handlerton *db_type) return FALSE; } -static const char *check_lowercase_names(handler *file, const char *path, - char *tmp_path) +const char *get_canonical_filename(handler *file, const char *path, + char *tmp_path) { if (lower_case_table_names != 2 || (file->ha_table_flags() & HA_FILE_BASED)) return path; @@ -1877,7 +1885,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, ! (file=get_new_handler((TABLE_SHARE*)0, thd->mem_root, table_type))) DBUG_RETURN(ENOENT); - path= check_lowercase_names(file, path, tmp_path); + path= get_canonical_filename(file, path, tmp_path); if ((error= file->ha_delete_table(path)) && generate_warning) { /* @@ -2487,7 +2495,7 @@ void handler::print_keydup_error(uint key_nr, const char *msg) str.append(STRING_WITH_LEN("...")); } my_printf_error(ER_DUP_ENTRY, msg, - MYF(0), str.c_ptr(), table->key_info[key_nr].name); + MYF(0), str.c_ptr_safe(), table->key_info[key_nr].name); } } @@ -2558,7 +2566,7 @@ void handler::print_error(int error, myf errflag) str.append(STRING_WITH_LEN("...")); } my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table_share->table_name.str, - str.c_ptr(), key_nr+1); + str.c_ptr_safe(), key_nr+1); DBUG_VOID_RETURN; } textno= ER_DUP_KEY; @@ -2732,6 +2740,8 @@ int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt) } } } + if (table->s->frm_version != FRM_VER_TRUE_VARCHAR) + return HA_ADMIN_NEEDS_ALTER; return check_for_upgrade(check_opt); } @@ -3277,66 +3287,6 @@ handler::ha_rename_partitions(const char *path) /** - Optimize partitions: public interface. - - @sa handler::optimize_partitions() -*/ - -int -handler::ha_optimize_partitions(THD *thd) -{ - mark_trx_read_write(); - - return optimize_partitions(thd); -} - - -/** - Analyze partitions: public interface. - - @sa handler::analyze_partitions() -*/ - -int -handler::ha_analyze_partitions(THD *thd) -{ - mark_trx_read_write(); - - return analyze_partitions(thd); -} - - -/** - Check partitions: public interface. - - @sa handler::check_partitions() -*/ - -int -handler::ha_check_partitions(THD *thd) -{ - mark_trx_read_write(); - - return check_partitions(thd); -} - - -/** - Repair partitions: public interface. - - @sa handler::repair_partitions() -*/ - -int -handler::ha_repair_partitions(THD *thd) -{ - mark_trx_read_write(); - - return repair_partitions(thd); -} - - -/** 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. @@ -3474,7 +3424,7 @@ int ha_create_table(THD *thd, const char *path, if (update_create_info) update_create_info_from_table(create_info, &table); - name= check_lowercase_names(table.file, share.path.str, name_buff); + name= get_canonical_filename(table.file, share.path.str, name_buff); error= table.file->ha_create(name, &table, create_info); VOID(closefrm(&table, 0)); @@ -3546,7 +3496,7 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name) update_create_info_from_table(&create_info, &table); create_info.table_options|= HA_OPTION_CREATE_FROM_ENGINE; - check_lowercase_names(table.file, path, path); + get_canonical_filename(table.file, path, path); error=table.file->ha_create(path, &table, &create_info); VOID(closefrm(&table, 1)); diff --git a/sql/handler.h b/sql/handler.h index 12ba5daf1e1..f6e29048407 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1254,10 +1254,6 @@ public: size_t pack_frm_len); int ha_drop_partitions(const char *path); int ha_rename_partitions(const char *path); - int ha_optimize_partitions(THD *thd); - int ha_analyze_partitions(THD *thd); - int ha_check_partitions(THD *thd); - int ha_repair_partitions(THD *thd); void adjust_next_insert_id_after_explicit_value(ulonglong nr); int update_auto_increment(); @@ -1924,14 +1920,6 @@ private: { return HA_ERR_WRONG_COMMAND; } virtual int rename_partitions(const char *path) { return HA_ERR_WRONG_COMMAND; } - virtual int optimize_partitions(THD *thd) - { return HA_ERR_WRONG_COMMAND; } - virtual int analyze_partitions(THD *thd) - { return HA_ERR_WRONG_COMMAND; } - virtual int check_partitions(THD *thd) - { return HA_ERR_WRONG_COMMAND; } - virtual int repair_partitions(THD *thd) - { return HA_ERR_WRONG_COMMAND; } }; diff --git a/sql/init.cc b/sql/init.cc index aee0eb7179c..afda36b6b9d 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -35,7 +35,7 @@ void unireg_init(ulong options) wild_many='%'; wild_one='_'; wild_prefix='\\'; /* Change to sql syntax */ current_pid=(ulong) getpid(); /* Save for later ref */ - init_time(); /* Init time-functions (read zone) */ + my_init_time(); /* Init time-functions (read zone) */ #ifndef EMBEDDED_LIBRARY my_abort_hook=unireg_abort; /* Abort with close of databases */ #endif diff --git a/sql/item.cc b/sql/item.cc index 9d75e55c9a3..d443b9d87c6 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -435,8 +435,11 @@ uint Item::decimal_precision() const Item_result restype= result_type(); if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT)) - return min(my_decimal_length_to_precision(max_length, decimals, unsigned_flag), - DECIMAL_MAX_PRECISION); + { + uint prec= + my_decimal_length_to_precision(max_length, decimals, unsigned_flag); + return min(prec, DECIMAL_MAX_PRECISION); + } return min(max_length, DECIMAL_MAX_PRECISION); } @@ -3157,6 +3160,49 @@ void Item_param::print(String *str, enum_query_type query_type) } +/** + Preserve the original parameter types and values + when re-preparing a prepared statement. + + @details Copy parameter type information and conversion + function pointers from a parameter of the old statement + to the corresponding parameter of the new one. + + Move parameter values from the old parameters to the new + one. We simply "exchange" the values, which allows + to save on allocation and character set conversion in + case a parameter is a string or a blob/clob. + + The old parameter gets the value of this one, which + ensures that all memory of this parameter is freed + correctly. + + @param[in] src parameter item of the original + prepared statement +*/ + +void +Item_param::set_param_type_and_swap_value(Item_param *src) +{ + unsigned_flag= src->unsigned_flag; + param_type= src->param_type; + set_param_func= src->set_param_func; + item_type= src->item_type; + item_result_type= src->item_result_type; + + collation.set(src->collation); + maybe_null= src->maybe_null; + null_value= src->null_value; + max_length= src->max_length; + decimals= src->decimals; + state= src->state; + value= src->value; + + decimal_value.swap(src->decimal_value); + str_value.swap(src->str_value); + str_value_ptr.swap(src->str_value_ptr); +} + /**************************************************************************** Item_copy_string ****************************************************************************/ @@ -4070,16 +4116,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if (any_privileges) { char *db, *tab; - if (cached_table->view) - { - db= cached_table->view_db.str; - tab= cached_table->view_name.str; - } - else - { - db= cached_table->db; - tab= cached_table->table_name; - } + db= cached_table->get_db_name(); + tab= cached_table->get_table_name(); if (!(have_privileges= (get_column_grant(thd, &field->table->grant, db, tab, field_name) & VIEW_ANY_ACL))) @@ -4241,9 +4279,14 @@ static void convert_zerofill_number_to_string(Item **item, Field_num *field) String tmp(buff,sizeof(buff), field->charset()), *res; res= (*item)->val_str(&tmp); - field->prepend_zeros(res); - pos= (char *) sql_strmake (res->ptr(), res->length()); - *item= new Item_string(pos, res->length(), field->charset()); + if ((*item)->is_null()) + *item= new Item_null(); + else + { + field->prepend_zeros(res); + pos= (char *) sql_strmake (res->ptr(), res->length()); + *item= new Item_string(pos, res->length(), field->charset()); + } } @@ -5120,21 +5163,28 @@ Item_bin_string::Item_bin_string(const char *str, uint str_length) if (!ptr) return; str_value.set(ptr, max_length, &my_charset_bin); - ptr+= max_length - 1; - ptr[1]= 0; // Set end null for string - for (; end >= str; end--) + + if (max_length > 0) { - if (power == 256) + ptr+= max_length - 1; + ptr[1]= 0; // Set end null for string + for (; end >= str; end--) { - power= 1; - *ptr--= bits; - bits= 0; + if (power == 256) + { + power= 1; + *ptr--= bits; + bits= 0; + } + if (*end == '1') + bits|= power; + power<<= 1; } - if (*end == '1') - bits|= power; - power<<= 1; + *ptr= (char) bits; } - *ptr= (char) bits; + else + ptr[0]= 0; + collation.set(&my_charset_bin, DERIVATION_COERCIBLE); fixed= 1; } @@ -5868,6 +5918,10 @@ void Item_ref::make_field(Send_field *field) field->table_name= table_name; if (db_name) field->db_name= db_name; + if (orig_field_name) + field->org_col_name= orig_field_name; + if (orig_table_name) + field->org_table_name= orig_table_name; } @@ -6144,6 +6198,13 @@ Item *Item_default_value::transform(Item_transformer transformer, uchar *args) { DBUG_ASSERT(!current_thd->is_stmt_prepare()); + /* + If the value of arg is NULL, then this object represents a constant, + so further transformation is unnecessary (and impossible). + */ + if (!arg) + return 0; + Item *new_item= arg->transform(transformer, args); if (!new_item) return 0; @@ -6936,8 +6997,9 @@ bool Item_type_holder::join_types(THD *thd, Item *item) if (Field::result_merge_type(fld_type) == DECIMAL_RESULT) { decimals= min(max(decimals, item->decimals), DECIMAL_MAX_SCALE); - int precision= min(max(prev_decimal_int_part, item->decimal_int_part()) - + decimals, DECIMAL_MAX_PRECISION); + int item_int_part= item->decimal_int_part(); + int item_prec = max(prev_decimal_int_part, item_int_part) + decimals; + int precision= min(item_prec, DECIMAL_MAX_PRECISION); unsigned_flag&= item->unsigned_flag; max_length= my_decimal_precision_to_length(precision, decimals, unsigned_flag); diff --git a/sql/item.h b/sql/item.h index 57399e935cd..97350352162 100644 --- a/sql/item.h +++ b/sql/item.h @@ -467,9 +467,9 @@ class Item { Item(const Item &); /* Prevent use of these */ void operator=(Item &); public: - static void *operator new(size_t size) + static void *operator new(size_t size) throw () { return sql_alloc(size); } - static void *operator new(size_t size, MEM_ROOT *mem_root) + static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return alloc_root(mem_root, size); } static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) {} @@ -1685,6 +1685,7 @@ public: bool eq(const Item *item, bool binary_cmp) const; /** Item is a argument to a limit clause. */ bool limit_clause_param; + void set_param_type_and_swap_value(Item_param *from); }; @@ -2046,7 +2047,7 @@ class Item_empty_string :public Item_partition_func_safe_string public: Item_empty_string(const char *header,uint length, CHARSET_INFO *cs= NULL) : Item_partition_func_safe_string("",0, cs ? cs : &my_charset_utf8_general_ci) - { name=(char*) header; max_length= cs ? length * cs->mbmaxlen : length; } + { name=(char*) header; max_length= length * collation.collation->mbmaxlen; } void make_field(Send_field *field); }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index f34cd35b4a9..a79a94868c8 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1028,19 +1028,24 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, 1 if items are equal or both are null 0 otherwise If is_nulls_eq is FALSE: - -1 a < b or one of items is null + -1 a < b or at least one item is null 0 a == b 1 a > b + See the table: + is_nulls_eq | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | + a_is_null | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | + b_is_null | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | + result | 1 | 0 | 0 |0/1|-1 |-1 |-1 |-1/0/1| */ int Arg_comparator::compare_datetime() { - bool is_null= FALSE; + bool a_is_null, b_is_null; ulonglong a_value, b_value; /* Get DATE/DATETIME/TIME value of the 'a' item. */ - a_value= (*get_value_func)(thd, &a, &a_cache, *b, &is_null); - if (!is_nulls_eq && is_null) + a_value= (*get_value_func)(thd, &a, &a_cache, *b, &a_is_null); + if (!is_nulls_eq && a_is_null) { if (owner) owner->null_value= 1; @@ -1048,14 +1053,15 @@ int Arg_comparator::compare_datetime() } /* Get DATE/DATETIME/TIME value of the 'b' item. */ - b_value= (*get_value_func)(thd, &b, &b_cache, *a, &is_null); - if (is_null) + b_value= (*get_value_func)(thd, &b, &b_cache, *a, &b_is_null); + if (a_is_null || b_is_null) { if (owner) owner->null_value= is_nulls_eq ? 0 : 1; - return is_nulls_eq ? 1 : -1; + return is_nulls_eq ? (a_is_null == b_is_null) : -1; } + /* Here we have two not-NULL values. */ if (owner) owner->null_value= 0; @@ -2162,8 +2168,11 @@ Item_func_ifnull::fix_length_and_dec() uint Item_func_ifnull::decimal_precision() const { - int max_int_part=max(args[0]->decimal_int_part(),args[1]->decimal_int_part()); - return min(max_int_part + decimals, DECIMAL_MAX_PRECISION); + int arg0_int_part= args[0]->decimal_int_part(); + int arg1_int_part= args[1]->decimal_int_part(); + int max_int_part= max(arg0_int_part, arg1_int_part); + int precision= max_int_part + decimals; + return min(precision, DECIMAL_MAX_PRECISION); } @@ -2344,8 +2353,9 @@ Item_func_if::fix_length_and_dec() uint Item_func_if::decimal_precision() const { - int precision=(max(args[1]->decimal_int_part(),args[2]->decimal_int_part())+ - decimals); + int arg1_prec= args[1]->decimal_int_part(); + int arg2_prec= args[2]->decimal_int_part(); + int precision=max(arg1_prec,arg2_prec) + decimals; return min(precision, DECIMAL_MAX_PRECISION); } @@ -3757,6 +3767,7 @@ longlong Item_func_in::val_int() return (longlong) (!null_value && tmp != negated); } + have_null= 0; for (uint i= 1 ; i < arg_count ; i++) { Item_result cmp_type= item_cmp_type(left_result_type, args[i]->result_type()); @@ -3765,9 +3776,8 @@ longlong Item_func_in::val_int() if (!(value_added_map & (1 << (uint)cmp_type))) { in_item->store_value(args[0]); - if ((null_value=args[0]->null_value)) + if ((null_value= args[0]->null_value)) return 0; - have_null= 0; value_added_map|= 1 << (uint)cmp_type; } if (!in_item->cmp(args[i]) && !args[i]->null_value) @@ -4455,8 +4465,20 @@ void Item_func_like::cleanup() #ifdef USE_REGEX -bool -Item_func_regex::regcomp(bool send_error) +/** + @brief Compile regular expression. + + @param[in] send_error send error message if any. + + @details Make necessary character set conversion then + compile regular expression passed in the args[1]. + + @retval 0 success. + @retval 1 error occurred. + @retval -1 given null regular expression. + */ + +int Item_func_regex::regcomp(bool send_error) { char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),&my_charset_bin); @@ -4464,12 +4486,12 @@ Item_func_regex::regcomp(bool send_error) int error; if (args[1]->null_value) - return TRUE; + return -1; if (regex_compiled) { if (!stringcmp(res, &prev_regexp)) - return FALSE; + return 0; prev_regexp.copy(*res); my_regfree(&preg); regex_compiled= 0; @@ -4481,7 +4503,7 @@ Item_func_regex::regcomp(bool send_error) uint dummy_errors; if (conv.copy(res->ptr(), res->length(), res->charset(), regex_lib_charset, &dummy_errors)) - return TRUE; + return 1; res= &conv; } @@ -4493,10 +4515,10 @@ Item_func_regex::regcomp(bool send_error) (void) my_regerror(error, &preg, buff, sizeof(buff)); my_error(ER_REGEXP_ERROR, MYF(0), buff); } - return TRUE; + return 1; } regex_compiled= 1; - return FALSE; + return 0; } @@ -4534,13 +4556,14 @@ Item_func_regex::fix_fields(THD *thd, Item **ref) const_item_cache=args[0]->const_item() && args[1]->const_item(); if (!regex_compiled && args[1]->const_item()) { - if (args[1]->null_value) + int comp_res= regcomp(TRUE); + if (comp_res == -1) { // Will always return NULL maybe_null=1; fixed= 1; return FALSE; } - if (regcomp(TRUE)) + else if (comp_res) return TRUE; regex_is_const= 1; maybe_null= args[0]->maybe_null; @@ -4587,6 +4610,7 @@ void Item_func_regex::cleanup() { my_regfree(&preg); regex_compiled=0; + prev_regexp.length(0); } DBUG_VOID_RETURN; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 0166a18029d..2bf39e6da8d 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1401,7 +1401,7 @@ class Item_func_regex :public Item_bool_func CHARSET_INFO *regex_lib_charset; int regex_lib_flags; String conv; - bool regcomp(bool send_error); + int regcomp(bool send_error); public: Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b), regex_compiled(0),regex_is_const(0) {} diff --git a/sql/item_create.cc b/sql/item_create.cc index 49cc33b95a7..349c47816ad 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -5057,8 +5057,41 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, break; case ITEM_CAST_DECIMAL: { - len= c_len ? atoi(c_len) : 0; - dec= c_dec ? atoi(c_dec) : 0; + if (c_len == NULL) + { + len= 0; + } + else + { + ulong decoded_size; + errno= 0; + decoded_size= strtoul(c_len, NULL, 10); + if (errno != 0) + { + my_error(ER_TOO_BIG_PRECISION, MYF(0), c_len, a->name, + DECIMAL_MAX_PRECISION); + return NULL; + } + len= decoded_size; + } + + if (c_dec == NULL) + { + dec= 0; + } + else + { + ulong decoded_size; + errno= 0; + decoded_size= strtoul(c_dec, NULL, 10); + if ((errno != 0) || (decoded_size > UINT_MAX)) + { + my_error(ER_TOO_BIG_SCALE, MYF(0), c_dec, a->name, + DECIMAL_MAX_SCALE); + return NULL; + } + dec= decoded_size; + } my_decimal_trim(&len, &dec); if (len < dec) { @@ -5083,7 +5116,22 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, case ITEM_CAST_CHAR: { CHARSET_INFO *real_cs= (cs ? cs : thd->variables.collation_connection); - len= c_len ? atoi(c_len) : -1; + if (c_len == NULL) + { + len= LL(-1); + } + else + { + ulong decoded_size; + errno= 0; + decoded_size= strtoul(c_len, NULL, 10); + if ((errno != 0) || (decoded_size > MAX_FIELD_BLOBLENGTH)) + { + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char", MAX_FIELD_BLOBLENGTH); + return NULL; + } + len= decoded_size; + } res= new (thd->mem_root) Item_char_typecast(a, len, real_cs); break; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 202c4bee9c7..b3c50718273 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1138,9 +1138,10 @@ my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value) void Item_func_additive_op::result_precision() { decimals= max(args[0]->decimals, args[1]->decimals); - int max_int_part= max(args[0]->decimal_precision() - args[0]->decimals, - args[1]->decimal_precision() - args[1]->decimals); - int precision= min(max_int_part + 1 + decimals, DECIMAL_MAX_PRECISION); + int arg1_int= args[0]->decimal_precision() - args[0]->decimals; + int arg2_int= args[1]->decimal_precision() - args[1]->decimals; + int est_prec= max(arg1_int, arg2_int) + 1 + decimals; + int precision= min(est_prec, DECIMAL_MAX_PRECISION); /* Integer operations keep unsigned_flag if one of arguments is unsigned */ if (result_type() == INT_RESULT) @@ -1251,8 +1252,8 @@ void Item_func_mul::result_precision() else unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag; decimals= min(args[0]->decimals + args[1]->decimals, DECIMAL_MAX_SCALE); - int precision= min(args[0]->decimal_precision() + args[1]->decimal_precision(), - DECIMAL_MAX_PRECISION); + uint est_prec = args[0]->decimal_precision() + args[1]->decimal_precision(); + uint precision= min(est_prec, DECIMAL_MAX_PRECISION); max_length= my_decimal_precision_to_length(precision, decimals,unsigned_flag); } @@ -1299,8 +1300,8 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value) void Item_func_div::result_precision() { - uint precision=min(args[0]->decimal_precision() + prec_increment, - DECIMAL_MAX_PRECISION); + uint arg_prec= args[0]->decimal_precision() + prec_increment; + uint precision=min(arg_prec, DECIMAL_MAX_PRECISION); /* Integer operations keep unsigned_flag if one of arguments is unsigned */ if (result_type() == INT_RESULT) unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 925d6addb47..bbcf76658bd 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -298,6 +298,12 @@ String *Item_func_concat::val_str(String *str) { if (!(res=args[i]->val_str(str))) goto null; + /* + CONCAT accumulates its result in the result of its the first + non-empty argument. Because of this we need is_const to be + evaluated only for it. + */ + is_const= args[i]->const_item() || !args[i]->used_tables(); } else { diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index d126e18d444..dcb2a364996 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -254,6 +254,11 @@ bool Item_subselect::exec() if (thd->is_error()) /* Do not execute subselect in case of a fatal error */ return 1; + /* + Simulate a failure in sub-query execution. Used to test e.g. + out of memory or query being killed conditions. + */ + DBUG_EXECUTE_IF("subselect_exec_fail", return 1;); res= engine->exec(); @@ -719,27 +724,48 @@ longlong Item_exists_subselect::val_int() return value; } + +/** + Return the result of EXISTS as a string value + + Converts the true/false result into a string value. + Note that currently this cannot be NULL, so if the query exection fails + it will return 0. + + @param decimal_value[out] buffer to hold the resulting string value + @retval Pointer to the converted string. + Can't be a NULL pointer, as currently + EXISTS cannot return NULL. +*/ + String *Item_exists_subselect::val_str(String *str) { DBUG_ASSERT(fixed == 1); if (exec()) - { reset(); - return 0; - } str->set((ulonglong)value,&my_charset_bin); return str; } +/** + Return the result of EXISTS as a decimal value + + Converts the true/false result into a decimal value. + Note that currently this cannot be NULL, so if the query exection fails + it will return 0. + + @param decimal_value[out] Buffer to hold the resulting decimal value + @retval Pointer to the converted decimal. + Can't be a NULL pointer, as currently + EXISTS cannot return NULL. +*/ + my_decimal *Item_exists_subselect::val_decimal(my_decimal *decimal_value) { DBUG_ASSERT(fixed == 1); if (exec()) - { reset(); - return 0; - } int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value); return decimal_value; } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 264b53c780a..96f0b6a142d 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3256,7 +3256,7 @@ void Item_func_group_concat::clear() no_appended= TRUE; if (tree) reset_tree(tree); - if (distinct) + if (unique_filter) unique_filter->reset(); /* No need to reset the table as we never call write_row */ } diff --git a/sql/lock.cc b/sql/lock.cc index bb1c2c46284..dbae407d223 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -1533,6 +1533,7 @@ void start_waiting_global_read_lock(THD *thd) if (unlikely(thd->global_read_lock)) DBUG_VOID_RETURN; (void) pthread_mutex_lock(&LOCK_global_read_lock); + DBUG_ASSERT(protect_against_global_read_lock); tmp= (!--protect_against_global_read_lock && (waiting_for_read_lock || global_read_lock_blocks_commit)); (void) pthread_mutex_unlock(&LOCK_global_read_lock); diff --git a/sql/log.cc b/sql/log.cc index 305deb2f0fe..b6fe1196835 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -741,10 +741,14 @@ bool Log_to_file_event_handler:: ulonglong query_utime, ulonglong lock_utime, bool is_command, const char *sql_text, uint sql_text_len) { - return mysql_slow_log.write(thd, current_time, query_start_arg, - user_host, user_host_len, - query_utime, lock_utime, is_command, - sql_text, sql_text_len); + Silence_log_table_errors error_handler; + thd->push_internal_handler(&error_handler); + bool retval= mysql_slow_log.write(thd, current_time, query_start_arg, + user_host, user_host_len, + query_utime, lock_utime, is_command, + sql_text, sql_text_len); + thd->pop_internal_handler(); + return retval; } @@ -760,9 +764,13 @@ bool Log_to_file_event_handler:: const char *sql_text, uint sql_text_len, CHARSET_INFO *client_cs) { - return mysql_log.write(event_time, user_host, user_host_len, - thread_id, command_type, command_type_len, - sql_text, sql_text_len); + Silence_log_table_errors error_handler; + thd->push_internal_handler(&error_handler); + bool retval= mysql_log.write(event_time, user_host, user_host_len, + thread_id, command_type, command_type_len, + sql_text, sql_text_len); + thd->pop_internal_handler(); + return retval; } @@ -1413,6 +1421,7 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, If rolling back a statement in a transaction, we truncate the transaction cache to remove the statement. */ + thd->binlog_remove_pending_rows_event(TRUE); if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) trx_data->reset(); else // ...statement @@ -3069,6 +3078,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, int ret = 0; bool exit_loop= 0; LOG_INFO log_info; + THD *thd= current_thd; DBUG_ENTER("purge_logs"); DBUG_PRINT("info",("to_log= %s",to_log)); @@ -3094,10 +3104,13 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, /* It's not fatal if we can't stat a log file that does not exist; If we could not stat, we won't delete. - */ - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), - log_info.log_file_name); + */ + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + } sql_print_information("Failed to execute my_stat on file '%s'", log_info.log_file_name); my_errno= 0; @@ -3107,13 +3120,24 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, /* Other than ENOENT are fatal */ - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, - ER_BINLOG_PURGE_FATAL_ERR, - "a problem with getting info on being purged %s; " - "consider examining correspondence " - "of your binlog index file " - "to the actual binlog files", - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with getting info on being purged %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } + else + { + sql_print_information("Failed to delete log file '%s'; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } error= LOG_INFO_FATAL; goto err; } @@ -3130,27 +3154,42 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, { if (my_errno == ENOENT) { - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + } sql_print_information("Failed to delete file '%s'", log_info.log_file_name); my_errno= 0; } else { - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, - ER_BINLOG_PURGE_FATAL_ERR, - "a problem with deleting %s; " - "consider examining correspondence " - "of your binlog index file " - "to the actual binlog files", - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } + else + { + sql_print_information("Failed to delete file '%s'; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } if (my_errno == EMFILE) { DBUG_PRINT("info", ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno)); error= LOG_INFO_EMFILE; + goto err; } error= LOG_INFO_FATAL; goto err; @@ -3203,7 +3242,8 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) int error; LOG_INFO log_info; MY_STAT stat_area; - + THD *thd= current_thd; + DBUG_ENTER("purge_logs_before_date"); pthread_mutex_lock(&LOCK_index); @@ -3225,12 +3265,15 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) { /* It's not fatal if we can't stat a log file that does not exist. - */ - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), - log_info.log_file_name); - sql_print_information("Failed to execute my_stat on file '%s'", - log_info.log_file_name); + */ + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + } + sql_print_information("Failed to execute my_stat on file '%s'", + log_info.log_file_name); my_errno= 0; } else @@ -3238,13 +3281,21 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) /* Other than ENOENT are fatal */ - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, - ER_BINLOG_PURGE_FATAL_ERR, - "a problem with getting info on being purged %s; " - "consider examining correspondence " - "of your binlog index file " - "to the actual binlog files", - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with getting info on being purged %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } + else + { + sql_print_information("Failed to delete log file '%s'", + log_info.log_file_name); + } error= LOG_INFO_FATAL; goto err; } @@ -3258,22 +3309,33 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) if (my_errno == ENOENT) { /* It's not fatal even if we can't delete a log file */ - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + } sql_print_information("Failed to delete file '%s'", log_info.log_file_name); my_errno= 0; } else { - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, - ER_BINLOG_PURGE_FATAL_ERR, - "a problem with deleting %s; " - "consider examining correspondence " - "of your binlog index file " - "to the actual binlog files", - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } + else + { + sql_print_information("Failed to delete log file '%s'", + log_info.log_file_name); + } error= LOG_INFO_FATAL; goto err; } @@ -3715,6 +3777,31 @@ THD::binlog_set_pending_rows_event(Rows_log_event* ev) } +/** + Remove the pending rows event, discarding any outstanding rows. + + If there is no pending rows event available, this is effectively a + no-op. + */ +int +MYSQL_BIN_LOG::remove_pending_rows_event(THD *thd) +{ + DBUG_ENTER(__FUNCTION__); + + binlog_trx_data *const trx_data= + (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); + + DBUG_ASSERT(trx_data); + + if (Rows_log_event* pending= trx_data->pending()) + { + delete pending; + trx_data->set_pending(NULL); + } + + DBUG_RETURN(0); +} + /* Moves the last bunch of rows from the pending Rows event to the binlog (either cached binlog if transaction, or disk binlog). Sets a new pending diff --git a/sql/log.h b/sql/log.h index 20a1b7e8e6d..891134a9762 100644 --- a/sql/log.h +++ b/sql/log.h @@ -307,6 +307,7 @@ public: void update_table_map_version() { ++m_table_map_version; } int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event); + int remove_pending_rows_event(THD *thd); #endif /* !defined(MYSQL_CLIENT) */ void reset_bytes_written() diff --git a/sql/log_event.cc b/sql/log_event.cc index 32cf735ea3f..80eaf808647 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1353,6 +1353,542 @@ void Log_event::print_header(IO_CACHE* file, } +/** + Prints a quoted string to io cache. + Control characters are displayed as hex sequence, e.g. \x00 + + @param[in] file IO cache + @param[in] prt Pointer to string + @param[in] length String length +*/ + +static void +my_b_write_quoted(IO_CACHE *file, const uchar *ptr, uint length) +{ + const uchar *s; + my_b_printf(file, "'"); + for (s= ptr; length > 0 ; s++, length--) + { + if (*s > 0x1F) + my_b_write(file, s, 1); + else + { + uchar hex[10]; + size_t len= my_snprintf((char*) hex, sizeof(hex), "%s%02x", "\\x", *s); + my_b_write(file, hex, len); + } + } + my_b_printf(file, "'"); +} + + +/** + Prints a bit string to io cache in format b'1010'. + + @param[in] file IO cache + @param[in] ptr Pointer to string + @param[in] nbits Number of bits +*/ +static void +my_b_write_bit(IO_CACHE *file, const uchar *ptr, uint nbits) +{ + uint bitnum, nbits8= ((nbits + 7) / 8) * 8, skip_bits= nbits8 - nbits; + my_b_printf(file, "b'"); + for (bitnum= skip_bits ; bitnum < nbits8; bitnum++) + { + int is_set= (ptr[(bitnum) / 8] >> (7 - bitnum % 8)) & 0x01; + my_b_write(file, (const uchar*) (is_set ? "1" : "0"), 1); + } + my_b_printf(file, "'"); +} + + +/** + Prints a packed string to io cache. + The string consists of length packed to 1 or 2 bytes, + followed by string data itself. + + @param[in] file IO cache + @param[in] ptr Pointer to string + @param[in] length String size + + @retval - number of bytes scanned. +*/ +static size_t +my_b_write_quoted_with_length(IO_CACHE *file, const uchar *ptr, uint length) +{ + if (length < 256) + { + length= *ptr; + my_b_write_quoted(file, ptr + 1, length); + return length + 1; + } + else + { + length= uint2korr(ptr); + my_b_write_quoted(file, ptr + 2, length); + return length + 2; + } +} + + +/** + Prints a 32-bit number in both signed and unsigned representation + + @param[in] file IO cache + @param[in] sl Signed number + @param[in] ul Unsigned number +*/ +static void +my_b_write_sint32_and_uint32(IO_CACHE *file, int32 si, uint32 ui) +{ + my_b_printf(file, "%d", si); + if (si < 0) + my_b_printf(file, " (%u)", ui); +} + + +/** + Print a packed value of the given SQL type into IO cache + + @param[in] file IO cache + @param[in] ptr Pointer to string + @param[in] type Column type + @param[in] meta Column meta information + @param[out] typestr SQL type string buffer (for verbose output) + @param[out] typestr_length Size of typestr + + @retval - number of bytes scanned from ptr. +*/ + +static size_t +log_event_print_value(IO_CACHE *file, const uchar *ptr, + uint type, uint meta, + char *typestr, size_t typestr_length) +{ + uint32 length= 0; + + if (type == MYSQL_TYPE_STRING) + { + if (meta >= 256) + { + uint byte0= meta >> 8; + uint byte1= meta & 0xFF; + + if ((byte0 & 0x30) != 0x30) + { + /* a long CHAR() field: see #37426 */ + length= byte1 | (((byte0 & 0x30) ^ 0x30) << 4); + type= byte0 | 0x30; + goto beg; + } + + switch (byte0) + { + case MYSQL_TYPE_SET: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_STRING: + type= byte0; + length= byte1; + break; + + default: + + { + char tmp[5]; + my_snprintf(tmp, sizeof(tmp), "%04X", meta); + my_b_printf(file, + "!! Don't know how to handle column type=%d meta=%d (%s)", + type, meta, tmp); + return 0; + } + } + } + else + length= meta; + } + + +beg: + + switch (type) { + case MYSQL_TYPE_LONG: + { + int32 si= sint4korr(ptr); + uint32 ui= uint4korr(ptr); + my_b_write_sint32_and_uint32(file, si, ui); + my_snprintf(typestr, typestr_length, "INT"); + return 4; + } + + case MYSQL_TYPE_TINY: + { + my_b_write_sint32_and_uint32(file, (int) (signed char) *ptr, + (uint) (unsigned char) *ptr); + my_snprintf(typestr, typestr_length, "TINYINT"); + return 1; + } + + case MYSQL_TYPE_SHORT: + { + int32 si= (int32) sint2korr(ptr); + uint32 ui= (uint32) uint2korr(ptr); + my_b_write_sint32_and_uint32(file, si, ui); + my_snprintf(typestr, typestr_length, "SHORTINT"); + return 2; + } + + case MYSQL_TYPE_INT24: + { + int32 si= sint3korr(ptr); + uint32 ui= uint3korr(ptr); + my_b_write_sint32_and_uint32(file, si, ui); + my_snprintf(typestr, typestr_length, "MEDIUMINT"); + return 3; + } + + case MYSQL_TYPE_LONGLONG: + { + char tmp[64]; + longlong si= sint8korr(ptr); + longlong10_to_str(si, tmp, -10); + my_b_printf(file, "%s", tmp); + if (si < 0) + { + ulonglong ui= uint8korr(ptr); + longlong10_to_str((longlong) ui, tmp, 10); + my_b_printf(file, " (%s)", tmp); + } + my_snprintf(typestr, typestr_length, "LONGINT"); + return 8; + } + + case MYSQL_TYPE_NEWDECIMAL: + { + uint precision= meta >> 8; + uint decimals= meta & 0xFF; + uint bin_size= my_decimal_get_binary_size(precision, decimals); + my_decimal dec; + binary2my_decimal(E_DEC_FATAL_ERROR, (uchar*) ptr, &dec, + precision, decimals); + int i, end; + char buff[512], *pos; + pos= buff; + pos+= my_sprintf(buff, (buff, "%s", dec.sign() ? "-" : "")); + end= ROUND_UP(dec.frac) + ROUND_UP(dec.intg)-1; + for (i=0; i < end; i++) + pos+= my_sprintf(pos, (pos, "%09d.", dec.buf[i])); + pos+= my_sprintf(pos, (pos, "%09d", dec.buf[i])); + my_b_printf(file, "%s", buff); + my_snprintf(typestr, typestr_length, "DECIMAL(%d,%d)", + precision, decimals); + return bin_size; + } + + case MYSQL_TYPE_FLOAT: + { + float fl; + float4get(fl, ptr); + char tmp[320]; + sprintf(tmp, "%-20g", (double) fl); + my_b_printf(file, "%s", tmp); /* my_snprintf doesn't support %-20g */ + my_snprintf(typestr, typestr_length, "FLOAT"); + return 4; + } + + case MYSQL_TYPE_DOUBLE: + { + double dbl; + float8get(dbl, ptr); + char tmp[320]; + sprintf(tmp, "%-.20g", dbl); /* my_snprintf doesn't support %-20g */ + my_b_printf(file, "%s", tmp); + strcpy(typestr, "DOUBLE"); + return 8; + } + + case MYSQL_TYPE_BIT: + { + /* Meta-data: bit_len, bytes_in_rec, 2 bytes */ + uint nbits= ((meta >> 8) * 8) + (meta & 0xFF); + length= (nbits + 7) / 8; + my_b_write_bit(file, ptr, nbits); + my_snprintf(typestr, typestr_length, "BIT(%d)", nbits); + return length; + } + + case MYSQL_TYPE_TIMESTAMP: + { + uint32 i32= uint4korr(ptr); + my_b_printf(file, "%d", i32); + my_snprintf(typestr, typestr_length, "TIMESTAMP"); + return 4; + } + + case MYSQL_TYPE_DATETIME: + { + uint d, t; + uint64 i64= uint8korr(ptr); /* YYYYMMDDhhmmss */ + d= i64 / 1000000; + t= i64 % 1000000; + my_b_printf(file, "%04d-%02d-%02d %02d:%02d:%02d", + d / 10000, (d % 10000) / 100, d % 100, + t / 10000, (t % 10000) / 100, t % 100); + my_snprintf(typestr, typestr_length, "DATETIME"); + return 8; + } + + case MYSQL_TYPE_TIME: + { + uint32 i32= uint3korr(ptr); + my_b_printf(file, "'%02d:%02d:%02d'", + i32 / 10000, (i32 % 10000) / 100, i32 % 100); + my_snprintf(typestr, typestr_length, "TIME"); + return 3; + } + + case MYSQL_TYPE_DATE: + { + uint i32= uint3korr(ptr); + my_b_printf(file , "'%04d:%02d:%02d'", + (i32 / (16L * 32L)), (i32 / 32L % 16L), (i32 % 32L)); + my_snprintf(typestr, typestr_length, "DATE"); + return 3; + } + + case MYSQL_TYPE_YEAR: + { + uint32 i32= *ptr; + my_b_printf(file, "%04d", i32+ 1900); + my_snprintf(typestr, typestr_length, "YEAR"); + return 1; + } + + case MYSQL_TYPE_ENUM: + switch (length) { + case 1: + my_b_printf(file, "%d", (int) *ptr); + my_snprintf(typestr, typestr_length, "ENUM(1 byte)"); + return 1; + case 2: + { + int32 i32= uint2korr(ptr); + my_b_printf(file, "%d", i32); + my_snprintf(typestr, typestr_length, "ENUM(2 bytes)"); + return 2; + } + default: + my_b_printf(file, "!! Unknown ENUM packlen=%d", length); + return 0; + } + break; + + case MYSQL_TYPE_SET: + my_b_write_bit(file, ptr , length * 8); + my_snprintf(typestr, typestr_length, "SET(%d bytes)", length); + return length; + + case MYSQL_TYPE_BLOB: + switch (meta) { + case 1: + length= *ptr; + my_b_write_quoted(file, ptr + 1, length); + my_snprintf(typestr, typestr_length, "TINYBLOB/TINYTEXT"); + return length + 1; + case 2: + length= uint2korr(ptr); + my_b_write_quoted(file, ptr + 2, length); + my_snprintf(typestr, typestr_length, "BLOB/TEXT"); + return length + 2; + case 3: + length= uint3korr(ptr); + my_b_write_quoted(file, ptr + 3, length); + my_snprintf(typestr, typestr_length, "MEDIUMBLOB/MEDIUMTEXT"); + return length + 3; + case 4: + length= uint4korr(ptr); + my_b_write_quoted(file, ptr + 4, length); + my_snprintf(typestr, typestr_length, "LONGBLOB/LONGTEXT"); + return length + 4; + default: + my_b_printf(file, "!! Unknown BLOB packlen=%d", length); + return 0; + } + + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VAR_STRING: + length= meta; + my_snprintf(typestr, typestr_length, "VARSTRING(%d)", length); + return my_b_write_quoted_with_length(file, ptr, length); + + case MYSQL_TYPE_STRING: + my_snprintf(typestr, typestr_length, "STRING(%d)", length); + return my_b_write_quoted_with_length(file, ptr, length); + + default: + { + char tmp[5]; + my_snprintf(tmp, sizeof(tmp), "%04x", meta); + my_b_printf(file, + "!! Don't know how to handle column type=%d meta=%d (%s)", + type, meta, tmp); + } + break; + } + *typestr= 0; + return 0; +} + + +/** + Print a packed row into IO cache + + @param[in] file IO cache + @param[in] td Table definition + @param[in] print_event_into Print parameters + @param[in] cols_bitmap Column bitmaps. + @param[in] value Pointer to packed row + @param[in] prefix Row's SQL clause ("SET", "WHERE", etc) + + @retval - number of bytes scanned. +*/ + + +size_t +Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td, + PRINT_EVENT_INFO *print_event_info, + MY_BITMAP *cols_bitmap, + const uchar *value, const uchar *prefix) +{ + const uchar *value0= value; + const uchar *null_bits= value; + char typestr[64]= ""; + + value+= (m_width + 7) / 8; + + my_b_printf(file, "%s", prefix); + + for (size_t i= 0; i < td->size(); i ++) + { + int is_null= (null_bits[i / 8] >> (i % 8)) & 0x01; + + if (bitmap_is_set(cols_bitmap, i) == 0) + continue; + + if (is_null) + { + my_b_printf(file, "### @%d=NULL", i + 1); + } + else + { + my_b_printf(file, "### @%d=", i + 1); + size_t size= log_event_print_value(file, value, + td->type(i), td->field_metadata(i), + typestr, sizeof(typestr)); + if (!size) + return 0; + + value+= size; + } + + if (print_event_info->verbose > 1) + { + my_b_printf(file, " /* "); + + if (typestr[0]) + my_b_printf(file, "%s ", typestr); + else + my_b_printf(file, "type=%d ", td->type(i)); + + my_b_printf(file, "meta=%d nullable=%d is_null=%d ", + td->field_metadata(i), + td->maybe_null(i), is_null); + my_b_printf(file, "*/"); + } + + my_b_printf(file, "\n"); + } + return value - value0; +} + + +/** + Print a row event into IO cache in human readable form (in SQL format) + + @param[in] file IO cache + @param[in] print_event_into Print parameters +*/ +void Rows_log_event::print_verbose(IO_CACHE *file, + PRINT_EVENT_INFO *print_event_info) +{ + Table_map_log_event *map; + table_def *td; + const char *sql_command, *sql_clause1, *sql_clause2; + Log_event_type type_code= get_type_code(); + + switch (type_code) { + case WRITE_ROWS_EVENT: + sql_command= "INSERT INTO"; + sql_clause1= "### SET\n"; + sql_clause2= NULL; + break; + case DELETE_ROWS_EVENT: + sql_command= "DELETE FROM"; + sql_clause1= "### WHERE\n"; + sql_clause2= NULL; + break; + case UPDATE_ROWS_EVENT: + sql_command= "UPDATE"; + sql_clause1= "### WHERE\n"; + sql_clause2= "### SET\n"; + break; + default: + sql_command= sql_clause1= sql_clause2= NULL; + DBUG_ASSERT(0); /* Not possible */ + } + + if (!(map= print_event_info->m_table_map.get_table(m_table_id)) || + !(td= map->create_table_def())) + { + my_b_printf(file, "### Row event for unknown table #%d", m_table_id); + return; + } + + for (const uchar *value= m_rows_buf; value < m_rows_end; ) + { + size_t length; + my_b_printf(file, "### %s %s.%s\n", + sql_command, + map->get_db_name(), map->get_table_name()); + /* Print the first image */ + if (!(length= print_verbose_one_row(file, td, print_event_info, + &m_cols, value, + (const uchar*) sql_clause1))) + goto end; + value+= length; + + /* Print the second image (for UPDATE only) */ + if (sql_clause2) + { + if (!(length= print_verbose_one_row(file, td, print_event_info, + &m_cols_ai, value, + (const uchar*) sql_clause2))) + goto end; + value+= length; + } + } + +end: + delete td; +} + +#ifdef MYSQL_CLIENT +void free_table_map_log_event(Table_map_log_event *event) +{ + delete event; +} +#endif + void Log_event::print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info, bool more) @@ -1374,14 +1910,51 @@ void Log_event::print_base64(IO_CACHE* file, DBUG_ASSERT(0); } - if (my_b_tell(file) == 0) - my_b_printf(file, "\nBINLOG '\n"); - - my_b_printf(file, "%s\n", tmp_str); + if (print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS) + { + if (my_b_tell(file) == 0) + my_b_printf(file, "\nBINLOG '\n"); - if (!more) - my_b_printf(file, "'%s\n", print_event_info->delimiter); + my_b_printf(file, "%s\n", tmp_str); + if (!more) + my_b_printf(file, "'%s\n", print_event_info->delimiter); + } + + if (print_event_info->verbose) + { + Rows_log_event *ev= NULL; + + if (ptr[4] == TABLE_MAP_EVENT) + { + Table_map_log_event *map; + map= new Table_map_log_event((const char*) ptr, size, + glob_description_event); + print_event_info->m_table_map.set_table(map->get_table_id(), map); + } + else if (ptr[4] == WRITE_ROWS_EVENT) + { + ev= new Write_rows_log_event((const char*) ptr, size, + glob_description_event); + } + else if (ptr[4] == DELETE_ROWS_EVENT) + { + ev= new Delete_rows_log_event((const char*) ptr, size, + glob_description_event); + } + else if (ptr[4] == UPDATE_ROWS_EVENT) + { + ev= new Update_rows_log_event((const char*) ptr, size, + glob_description_event); + } + + if (ev) + { + ev->print_verbose(file, print_event_info); + delete ev; + } + } + my_free(tmp_str, MYF(0)); DBUG_VOID_RETURN; } @@ -1474,6 +2047,11 @@ void Query_log_event::pack_info(Protocol *protocol) static void write_str_with_code_and_len(char **dst, const char *src, int len, uint code) { + /* + only 1 byte to store the length of catalog, so it should not + surpass 255 + */ + DBUG_ASSERT(len <= 255); DBUG_ASSERT(src); *((*dst)++)= code; *((*dst)++)= (uchar) len; @@ -1493,21 +2071,8 @@ static void write_str_with_code_and_len(char **dst, const char *src, bool Query_log_event::write(IO_CACHE* file) { - /** - @todo if catalog can be of length FN_REFLEN==512, then we are not - replicating it correctly, since the length is stored in a byte - /sven - */ - uchar buf[QUERY_HEADER_LEN+ - 1+4+ // code of flags2 and flags2 - 1+8+ // code of sql_mode and sql_mode - 1+1+FN_REFLEN+ // code of catalog and catalog length and catalog - 1+4+ // code of autoinc and the 2 autoinc variables - 1+6+ // code of charset and charset - 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 charset_database and charset_database_number - ], *start, *start_of_status; + uchar buf[QUERY_HEADER_LEN + MAX_SIZE_LOG_EVENT_STATUS]; + uchar *start, *start_of_status; ulong event_length; if (!query) @@ -1613,10 +2178,8 @@ bool Query_log_event::write(IO_CACHE* file) { /* In the TZ sys table, column Name is of length 64 so this should be ok */ DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH); - *start++= Q_TIME_ZONE_CODE; - *start++= time_zone_len; - memcpy(start, time_zone_str, time_zone_len); - start+= time_zone_len; + write_str_with_code_and_len((char **)(&start), + time_zone_str, time_zone_len, Q_TIME_ZONE_CODE); } if (lc_time_names_number) { @@ -1632,7 +2195,17 @@ bool Query_log_event::write(IO_CACHE* file) int2store(start, charset_database_number); start+= 2; } + if (table_map_for_update) + { + *start++= Q_TABLE_MAP_FOR_UPDATE_CODE; + int8store(start, table_map_for_update); + start+= 8; + } /* + NOTE: When adding new status vars, please don't forget to update + the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update function + code_name in this file. + Here there could be code like if (command-line-option-which-says-"log_this_variable" && inited) { @@ -1709,7 +2282,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, 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), - charset_database_number(0) + charset_database_number(0), + table_map_for_update((ulonglong)thd_arg->table_map_for_update) { time_t end_time; @@ -1838,6 +2412,7 @@ code_name(int code) case Q_CATALOG_NZ_CODE: return "Q_CATALOG_NZ_CODE"; case Q_LC_TIME_NAMES_CODE: return "Q_LC_TIME_NAMES_CODE"; case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE"; + case Q_TABLE_MAP_FOR_UPDATE_CODE: return "Q_TABLE_MAP_FOR_UPDATE_CODE"; } sprintf(buf, "CODE#%d", code); return buf; @@ -1874,7 +2449,8 @@ 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), charset_database_number(0) + time_zone_len(0), lc_time_names_number(0), charset_database_number(0), + table_map_for_update(0) { ulong data_len; uint32 tmp; @@ -2016,6 +2592,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, charset_database_number= uint2korr(pos); pos+= 2; break; + case Q_TABLE_MAP_FOR_UPDATE_CODE: + CHECK_SPACE(pos, end, 8); + table_map_for_update= uint8korr(pos); + pos+= 8; + 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\ @@ -2423,6 +3004,8 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, else thd->variables.collation_database= thd->db_charset; + thd->table_map_for_update= (table_map)table_map_for_update; + /* Execute the query (note that we bypass dispatch_command()) */ const char* found_semicolon= NULL; mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); @@ -2679,7 +3262,8 @@ void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info) print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER && !print_event_info->short_form) { - my_b_printf(&cache, "BINLOG '\n"); + if (print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS) + my_b_printf(&cache, "BINLOG '\n"); print_base64(&cache, print_event_info, FALSE); print_event_info->printed_fd_event= TRUE; } @@ -4872,8 +5456,14 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli) /* Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) + + Fix_fields() can fail, in which case a call of update_hash() might + crash the server, so if fix fields fails, we just return with an + error. */ - e.fix_fields(thd, 0); + if (e.fix_fields(thd, 0)) + return 1; + /* A variable can just be considered as a table with a single record and with a single column. Thus, like @@ -6428,15 +7018,29 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) */ if (!thd->lock) { - bool need_reopen= 1; /* To execute the first lap of the loop below */ - /* - lock_tables() reads the contents of thd->lex, so they must be - initialized. Contrary to in - Table_map_log_event::do_apply_event() we don't call - mysql_init_query() as that may reset the binlog format. + Lock_tables() reads the contents of thd->lex, so they must be + initialized. + + We also call the mysql_reset_thd_for_next_command(), since this + is the logical start of the next "statement". Note that this + call might reset the value of current_stmt_binlog_row_based, so + we need to do any changes to that value after this function. */ lex_start(thd); + mysql_reset_thd_for_next_command(thd); + + /* + Check if the slave is set to use SBR. If so, it should switch + to using RBR until the end of the "statement", i.e., next + STMT_END_F or next error. + */ + if (!thd->current_stmt_binlog_row_based && + mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG)) + { + thd->set_current_stmt_binlog_row_based(); + } + /* There are a few flags that are replicated with each row event. @@ -6455,72 +7059,23 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) /* A small test to verify that objects have consistent types */ DBUG_ASSERT(sizeof(thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS)); - - while ((error= lock_tables(thd, rli->tables_to_lock, - rli->tables_to_lock_count, &need_reopen))) + if (simple_open_n_lock_tables(thd, rli->tables_to_lock)) { - if (!need_reopen) - { - if (thd->is_slave_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->main_da.sql_errno(); - rli->report(ERROR_LEVEL, actual_error, - "Error '%s' in %s event: when locking tables", - (actual_error ? thd->main_da.message(): - "unexpected success or fatal error"), - get_type_str()); - thd->is_fatal_error= 1; - } - else - { - rli->report(ERROR_LEVEL, error, - "Error in %s event: when locking tables", - get_type_str()); - } - const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); - DBUG_RETURN(error); - } - - /* - So we need to reopen the tables. - - We need to flush the pending RBR event, since it keeps a - pointer to an open table. - - ALTERNATIVE SOLUTION (not implemented): Extract a pointer to - the pending RBR event and reset the table pointer after the - tables has been reopened. - - NOTE: For this new scheme there should be no pending event: - need to add code to assert that is the case. - */ - thd->binlog_flush_pending_rows_event(false); - TABLE_LIST *tables= rli->tables_to_lock; - close_tables_for_reopen(thd, &tables); - - uint tables_count= rli->tables_to_lock_count; - if ((error= open_tables(thd, &tables, &tables_count, 0))) + uint actual_error= thd->main_da.sql_errno(); + if (thd->is_slave_error || thd->is_fatal_error) { - if (thd->is_slave_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->main_da.sql_errno(); - rli->report(ERROR_LEVEL, actual_error, - "Error '%s' on reopening tables", - (actual_error ? thd->main_da.message() : - "unexpected success or fatal error")); - thd->is_slave_error= 1; - } - const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); - DBUG_RETURN(error); + /* + Error reporting borrowed from Query_log_event with many excessive + simplifications (we don't honour --slave-skip-errors) + */ + rli->report(ERROR_LEVEL, actual_error, + "Error '%s' on opening tables", + (actual_error ? thd->main_da.message() : + "unexpected success or fatal error")); + thd->is_slave_error= 1; } + const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); + DBUG_RETURN(actual_error); } /* @@ -6573,6 +7128,8 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) table= m_table= const_cast<Relay_log_info*>(rli)->m_table_map.get_table(m_table_id); + DBUG_PRINT("debug", ("m_table: 0x%lx, m_table_id: %lu", (ulong) m_table, m_table_id)); + if (table) { /* @@ -7289,78 +7846,15 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) int error= 0; - if (!rpl_filter->db_ok(table_list->db) || - (rpl_filter->is_on() && !rpl_filter->tables_ok("", table_list))) + if (rli->sql_thd->slave_thread /* filtering is for slave only */ && + (!rpl_filter->db_ok(table_list->db) || + (rpl_filter->is_on() && !rpl_filter->tables_ok("", table_list)))) { my_free(memory, MYF(MY_WME)); } else { - /* - open_tables() reads the contents of thd->lex, so they must be - initialized, so we should call lex_start(); to be even safer, we - call mysql_init_query() which does a more complete set of inits. - */ - lex_start(thd); - mysql_reset_thd_for_next_command(thd); - /* - Check if the slave is set to use SBR. If so, it should switch - to using RBR until the end of the "statement", i.e., next - STMT_END_F or next error. - */ - if (!thd->current_stmt_binlog_row_based && - mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG)) - { - thd->set_current_stmt_binlog_row_based(); - } - - /* - 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; 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->is_slave_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->main_da.sql_errno(); - rli->report(ERROR_LEVEL, actual_error, - "Error '%s' on opening table `%s`.`%s`", - (actual_error ? thd->main_da.message() : - "unexpected success or fatal error"), - table_list->db, table_list->table_name); - thd->is_slave_error= 1; - } - goto err; - } - - m_table= table_list->table; - - /* - This will fail later otherwise, the 'in_use' field should be - set to the current thread. - */ - DBUG_ASSERT(m_table->in_use); /* Use placement new to construct the table_def instance in the @@ -7386,10 +7880,6 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) } DBUG_RETURN(error); - -err: - my_free(memory, MYF(MY_WME)); - DBUG_RETURN(error); } Log_event::enum_skip_reason diff --git a/sql/log_event.h b/sql/log_event.h index 76d92b23189..3c109b798d3 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -34,6 +34,14 @@ #include <my_bitmap.h> #include "rpl_constants.h" + +#ifdef MYSQL_CLIENT +#include "rpl_utility.h" +#include "hash.h" +#include "rpl_tblmap.h" +#include "rpl_tblmap.cc" +#endif + #ifndef MYSQL_CLIENT #include "rpl_record.h" #include "rpl_reporting.h" @@ -237,12 +245,15 @@ struct sql_ex_info packet (i.e. a query) sent from client to master; First, an auxiliary log_event status vars estimation: */ -#define MAX_SIZE_LOG_EVENT_STATUS (4 /* flags2 */ + \ - 8 /* sql mode */ + \ - 1 + 1 + 255 /* catalog */ + \ - 4 /* autoinc */ + \ - 6 /* charset */ + \ - MAX_TIME_ZONE_NAME_LENGTH) +#define MAX_SIZE_LOG_EVENT_STATUS (1 + 4 /* type, flags2 */ + \ + 1 + 8 /* type, sql_mode */ + \ + 1 + 1 + 255 /* type, length, catalog */ + \ + 1 + 4 /* type, auto_increment */ + \ + 1 + 6 /* type, charset */ + \ + 1 + 1 + 255 /* type, length, time_zone */ + \ + 1 + 2 /* type, lc_time_names_number */ + \ + 1 + 2 /* type, charset_database_number */ + \ + 1 + 8 /* type, table_map_for_update */) #define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \ LOG_EVENT_HEADER_LEN + /* write_header */ \ QUERY_HEADER_LEN + /* write_data */ \ @@ -306,6 +317,8 @@ struct sql_ex_info #define Q_LC_TIME_NAMES_CODE 7 #define Q_CHARSET_DATABASE_CODE 8 + +#define Q_TABLE_MAP_FOR_UPDATE_CODE 9 /* Intvar event post-header */ #define I_TYPE_OFFSET 0 @@ -572,6 +585,7 @@ enum enum_base64_output_mode { BASE64_OUTPUT_AUTO= 1, BASE64_OUTPUT_ALWAYS= 2, BASE64_OUTPUT_UNSPEC= 3, + BASE64_OUTPUT_DECODE_ROWS= 4, /* insert new output modes here */ BASE64_OUTPUT_MODE_COUNT }; @@ -634,6 +648,11 @@ typedef struct st_print_event_info uint8 common_header_len; char delimiter[16]; +#ifdef MYSQL_CLIENT + uint verbose; + table_mapping m_table_map; +#endif + /* These two caches are used by the row-based replication events to collect the header information and the main body of the events @@ -1455,6 +1474,22 @@ protected: This field is written if it is not 0. </td> </tr> + <tr> + <td>table_map_for_update</td> + <td>Q_TABLE_MAP_FOR_UPDATE_CODE == 9</td> + <td>8 byte integer</td> + + <td>The value of the table map that is to be updated by the + multi-table update query statement. Every bit of this variable + represents a table, and is set to 1 if the corresponding table is + to be updated by this statement. + + The value of this variable is set when executing a multi-table update + statement and used by slave to apply filter rules without opening + all the tables on slave. This is required because some tables may + not exist on slave because of the filter rules. + </td> + </tr> </table> @subsection Query_log_event_notes_on_previous_versions Notes on Previous Versions @@ -1471,6 +1506,9 @@ protected: * See Q_CHARSET_DATABASE_CODE in the table above. + * When adding new status vars, please don't forget to update the + MAX_SIZE_LOG_EVENT_STATUS, and update function code_name + */ class Query_log_event: public Log_event { @@ -1548,6 +1586,11 @@ public: const char *time_zone_str; uint lc_time_names_number; /* 0 means en_US */ uint charset_database_number; + /* + map for tables that will be updated for a multi-table update query + statement, for other query statements, this will be zero. + */ + ulonglong table_map_for_update; #ifndef MYSQL_CLIENT @@ -3235,6 +3278,17 @@ public: ~Table_map_log_event(); +#ifdef MYSQL_CLIENT + table_def *create_table_def() + { + return new table_def(m_coltype, m_colcnt, m_field_metadata, + m_field_metadata_size, m_null_bits); + } + ulong get_table_id() const { return m_table_id; } + const char *get_table_name() const { return m_tblnam; } + const char *get_db_name() const { return m_dbnam; } +#endif + virtual Log_event_type get_type_code() { return TABLE_MAP_EVENT; } virtual bool is_valid() const { return m_memory != NULL; /* we check malloc */ } @@ -3365,6 +3419,12 @@ public: #ifdef MYSQL_CLIENT /* not for direct call, each derived has its own ::print() */ virtual void print(FILE *file, PRINT_EVENT_INFO *print_event_info)= 0; + void print_verbose(IO_CACHE *file, + PRINT_EVENT_INFO *print_event_info); + size_t print_verbose_one_row(IO_CACHE *file, table_def *td, + PRINT_EVENT_INFO *print_event_info, + MY_BITMAP *cols_bitmap, + const uchar *ptr, const uchar *prefix); #endif #ifndef MYSQL_CLIENT diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 3596b21cb30..96076b5c199 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -53,81 +53,46 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info */ if (!thd->lock) { - bool need_reopen= 1; /* To execute the first lap of the loop below */ - /* - lock_tables() reads the contents of thd->lex, so they must be - initialized. Contrary to in - Table_map_log_event::do_apply_event() we don't call - mysql_init_query() as that may reset the binlog format. + Lock_tables() reads the contents of thd->lex, so they must be + initialized. + + We also call the mysql_reset_thd_for_next_command(), since this + is the logical start of the next "statement". Note that this + call might reset the value of current_stmt_binlog_row_based, so + we need to do any changes to that value after this function. */ lex_start(thd); + mysql_reset_thd_for_next_command(thd); - while ((error= lock_tables(thd, rli->tables_to_lock, - rli->tables_to_lock_count, &need_reopen))) + /* + Check if the slave is set to use SBR. If so, it should switch + to using RBR until the end of the "statement", i.e., next + STMT_END_F or next error. + */ + if (!thd->current_stmt_binlog_row_based && + mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG)) { - if (!need_reopen) - { - if (thd->is_slave_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->main_da.sql_errno(); - rli->report(ERROR_LEVEL, actual_error, - "Error '%s' in %s event: when locking tables", - (actual_error ? thd->main_da.message() : - "unexpected success or fatal error"), - ev->get_type_str()); - thd->is_fatal_error= 1; - } - else - { - rli->report(ERROR_LEVEL, error, - "Error in %s event: when locking tables", - ev->get_type_str()); - } - const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); - DBUG_RETURN(error); - } - - /* - So we need to reopen the tables. - - We need to flush the pending RBR event, since it keeps a - pointer to an open table. - - ALTERNATIVE SOLUTION (not implemented): Extract a pointer to - the pending RBR event and reset the table pointer after the - tables has been reopened. - - NOTE: For this new scheme there should be no pending event: - need to add code to assert that is the case. - */ - thd->binlog_flush_pending_rows_event(false); - TABLE_LIST *tables= rli->tables_to_lock; - close_tables_for_reopen(thd, &tables); + thd->set_current_stmt_binlog_row_based(); + } - uint tables_count= rli->tables_to_lock_count; - if ((error= open_tables(thd, &tables, &tables_count, 0))) + if (simple_open_n_lock_tables(thd, rli->tables_to_lock)) + { + uint actual_error= thd->main_da.sql_errno(); + if (thd->is_slave_error || thd->is_fatal_error) { - if (thd->is_slave_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->main_da.sql_errno(); - rli->report(ERROR_LEVEL, actual_error, - "Error '%s' on reopening tables", - (actual_error ? thd->main_da.message() : - "unexpected success or fatal error")); - thd->is_slave_error= 1; - } - const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); - DBUG_RETURN(error); + /* + Error reporting borrowed from Query_log_event with many excessive + simplifications (we don't honour --slave-skip-errors) + */ + rli->report(ERROR_LEVEL, actual_error, + "Error '%s' on opening tables", + (actual_error ? thd->main_da.message() : + "unexpected success or fatal error")); + thd->is_slave_error= 1; } + const_cast<Relay_log_info*>(rli)->clear_tables_to_lock(); + DBUG_RETURN(actual_error); } /* diff --git a/sql/my_decimal.h b/sql/my_decimal.h index 1885036f42b..0e79f70ab4e 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -114,6 +114,14 @@ public: bool sign() const { return decimal_t::sign; } void sign(bool s) { decimal_t::sign= s; } uint precision() const { return intg + frac; } + + /** Swap two my_decimal values */ + void swap(my_decimal &rhs) + { + swap_variables(my_decimal, *this, rhs); + /* Swap the buffer pointers back */ + swap_variables(decimal_digit_t *, buf, rhs.buf); + } }; @@ -169,14 +177,23 @@ inline int check_result_and_overflow(uint mask, int result, my_decimal *val) inline uint my_decimal_length_to_precision(uint length, uint scale, bool unsigned_flag) { - return (uint) (length - (scale>0 ? 1:0) - (unsigned_flag ? 0:1)); + /* Precision can't be negative thus ignore unsigned_flag when length is 0. */ + DBUG_ASSERT(length || !scale); + return (uint) (length - (scale>0 ? 1:0) - + (unsigned_flag || !length ? 0:1)); } inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale, bool unsigned_flag) { + /* + When precision is 0 it means that original length was also 0. Thus + unsigned_flag is ignored in this case. + */ + DBUG_ASSERT(precision || !scale); set_if_smaller(precision, DECIMAL_MAX_PRECISION); - return (uint32)(precision + (scale>0 ? 1:0) + (unsigned_flag ? 0:1)); + return (uint32)(precision + (scale>0 ? 1:0) + + (unsigned_flag || !precision ? 0:1)); } inline diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d186ae54f7d..d4182ce5474 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -44,6 +44,8 @@ #include "sql_plugin.h" #include "scheduler.h" +class Parser_state; + /** Query type constants. @@ -259,6 +261,21 @@ protected: #define USER_VARS_HASH_SIZE 16 #define TABLE_OPEN_CACHE_MIN 64 #define TABLE_OPEN_CACHE_DEFAULT 64 +#define TABLE_DEF_CACHE_DEFAULT 256 +/** + We must have room for at least 256 table definitions in the table + cache, since otherwise there is no chance prepared + statements that use these many tables can work. + Prepared statements use table definition cache ids (table_map_id) + as table version identifiers. If the table definition + cache size is less than the number of tables used in a statement, + the contents of the table definition cache is guaranteed to rotate + between a prepare and execute. This leads to stable validation + errors. In future we shall use more stable version identifiers, + for now the only solution is to ensure that the table definition + cache can contain at least all tables of a given statement. +*/ +#define TABLE_DEF_CACHE_MIN 256 /* Value of 9236 discovered through binary search 2006-09-26 on Ubuntu Dapper @@ -668,6 +685,31 @@ const char *set_thd_proc_info(THD *thd, const char *info, const char *calling_file, const unsigned int calling_line); +/** + Enumerate possible types of a table from re-execution + standpoint. + TABLE_LIST class has a member of this type. + At prepared statement prepare, this member is assigned a value + as of the current state of the database. Before (re-)execution + of a prepared statement, we check that the value recorded at + prepare matches the type of the object we obtained from the + table definition cache. + + @sa check_and_update_table_version() + @sa Execute_observer + @sa Prepared_statement::reprepare() +*/ + +enum enum_table_ref_type +{ + /** Initial value set by the parser */ + TABLE_REF_NULL= 0, + TABLE_REF_VIEW, + TABLE_REF_BASE_TABLE, + TABLE_REF_I_S_TABLE, + TABLE_REF_TMP_TABLE +}; + /* External variables */ @@ -759,11 +801,10 @@ bool check_string_byte_length(LEX_STRING *str, const char *err_msg, bool check_string_char_length(LEX_STRING *str, const char *err_msg, uint max_char_length, CHARSET_INFO *cs, bool no_error); -bool test_if_data_home_dir(const char *dir); bool parse_sql(THD *thd, - class Lex_input_stream *lip, - class Object_creation_ctx *creation_ctx); + Parser_state *parser_state, + Object_creation_ctx *creation_ctx); enum enum_mysql_completiontype { ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7, @@ -1530,6 +1571,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, char *db, const char *table_name, uint fast_alter_partition); +uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info, + enum partition_state part_state); uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, HA_CREATE_INFO *create_info, handlerton *old_db_type, @@ -1819,6 +1862,7 @@ extern CHARSET_INFO *character_set_filesystem; #ifdef MYSQL_SERVER extern char *opt_mysql_tmpdir, mysql_charsets_dir[], def_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; +extern int mysql_unpacked_real_data_home_len; #define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list)) extern MY_TMPDIR mysql_tmpdir_list; extern const LEX_STRING command_name[]; @@ -2094,6 +2138,7 @@ int writefrm(const char* name, const uchar* data, size_t len); int closefrm(TABLE *table, bool free_share); int read_string(File file, uchar* *to, size_t length); void free_blobs(TABLE *table); +void free_field_buffers_larger_than(TABLE *table, uint32 size); int set_zone(int nr,int min_zone,int max_zone); ulong convert_period_to_month(ulong period); ulong convert_month_to_period(ulong month); @@ -2139,8 +2184,8 @@ ulonglong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(uchar *,uint,char,char); void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, - SQL_SELECT *select, - int use_record_cache, bool print_errors); + SQL_SELECT *select, int use_record_cache, + bool print_errors, bool disable_rr_cache); void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, bool print_error, uint idx); void end_read_record(READ_RECORD *info); @@ -2188,6 +2233,8 @@ uint tablename_to_filename(const char *from, char *to, uint to_length); #ifdef MYSQL_SERVER uint build_table_filename(char *buff, size_t bufflen, const char *db, const char *table, const char *ext, uint flags); +const char *get_canonical_filename(handler *file, const char *path, + char *tmp_path); #define MYSQL50_TABLE_NAME_PREFIX "#mysql50#" #define MYSQL50_TABLE_NAME_PREFIX_LENGTH 9 @@ -2432,6 +2479,8 @@ bool load_collation(MEM_ROOT *mem_root, CHARSET_INFO **cl); #endif /* MYSQL_SERVER */ +extern "C" int test_if_data_home_dir(const char *dir); + #endif /* MYSQL_CLIENT */ #endif /* MYSQL_PRIV_H */ diff --git a/sql/mysql_priv.h.pp b/sql/mysql_priv.h.pp new file mode 100644 index 00000000000..8bb31f64587 --- /dev/null +++ b/sql/mysql_priv.h.pp @@ -0,0 +1,10978 @@ +#include <my_global.h> +#include <my_config.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <math.h> +#include <limits.h> +#include <float.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/timeb.h> +#include <sys/time.h> +#include <time.h> +#include <unistd.h> +#include <alloca.h> +#include <errno.h> +#include <crypt.h> +#include <assert.h> +#include <my_attribute.h> +int __cxa_pure_virtual () __attribute__ ((weak)); +#include <my_dbug.h> +struct _db_code_state_; +extern int _db_keyword_(struct _db_code_state_ *cs, const char *keyword); +extern int _db_strict_keyword_(const char *keyword); +extern int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len); +extern int _db_explain_init_(char *buf, size_t len); +extern void _db_setjmp_(void); +extern void _db_longjmp_(void); +extern void _db_process_(const char *name); +extern void _db_push_(const char *control); +extern void _db_pop_(void); +extern void _db_set_(struct _db_code_state_ *cs, const char *control); +extern void _db_set_init_(const char *control); +extern void _db_enter_(const char *_func_,const char *_file_,uint _line_, + const char **_sfunc_,const char **_sfile_, + uint *_slevel_, char ***); +extern void _db_return_(uint _line_,const char **_sfunc_,const char **_sfile_, + uint *_slevel_); +extern void _db_pargs_(uint _line_,const char *keyword); +extern void _db_doprnt_ (const char *format,...) + __attribute__((format(printf, 1, 2))); +extern void _db_dump_(uint _line_,const char *keyword, + const unsigned char *memory, size_t length); +extern void _db_end_(void); +extern void _db_lock_file_(void); +extern void _db_unlock_file_(void); +extern FILE *_db_fp_(void); +typedef int File; +typedef int my_socket; +typedef void (*sig_return)(); +typedef char pchar; +typedef char puchar; +typedef char pbool; +typedef short pshort; +typedef float pfloat; +typedef int (*qsort_cmp)(const void *,const void *); +typedef int (*qsort_cmp2)(void*, const void *,const void *); +#include <sys/socket.h> +typedef socklen_t size_socket; +typedef long my_ptrdiff_t; +typedef unsigned char uchar; +typedef signed char int8; +typedef unsigned char uint8; +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef unsigned long long int ulonglong; +typedef long long int longlong; +typedef longlong int64; +typedef ulonglong uint64; +typedef unsigned long long my_ulonglong; +typedef int intptr; +typedef ulonglong my_off_t; +typedef off_t os_off_t; +typedef uint8 int7; +typedef short int15; +typedef int myf; +typedef char my_bool; +typedef char bool; +typedef union { + double v; + long m[2]; +} doubleget_union; +#include <dlfcn.h> +#include <mysql_version.h> +#include <mysql_embed.h> +#include <my_sys.h> +#include <my_pthread.h> +#include <pthread.h> +#include <sched.h> +extern int my_pthread_getprio(pthread_t thread_id); +typedef void *(* pthread_handler)(void *); +extern void my_pthread_setprio(pthread_t thread_id,int prior); +extern void my_pthread_attr_setprio(pthread_attr_t *attr, int priority); +typedef struct st_safe_mutex_t +{ + pthread_mutex_t global,mutex; + const char *file; + uint line,count; + pthread_t thread; +} safe_mutex_t; +int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr, + const char *file, uint line); +int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line); +int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line); +int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line); +int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file, + uint line); +int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp, + struct timespec *abstime, const char *file, uint line); +void safe_mutex_global_init(void); +void safe_mutex_end(FILE *file); +typedef ulong my_thread_id; +extern my_bool my_thread_global_init(void); +extern void my_thread_global_end(void); +extern my_bool my_thread_init(void); +extern void my_thread_end(void); +extern const char *my_thread_name(void); +extern my_thread_id my_thread_dbug_id(void); +extern int pthread_no_free(void *); +extern int pthread_dummy(int); +struct st_my_thread_var +{ + int thr_errno; + pthread_cond_t suspend; + pthread_mutex_t mutex; + pthread_mutex_t * volatile current_mutex; + pthread_cond_t * volatile current_cond; + pthread_t pthread_self; + my_thread_id id; + int cmp_length; + int volatile abort; + my_bool init; + struct st_my_thread_var *next,**prev; + void *opt_info; + void *dbug; + char name[10 +1]; +}; +extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const)); +extern uint my_thread_end_wait_time; +extern uint thd_lib_detected; +#include <m_ctype.h> +#include <my_attribute.h> +typedef struct unicase_info_st +{ + uint16 toupper; + uint16 tolower; + uint16 sort; +} MY_UNICASE_INFO; +extern MY_UNICASE_INFO *my_unicase_default[256]; +extern MY_UNICASE_INFO *my_unicase_turkish[256]; +typedef struct uni_ctype_st +{ + uchar pctype; + uchar *ctype; +} MY_UNI_CTYPE; +extern MY_UNI_CTYPE my_uni_ctype[256]; +typedef struct my_uni_idx_st +{ + uint16 from; + uint16 to; + uchar *tab; +} MY_UNI_IDX; +typedef struct +{ + uint beg; + uint end; + uint mb_len; +} my_match_t; +enum my_lex_states +{ + MY_LEX_START, MY_LEX_CHAR, MY_LEX_IDENT, + MY_LEX_IDENT_SEP, MY_LEX_IDENT_START, + MY_LEX_REAL, MY_LEX_HEX_NUMBER, MY_LEX_BIN_NUMBER, + MY_LEX_CMP_OP, MY_LEX_LONG_CMP_OP, MY_LEX_STRING, MY_LEX_COMMENT, MY_LEX_END, + MY_LEX_OPERATOR_OR_IDENT, MY_LEX_NUMBER_IDENT, MY_LEX_INT_OR_REAL, + MY_LEX_REAL_OR_POINT, MY_LEX_BOOL, MY_LEX_EOL, MY_LEX_ESCAPE, + MY_LEX_LONG_COMMENT, MY_LEX_END_LONG_COMMENT, MY_LEX_SEMICOLON, + MY_LEX_SET_VAR, MY_LEX_USER_END, MY_LEX_HOSTNAME, MY_LEX_SKIP, + MY_LEX_USER_VARIABLE_DELIMITER, MY_LEX_SYSTEM_VAR, + MY_LEX_IDENT_OR_KEYWORD, + MY_LEX_IDENT_OR_HEX, MY_LEX_IDENT_OR_BIN, MY_LEX_IDENT_OR_NCHAR, + MY_LEX_STRING_OR_DELIMITER +}; +struct charset_info_st; +typedef struct my_collation_handler_st +{ + my_bool (*init)(struct charset_info_st *, void *(*alloc)(size_t)); + int (*strnncoll)(struct charset_info_st *, + const uchar *, size_t, const uchar *, size_t, my_bool); + int (*strnncollsp)(struct charset_info_st *, + const uchar *, size_t, const uchar *, size_t, + my_bool diff_if_only_endspace_difference); + size_t (*strnxfrm)(struct charset_info_st *, + uchar *, size_t, const uchar *, size_t); + size_t (*strnxfrmlen)(struct charset_info_st *, size_t); + my_bool (*like_range)(struct charset_info_st *, + const char *s, size_t s_length, + pchar w_prefix, pchar w_one, pchar w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_len, size_t *max_len); + int (*wildcmp)(struct charset_info_st *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape,int w_one, int w_many); + int (*strcasecmp)(struct charset_info_st *, const char *, const char *); + uint (*instr)(struct charset_info_st *, + const char *b, size_t b_length, + const char *s, size_t s_length, + my_match_t *match, uint nmatch); + void (*hash_sort)(struct charset_info_st *cs, const uchar *key, size_t len, + ulong *nr1, ulong *nr2); + my_bool (*propagate)(struct charset_info_st *cs, const uchar *str, size_t len); +} MY_COLLATION_HANDLER; +extern MY_COLLATION_HANDLER my_collation_mb_bin_handler; +extern MY_COLLATION_HANDLER my_collation_8bit_bin_handler; +extern MY_COLLATION_HANDLER my_collation_8bit_simple_ci_handler; +extern MY_COLLATION_HANDLER my_collation_ucs2_uca_handler; +typedef int (*my_charset_conv_mb_wc)(struct charset_info_st *, ulong *, + const uchar *, const uchar *); +typedef int (*my_charset_conv_wc_mb)(struct charset_info_st *, ulong, + uchar *, uchar *); +typedef size_t (*my_charset_conv_case)(struct charset_info_st *, + char *, size_t, char *, size_t); +typedef struct my_charset_handler_st +{ + my_bool (*init)(struct charset_info_st *, void *(*alloc)(size_t)); + uint (*ismbchar)(struct charset_info_st *, const char *, const char *); + uint (*mbcharlen)(struct charset_info_st *, uint c); + size_t (*numchars)(struct charset_info_st *, const char *b, const char *e); + size_t (*charpos)(struct charset_info_st *, const char *b, const char *e, + size_t pos); + size_t (*well_formed_len)(struct charset_info_st *, + const char *b,const char *e, + size_t nchars, int *error); + size_t (*lengthsp)(struct charset_info_st *, const char *ptr, size_t length); + size_t (*numcells)(struct charset_info_st *, const char *b, const char *e); + my_charset_conv_mb_wc mb_wc; + my_charset_conv_wc_mb wc_mb; + int (*ctype)(struct charset_info_st *cs, int *ctype, + const uchar *s, const uchar *e); + size_t (*caseup_str)(struct charset_info_st *, char *); + size_t (*casedn_str)(struct charset_info_st *, char *); + my_charset_conv_case caseup; + my_charset_conv_case casedn; + size_t (*snprintf)(struct charset_info_st *, char *to, size_t n, + const char *fmt, + ...) __attribute__((format(printf, 4, 5))); + size_t (*long10_to_str)(struct charset_info_st *, char *to, size_t n, + int radix, long int val); + size_t (*longlong10_to_str)(struct charset_info_st *, char *to, size_t n, + int radix, longlong val); + void (*fill)(struct charset_info_st *, char *to, size_t len, int fill); + long (*strntol)(struct charset_info_st *, const char *s, size_t l, + int base, char **e, int *err); + ulong (*strntoul)(struct charset_info_st *, const char *s, size_t l, + int base, char **e, int *err); + longlong (*strntoll)(struct charset_info_st *, const char *s, size_t l, + int base, char **e, int *err); + ulonglong (*strntoull)(struct charset_info_st *, const char *s, size_t l, + int base, char **e, int *err); + double (*strntod)(struct charset_info_st *, char *s, size_t l, char **e, + int *err); + longlong (*strtoll10)(struct charset_info_st *cs, + const char *nptr, char **endptr, int *error); + ulonglong (*strntoull10rnd)(struct charset_info_st *cs, + const char *str, size_t length, + int unsigned_fl, + char **endptr, int *error); + size_t (*scan)(struct charset_info_st *, const char *b, const char *e, + int sq); +} MY_CHARSET_HANDLER; +extern MY_CHARSET_HANDLER my_charset_8bit_handler; +extern MY_CHARSET_HANDLER my_charset_ucs2_handler; +typedef struct charset_info_st +{ + uint number; + uint primary_number; + uint binary_number; + uint state; + const char *csname; + const char *name; + const char *comment; + const char *tailoring; + uchar *ctype; + uchar *to_lower; + uchar *to_upper; + uchar *sort_order; + uint16 *contractions; + uint16 **sort_order_big; + uint16 *tab_to_uni; + MY_UNI_IDX *tab_from_uni; + MY_UNICASE_INFO **caseinfo; + uchar *state_map; + uchar *ident_map; + uint strxfrm_multiply; + uchar caseup_multiply; + uchar casedn_multiply; + uint mbminlen; + uint mbmaxlen; + uint16 min_sort_char; + uint16 max_sort_char; + uchar pad_char; + my_bool escape_with_backslash_is_dangerous; + MY_CHARSET_HANDLER *cset; + MY_COLLATION_HANDLER *coll; +} CHARSET_INFO; +extern CHARSET_INFO my_charset_bin; +extern CHARSET_INFO my_charset_big5_chinese_ci; +extern CHARSET_INFO my_charset_big5_bin; +extern CHARSET_INFO my_charset_cp932_japanese_ci; +extern CHARSET_INFO my_charset_cp932_bin; +extern CHARSET_INFO my_charset_eucjpms_japanese_ci; +extern CHARSET_INFO my_charset_eucjpms_bin; +extern CHARSET_INFO my_charset_euckr_korean_ci; +extern CHARSET_INFO my_charset_euckr_bin; +extern CHARSET_INFO my_charset_gb2312_chinese_ci; +extern CHARSET_INFO my_charset_gb2312_bin; +extern CHARSET_INFO my_charset_gbk_chinese_ci; +extern CHARSET_INFO my_charset_gbk_bin; +extern CHARSET_INFO my_charset_latin1; +extern CHARSET_INFO my_charset_latin1_german2_ci; +extern CHARSET_INFO my_charset_latin1_bin; +extern CHARSET_INFO my_charset_latin2_czech_ci; +extern CHARSET_INFO my_charset_sjis_japanese_ci; +extern CHARSET_INFO my_charset_sjis_bin; +extern CHARSET_INFO my_charset_tis620_thai_ci; +extern CHARSET_INFO my_charset_tis620_bin; +extern CHARSET_INFO my_charset_ucs2_general_ci; +extern CHARSET_INFO my_charset_ucs2_bin; +extern CHARSET_INFO my_charset_ucs2_unicode_ci; +extern CHARSET_INFO my_charset_ujis_japanese_ci; +extern CHARSET_INFO my_charset_ujis_bin; +extern CHARSET_INFO my_charset_utf8_general_ci; +extern CHARSET_INFO my_charset_utf8_unicode_ci; +extern CHARSET_INFO my_charset_utf8_bin; +extern CHARSET_INFO my_charset_cp1250_czech_ci; +extern CHARSET_INFO my_charset_filename; +extern size_t my_strnxfrm_simple(CHARSET_INFO *, uchar *, size_t, + const uchar *, size_t); +size_t my_strnxfrmlen_simple(CHARSET_INFO *, size_t); +extern int my_strnncoll_simple(CHARSET_INFO *, const uchar *, size_t, + const uchar *, size_t, my_bool); +extern int my_strnncollsp_simple(CHARSET_INFO *, const uchar *, size_t, + const uchar *, size_t, + my_bool diff_if_only_endspace_difference); +extern void my_hash_sort_simple(CHARSET_INFO *cs, + const uchar *key, size_t len, + ulong *nr1, ulong *nr2); +extern size_t my_lengthsp_8bit(CHARSET_INFO *cs, const char *ptr, size_t length); +extern uint my_instr_simple(struct charset_info_st *, + const char *b, size_t b_length, + const char *s, size_t s_length, + my_match_t *match, uint nmatch); +extern size_t my_caseup_str_8bit(CHARSET_INFO *, char *); +extern size_t my_casedn_str_8bit(CHARSET_INFO *, char *); +extern size_t my_caseup_8bit(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_casedn_8bit(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern int my_strcasecmp_8bit(CHARSET_INFO * cs, const char *, const char *); +int my_mb_wc_8bit(CHARSET_INFO *cs,ulong *wc, const uchar *s,const uchar *e); +int my_wc_mb_8bit(CHARSET_INFO *cs,ulong wc, uchar *s, uchar *e); +int my_mb_ctype_8bit(CHARSET_INFO *,int *, const uchar *,const uchar *); +int my_mb_ctype_mb(CHARSET_INFO *,int *, const uchar *,const uchar *); +size_t my_scan_8bit(CHARSET_INFO *cs, const char *b, const char *e, int sq); +size_t my_snprintf_8bit(struct charset_info_st *, char *to, size_t n, + const char *fmt, ...) + __attribute__((format(printf, 4, 5))); +long my_strntol_8bit(CHARSET_INFO *, const char *s, size_t l, int base, + char **e, int *err); +ulong my_strntoul_8bit(CHARSET_INFO *, const char *s, size_t l, int base, + char **e, int *err); +longlong my_strntoll_8bit(CHARSET_INFO *, const char *s, size_t l, int base, + char **e, int *err); +ulonglong my_strntoull_8bit(CHARSET_INFO *, const char *s, size_t l, int base, + char **e, int *err); +double my_strntod_8bit(CHARSET_INFO *, char *s, size_t l,char **e, + int *err); +size_t my_long10_to_str_8bit(CHARSET_INFO *, char *to, size_t l, int radix, + long int val); +size_t my_longlong10_to_str_8bit(CHARSET_INFO *, char *to, size_t l, int radix, + longlong val); +longlong my_strtoll10_8bit(CHARSET_INFO *cs, + const char *nptr, char **endptr, int *error); +longlong my_strtoll10_ucs2(CHARSET_INFO *cs, + const char *nptr, char **endptr, int *error); +ulonglong my_strntoull10rnd_8bit(CHARSET_INFO *cs, + const char *str, size_t length, int + unsigned_fl, char **endptr, int *error); +ulonglong my_strntoull10rnd_ucs2(CHARSET_INFO *cs, + const char *str, size_t length, + int unsigned_fl, char **endptr, int *error); +void my_fill_8bit(CHARSET_INFO *cs, char* to, size_t l, int fill); +my_bool my_like_range_simple(CHARSET_INFO *cs, + const char *ptr, size_t ptr_length, + pbool escape, pbool w_one, pbool w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_length, size_t *max_length); +my_bool my_like_range_mb(CHARSET_INFO *cs, + const char *ptr, size_t ptr_length, + pbool escape, pbool w_one, pbool w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_length, size_t *max_length); +my_bool my_like_range_ucs2(CHARSET_INFO *cs, + const char *ptr, size_t ptr_length, + pbool escape, pbool w_one, pbool w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_length, size_t *max_length); +int my_wildcmp_8bit(CHARSET_INFO *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); +int my_wildcmp_bin(CHARSET_INFO *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); +size_t my_numchars_8bit(CHARSET_INFO *, const char *b, const char *e); +size_t my_numcells_8bit(CHARSET_INFO *, const char *b, const char *e); +size_t my_charpos_8bit(CHARSET_INFO *, const char *b, const char *e, size_t pos); +size_t my_well_formed_len_8bit(CHARSET_INFO *, const char *b, const char *e, + size_t pos, int *error); +uint my_mbcharlen_8bit(CHARSET_INFO *, uint c); +extern size_t my_caseup_str_mb(CHARSET_INFO *, char *); +extern size_t my_casedn_str_mb(CHARSET_INFO *, char *); +extern size_t my_caseup_mb(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_casedn_mb(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern int my_strcasecmp_mb(CHARSET_INFO * cs,const char *, const char *); +int my_wildcmp_mb(CHARSET_INFO *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); +size_t my_numchars_mb(CHARSET_INFO *, const char *b, const char *e); +size_t my_numcells_mb(CHARSET_INFO *, const char *b, const char *e); +size_t my_charpos_mb(CHARSET_INFO *, const char *b, const char *e, size_t pos); +size_t my_well_formed_len_mb(CHARSET_INFO *, const char *b, const char *e, + size_t pos, int *error); +uint my_instr_mb(struct charset_info_st *, + const char *b, size_t b_length, + const char *s, size_t s_length, + my_match_t *match, uint nmatch); +int my_wildcmp_unicode(CHARSET_INFO *cs, + const char *str, const char *str_end, + const char *wildstr, const char *wildend, + int escape, int w_one, int w_many, + MY_UNICASE_INFO **weights); +extern my_bool my_parse_charset_xml(const char *bug, size_t len, + int (*add)(CHARSET_INFO *cs)); +extern char *my_strchr(CHARSET_INFO *cs, const char *str, const char *end, + pchar c); +my_bool my_propagate_simple(CHARSET_INFO *cs, const uchar *str, size_t len); +my_bool my_propagate_complex(CHARSET_INFO *cs, const uchar *str, size_t len); +uint my_string_repertoire(CHARSET_INFO *cs, const char *str, ulong len); +my_bool my_charset_is_ascii_based(CHARSET_INFO *cs); +my_bool my_charset_is_8bit_pure_ascii(CHARSET_INFO *cs); +#include <stdarg.h> +#include <typelib.h> +#include "my_alloc.h" +typedef struct st_used_mem +{ + struct st_used_mem *next; + unsigned int left; + unsigned int size; +} USED_MEM; +typedef struct st_mem_root +{ + USED_MEM *free; + USED_MEM *used; + USED_MEM *pre_alloc; + size_t min_malloc; + size_t block_size; + unsigned int block_num; + unsigned int first_block_usage; + void (*error_handler)(void); +} MEM_ROOT; +typedef struct st_typelib { + unsigned int count; + const char *name; + const char **type_names; + unsigned int *type_lengths; +} TYPELIB; +extern my_ulonglong find_typeset(char *x, TYPELIB *typelib,int *error_position); +extern int find_type_or_exit(const char *x, TYPELIB *typelib, + const char *option); +extern int find_type(char *x, const TYPELIB *typelib, unsigned int full_name); +extern void make_type(char *to,unsigned int nr,TYPELIB *typelib); +extern const char *get_type(TYPELIB *typelib,unsigned int nr); +extern TYPELIB *copy_typelib(MEM_ROOT *root, TYPELIB *from); +extern TYPELIB sql_protocol_typelib; +extern void *my_malloc(size_t Size,myf MyFlags); +extern void *my_realloc(void *oldpoint, size_t Size, myf MyFlags); +extern void my_no_flags_free(void *ptr); +extern void *my_memdup(const void *from,size_t length,myf MyFlags); +extern char *my_strdup(const char *from,myf MyFlags); +extern char *my_strndup(const char *from, size_t length, + myf MyFlags); +extern uint my_get_large_page_size(void); +extern uchar * my_large_malloc(size_t size, myf my_flags); +extern void my_large_free(uchar * ptr, myf my_flags); +extern int errno; +extern char errbuff[(2)][(256)]; +extern char *home_dir; +extern const char *my_progname; +extern char curr_dir[]; +extern int (*error_handler_hook)(uint my_err, const char *str,myf MyFlags); +extern int (*fatal_error_handler_hook)(uint my_err, const char *str, + myf MyFlags); +extern uint my_file_limit; +extern ulong my_thread_stack_size; +extern my_bool my_use_large_pages; +extern uint my_large_page_size; +extern CHARSET_INFO *default_charset_info; +extern CHARSET_INFO *all_charsets[256]; +extern CHARSET_INFO compiled_charsets[]; +extern ulong my_file_opened,my_stream_opened, my_tmp_file_created; +extern ulong my_file_total_opened; +extern uint mysys_usage_id; +extern my_bool my_init_done; +extern void (*my_sigtstp_cleanup)(void), + (*my_sigtstp_restart)(void), + (*my_abort_hook)(int); +extern int my_umask, + my_umask_dir, + my_recived_signals, + my_safe_to_handle_signal, + my_dont_interrupt; +extern my_bool mysys_uses_curses, my_use_symdir; +extern ulong sf_malloc_cur_memory, sf_malloc_max_memory; +extern ulong my_default_record_cache_size; +extern my_bool my_disable_locking, my_disable_async_io, + my_disable_flush_key_blocks, my_disable_symlinks; +extern char wild_many,wild_one,wild_prefix; +extern const char *charsets_dir; +extern char *my_defaults_extra_file; +extern const char *my_defaults_group_suffix; +extern const char *my_defaults_file; +extern my_bool timed_mutexes; +typedef struct wild_file_pack +{ + uint wilds; + uint not_pos; + char * *wild; +} WF_PACK; +enum loglevel { + ERROR_LEVEL, + WARNING_LEVEL, + INFORMATION_LEVEL +}; +enum cache_type +{ + TYPE_NOT_SET= 0, READ_CACHE, WRITE_CACHE, + SEQ_READ_APPEND , + READ_FIFO, READ_NET,WRITE_NET}; +enum flush_type +{ + FLUSH_KEEP, + FLUSH_RELEASE, + FLUSH_IGNORE_CHANGED, + FLUSH_FORCE_WRITE +}; +typedef struct st_record_cache +{ + File file; + int rc_seek,error,inited; + uint rc_length,read_length,reclength; + my_off_t rc_record_pos,end_of_file; + uchar *rc_buff,*rc_buff2,*rc_pos,*rc_end,*rc_request_pos; + enum cache_type type; +} RECORD_CACHE; +enum file_type +{ + UNOPEN = 0, FILE_BY_OPEN, FILE_BY_CREATE, STREAM_BY_FOPEN, STREAM_BY_FDOPEN, + FILE_BY_MKSTEMP, FILE_BY_DUP +}; +struct st_my_file_info +{ + char * name; + enum file_type type; +}; +extern struct st_my_file_info *my_file_info; +typedef struct st_dynamic_array +{ + uchar *buffer; + uint elements,max_element; + uint alloc_increment; + uint size_of_element; +} DYNAMIC_ARRAY; +typedef struct st_my_tmpdir +{ + DYNAMIC_ARRAY full_list; + char **list; + uint cur, max; + pthread_mutex_t mutex; +} MY_TMPDIR; +typedef struct st_dynamic_string +{ + char *str; + size_t length,max_length,alloc_increment; +} DYNAMIC_STRING; +struct st_io_cache; +typedef int (*IO_CACHE_CALLBACK)(struct st_io_cache*); +typedef struct st_io_cache_share +{ + pthread_mutex_t mutex; + pthread_cond_t cond; + pthread_cond_t cond_writer; + my_off_t pos_in_file; + struct st_io_cache *source_cache; + uchar *buffer; + uchar *read_end; + int running_threads; + int total_threads; + int error; +} IO_CACHE_SHARE; +typedef struct st_io_cache +{ + my_off_t pos_in_file; + my_off_t end_of_file; + uchar *read_pos; + uchar *read_end; + uchar *buffer; + uchar *request_pos; + uchar *write_buffer; + uchar *append_read_pos; + uchar *write_pos; + uchar *write_end; + uchar **current_pos, **current_end; + pthread_mutex_t append_buffer_lock; + IO_CACHE_SHARE *share; + int (*read_function)(struct st_io_cache *,uchar *,size_t); + int (*write_function)(struct st_io_cache *,const uchar *,size_t); + enum cache_type type; + IO_CACHE_CALLBACK pre_read; + IO_CACHE_CALLBACK post_read; + IO_CACHE_CALLBACK pre_close; + ulong disk_writes; + void* arg; + char *file_name; + char *dir,*prefix; + File file; + int seek_not_done,error; + size_t buffer_length; + size_t read_length; + myf myflags; + my_bool alloced_buffer; +} IO_CACHE; +typedef int (*qsort2_cmp)(const void *, const void *, const void *); +int my_b_copy_to_file(IO_CACHE *cache, FILE *file); +my_off_t my_b_append_tell(IO_CACHE* info); +my_off_t my_b_safe_tell(IO_CACHE* info); +typedef uint32 ha_checksum; +typedef int (*Process_option_func)(void *ctx, const char *group_name, + const char *option); +#include <my_alloc.h> +extern int my_copy(const char *from,const char *to,myf MyFlags); +extern int my_append(const char *from,const char *to,myf MyFlags); +extern int my_delete(const char *name,myf MyFlags); +extern int my_getwd(char * buf,size_t size,myf MyFlags); +extern int my_setwd(const char *dir,myf MyFlags); +extern int my_lock(File fd,int op,my_off_t start, my_off_t length,myf MyFlags); +extern void *my_once_alloc(size_t Size,myf MyFlags); +extern void my_once_free(void); +extern char *my_once_strdup(const char *src,myf myflags); +extern void *my_once_memdup(const void *src, size_t len, myf myflags); +extern File my_open(const char *FileName,int Flags,myf MyFlags); +extern File my_register_filename(File fd, const char *FileName, + enum file_type type_of_file, + uint error_message_number, myf MyFlags); +extern File my_create(const char *FileName,int CreateFlags, + int AccessFlags, myf MyFlags); +extern int my_close(File Filedes,myf MyFlags); +extern File my_dup(File file, myf MyFlags); +extern int my_mkdir(const char *dir, int Flags, myf MyFlags); +extern int my_readlink(char *to, const char *filename, myf MyFlags); +extern int my_realpath(char *to, const char *filename, myf MyFlags); +extern File my_create_with_symlink(const char *linkname, const char *filename, + int createflags, int access_flags, + myf MyFlags); +extern int my_delete_with_symlink(const char *name, myf MyFlags); +extern int my_rename_with_symlink(const char *from,const char *to,myf MyFlags); +extern int my_symlink(const char *content, const char *linkname, myf MyFlags); +extern size_t my_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags); +extern size_t my_pread(File Filedes,uchar *Buffer,size_t Count,my_off_t offset, + myf MyFlags); +extern int my_rename(const char *from,const char *to,myf MyFlags); +extern my_off_t my_seek(File fd,my_off_t pos,int whence,myf MyFlags); +extern my_off_t my_tell(File fd,myf MyFlags); +extern size_t my_write(File Filedes,const uchar *Buffer,size_t Count, + myf MyFlags); +extern size_t my_pwrite(File Filedes,const uchar *Buffer,size_t Count, + my_off_t offset,myf MyFlags); +extern size_t my_fread(FILE *stream,uchar *Buffer,size_t Count,myf MyFlags); +extern size_t my_fwrite(FILE *stream,const uchar *Buffer,size_t Count, + myf MyFlags); +extern my_off_t my_fseek(FILE *stream,my_off_t pos,int whence,myf MyFlags); +extern my_off_t my_ftell(FILE *stream,myf MyFlags); +extern void *_mymalloc(size_t uSize,const char *sFile, + uint uLine, myf MyFlag); +extern void *_myrealloc(void *pPtr,size_t uSize,const char *sFile, + uint uLine, myf MyFlag); +extern void * my_multi_malloc (myf MyFlags, ...); +extern void _myfree(void *pPtr,const char *sFile,uint uLine, myf MyFlag); +extern int _sanity(const char *sFile, uint uLine); +extern void *_my_memdup(const void *from, size_t length, + const char *sFile, uint uLine,myf MyFlag); +extern char * _my_strdup(const char *from, const char *sFile, uint uLine, + myf MyFlag); +extern char *_my_strndup(const char *from, size_t length, + const char *sFile, uint uLine, + myf MyFlag); +extern void *my_memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen); +extern int check_if_legal_filename(const char *path); +extern int check_if_legal_tablename(const char *path); +extern void init_glob_errs(void); +extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags); +extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags); +extern int my_fclose(FILE *fd,myf MyFlags); +extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags); +extern int my_sync(File fd, myf my_flags); +extern int my_sync_dir(const char *dir_name, myf my_flags); +extern int my_sync_dir_by_file(const char *file_name, myf my_flags); +extern int my_error (int nr,myf MyFlags, ...); +extern int my_printf_error (uint my_err, const char *format, myf MyFlags, ...) + __attribute__((format(printf, 2, 4))); +extern int my_error_register(const char **errmsgs, int first, int last); +extern const char **my_error_unregister(int first, int last); +extern int my_message(uint my_err, const char *str,myf MyFlags); +extern int my_message_no_curses(uint my_err, const char *str,myf MyFlags); +extern int my_message_curses(uint my_err, const char *str,myf MyFlags); +extern my_bool my_init(void); +extern void my_end(int infoflag); +extern int my_redel(const char *from, const char *to, int MyFlags); +extern int my_copystat(const char *from, const char *to, int MyFlags); +extern char * my_filename(File fd); +extern my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist); +extern char *my_tmpdir(MY_TMPDIR *tmpdir); +extern void free_tmpdir(MY_TMPDIR *tmpdir); +extern void my_remember_signal(int signal_number,void (*func)(int)); +extern size_t dirname_part(char * to,const char *name, size_t *to_res_length); +extern size_t dirname_length(const char *name); +extern int test_if_hard_path(const char *dir_name); +extern my_bool has_path(const char *name); +extern char *convert_dirname(char *to, const char *from, const char *from_end); +extern void to_unix_path(char * name); +extern char * fn_ext(const char *name); +extern char * fn_same(char * toname,const char *name,int flag); +extern char * fn_format(char * to,const char *name,const char *dir, + const char *form, uint flag); +extern size_t strlength(const char *str); +extern void pack_dirname(char * to,const char *from); +extern size_t unpack_dirname(char * to,const char *from); +extern size_t cleanup_dirname(char * to,const char *from); +extern size_t system_filename(char * to,const char *from); +extern size_t unpack_filename(char * to,const char *from); +extern char * intern_filename(char * to,const char *from); +extern char * directory_file_name(char * dst, const char *src); +extern int pack_filename(char * to, const char *name, size_t max_length); +extern char * my_path(char * to,const char *progname, + const char *own_pathname_part); +extern char * my_load_path(char * to, const char *path, + const char *own_path_prefix); +extern int wild_compare(const char *str,const char *wildstr, + pbool str_is_pattern); +extern WF_PACK *wf_comp(char * str); +extern int wf_test(struct wild_file_pack *wf_pack,const char *name); +extern void wf_end(struct wild_file_pack *buffer); +extern size_t strip_sp(char * str); +extern my_bool array_append_string_unique(const char *str, + const char **array, size_t size); +extern void get_date(char * to,int timeflag,time_t use_time); +extern void soundex(CHARSET_INFO *, char * out_pntr, char * in_pntr, + pbool remove_garbage); +extern int init_record_cache(RECORD_CACHE *info,size_t cachesize,File file, + size_t reclength,enum cache_type type, + pbool use_async_io); +extern int read_cache_record(RECORD_CACHE *info,uchar *to); +extern int end_record_cache(RECORD_CACHE *info); +extern int write_cache_record(RECORD_CACHE *info,my_off_t filepos, + const uchar *record,size_t length); +extern int flush_write_cache(RECORD_CACHE *info); +extern long my_clock(void); +extern void sigtstp_handler(int signal_number); +extern void handle_recived_signals(void); +extern void my_set_alarm_variable(int signo); +extern void my_string_ptr_sort(uchar *base,uint items,size_t size); +extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements, + size_t size_of_element,uchar *buffer[]); +extern void my_qsort(void *base_ptr, size_t total_elems, size_t size, + qsort_cmp cmp); +extern void my_qsort2(void *base_ptr, size_t total_elems, size_t size, + qsort2_cmp cmp, void *cmp_argument); +extern qsort2_cmp get_ptr_compare(size_t); +void my_store_ptr(uchar *buff, size_t pack_length, my_off_t pos); +my_off_t my_get_ptr(uchar *ptr, size_t pack_length); +extern int init_io_cache(IO_CACHE *info,File file,size_t cachesize, + enum cache_type type,my_off_t seek_offset, + pbool use_async_io, myf cache_myflags); +extern my_bool reinit_io_cache(IO_CACHE *info,enum cache_type type, + my_off_t seek_offset,pbool use_async_io, + pbool clear_cache); +extern void setup_io_cache(IO_CACHE* info); +extern int _my_b_read(IO_CACHE *info,uchar *Buffer,size_t Count); +extern int _my_b_read_r(IO_CACHE *info,uchar *Buffer,size_t Count); +extern void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare, + IO_CACHE *write_cache, uint num_threads); +extern void remove_io_thread(IO_CACHE *info); +extern int _my_b_seq_read(IO_CACHE *info,uchar *Buffer,size_t Count); +extern int _my_b_net_read(IO_CACHE *info,uchar *Buffer,size_t Count); +extern int _my_b_get(IO_CACHE *info); +extern int _my_b_async_read(IO_CACHE *info,uchar *Buffer,size_t Count); +extern int _my_b_write(IO_CACHE *info,const uchar *Buffer,size_t Count); +extern int my_b_append(IO_CACHE *info,const uchar *Buffer,size_t Count); +extern int my_b_safe_write(IO_CACHE *info,const uchar *Buffer,size_t Count); +extern int my_block_write(IO_CACHE *info, const uchar *Buffer, + size_t Count, my_off_t pos); +extern int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock); +extern int end_io_cache(IO_CACHE *info); +extern size_t my_b_fill(IO_CACHE *info); +extern void my_b_seek(IO_CACHE *info,my_off_t pos); +extern size_t my_b_gets(IO_CACHE *info, char *to, size_t max_length); +extern my_off_t my_b_filelength(IO_CACHE *info); +extern size_t my_b_printf(IO_CACHE *info, const char* fmt, ...); +extern size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list ap); +extern my_bool open_cached_file(IO_CACHE *cache,const char *dir, + const char *prefix, size_t cache_size, + myf cache_myflags); +extern my_bool real_open_cached_file(IO_CACHE *cache); +extern void close_cached_file(IO_CACHE *cache); +File create_temp_file(char *to, const char *dir, const char *pfx, + int mode, myf MyFlags); +extern my_bool init_dynamic_array2(DYNAMIC_ARRAY *array,uint element_size, + void *init_buffer, uint init_alloc, + uint alloc_increment + ); +extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size, + uint init_alloc,uint alloc_increment + ); +extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,uchar * element); +extern uchar *alloc_dynamic(DYNAMIC_ARRAY *array); +extern uchar *pop_dynamic(DYNAMIC_ARRAY*); +extern my_bool set_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index); +extern my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements); +extern void get_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index); +extern void delete_dynamic(DYNAMIC_ARRAY *array); +extern void delete_dynamic_element(DYNAMIC_ARRAY *array, uint array_index); +extern void freeze_size(DYNAMIC_ARRAY *array); +extern int get_index_dynamic(DYNAMIC_ARRAY *array, uchar * element); +extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, + size_t init_alloc,size_t alloc_increment); +extern my_bool dynstr_append(DYNAMIC_STRING *str, const char *append); +my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append, + size_t length); +extern my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append, + ...); +extern my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str); +extern my_bool dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size); +extern my_bool dynstr_trunc(DYNAMIC_STRING *str, size_t n); +extern void dynstr_free(DYNAMIC_STRING *str); +extern void init_alloc_root(MEM_ROOT *mem_root, size_t block_size, + size_t pre_alloc_size); +extern void *alloc_root(MEM_ROOT *mem_root, size_t Size); +extern void *multi_alloc_root(MEM_ROOT *mem_root, ...); +extern void free_root(MEM_ROOT *root, myf MyFLAGS); +extern void set_prealloc_root(MEM_ROOT *root, char *ptr); +extern void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size, + size_t prealloc_size); +extern char *strdup_root(MEM_ROOT *root,const char *str); +extern char *strmake_root(MEM_ROOT *root,const char *str,size_t len); +extern void *memdup_root(MEM_ROOT *root,const void *str, size_t len); +extern int get_defaults_options(int argc, char **argv, + char **defaults, char **extra_defaults, + char **group_suffix); +extern int load_defaults(const char *conf_file, const char **groups, + int *argc, char ***argv); +extern int modify_defaults_file(const char *file_location, const char *option, + const char *option_value, + const char *section_name, int remove_option); +extern int my_search_option_files(const char *conf_file, int *argc, + char ***argv, uint *args_used, + Process_option_func func, void *func_ctx); +extern void free_defaults(char **argv); +extern void my_print_default_files(const char *conf_file); +extern void print_defaults(const char *conf_file, const char **groups); +extern my_bool my_compress(uchar *, size_t *, size_t *); +extern my_bool my_uncompress(uchar *, size_t , size_t *); +extern uchar *my_compress_alloc(const uchar *packet, size_t *len, + size_t *complen); +extern int packfrm(uchar *, size_t, uchar **, size_t *); +extern int unpackfrm(uchar **, size_t *, const uchar *); +extern ha_checksum my_checksum(ha_checksum crc, const uchar *mem, + size_t count); +extern void my_sleep(ulong m_seconds); +extern ulong crc32(ulong crc, const uchar *buf, uint len); +extern uint my_set_max_open_files(uint files); +void my_free_open_file_info(void); +extern time_t my_time(myf flags); +extern ulonglong my_getsystime(void); +extern ulonglong my_micro_time(); +extern ulonglong my_micro_time_and_time(time_t *time_arg); +time_t my_time_possible_from_micro(ulonglong microtime); +extern my_bool my_gethwaddr(uchar *to); +extern int my_getncpus(); +#include <sys/mman.h> +int my_msync(int, void *, size_t, int); +extern uint get_charset_number(const char *cs_name, uint cs_flags); +extern uint get_collation_number(const char *name); +extern const char *get_charset_name(uint cs_number); +extern CHARSET_INFO *get_charset(uint cs_number, myf flags); +extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags); +extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, + uint cs_flags, myf my_flags); +extern my_bool resolve_charset(const char *cs_name, + CHARSET_INFO *default_cs, + CHARSET_INFO **cs); +extern my_bool resolve_collation(const char *cl_name, + CHARSET_INFO *default_cl, + CHARSET_INFO **cl); +extern void free_charsets(void); +extern char *get_charsets_dir(char *buf); +extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2); +extern my_bool init_compiled_charsets(myf flags); +extern void add_compiled_collation(CHARSET_INFO *cs); +extern size_t escape_string_for_mysql(CHARSET_INFO *charset_info, + char *to, size_t to_length, + const char *from, size_t length); +extern size_t escape_quotes_for_mysql(CHARSET_INFO *charset_info, + char *to, size_t to_length, + const char *from, size_t length); +extern void thd_increment_bytes_sent(ulong length); +extern void thd_increment_bytes_received(ulong length); +extern void thd_increment_net_big_packet_count(ulong length); +#include <my_time.h> +#include "my_global.h" +#include "mysql_time.h" +enum enum_mysql_timestamp_type +{ + MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1, + MYSQL_TIMESTAMP_DATE= 0, MYSQL_TIMESTAMP_DATETIME= 1, MYSQL_TIMESTAMP_TIME= 2 +}; +typedef struct st_mysql_time +{ + unsigned int year, month, day, hour, minute, second; + unsigned long second_part; + my_bool neg; + enum enum_mysql_timestamp_type time_type; +} MYSQL_TIME; +extern ulonglong log_10_int[20]; +extern uchar days_in_month[]; +typedef long my_time_t; +my_bool check_date(const MYSQL_TIME *ltime, my_bool not_zero_date, + ulong flags, int *was_cut); +enum enum_mysql_timestamp_type +str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, + uint flags, int *was_cut); +longlong number_to_datetime(longlong nr, MYSQL_TIME *time_res, + uint flags, int *was_cut); +ulonglong TIME_to_ulonglong_datetime(const MYSQL_TIME *); +ulonglong TIME_to_ulonglong_date(const MYSQL_TIME *); +ulonglong TIME_to_ulonglong_time(const MYSQL_TIME *); +ulonglong TIME_to_ulonglong(const MYSQL_TIME *); +my_bool str_to_time(const char *str,uint length, MYSQL_TIME *l_time, + int *warning); +int check_time_range(struct st_mysql_time *, int *warning); +long calc_daynr(uint year,uint month,uint day); +uint calc_days_in_year(uint year); +uint year_2000_handling(uint year); +void my_init_time(void); +static inline my_bool validate_timestamp_range(const MYSQL_TIME *t) +{ + if ((t->year > 2038 || t->year < (1900 + 70 - 1)) || + (t->year == 2038 && (t->month > 1 || t->day > 19)) || + (t->year == (1900 + 70 - 1) && (t->month < 12 || t->day < 31))) + return (0); + return (1); +} +my_time_t +my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, + my_bool *in_dst_time_gap); +void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type); +int my_time_to_str(const MYSQL_TIME *l_time, char *to); +int my_date_to_str(const MYSQL_TIME *l_time, char *to); +int my_datetime_to_str(const MYSQL_TIME *l_time, char *to); +int my_TIME_to_str(const MYSQL_TIME *l_time, char *to); +enum interval_type +{ + INTERVAL_YEAR, INTERVAL_QUARTER, INTERVAL_MONTH, INTERVAL_WEEK, INTERVAL_DAY, + INTERVAL_HOUR, INTERVAL_MINUTE, INTERVAL_SECOND, INTERVAL_MICROSECOND, + INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE, + INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND, + INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND, + INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND, INTERVAL_LAST +}; +#include <m_string.h> +#include <strings.h> +#include <string.h> +#include <stdarg.h> +#include <strings.h> +#include <memory.h> +extern void *(*my_str_malloc)(size_t); +extern void (*my_str_free)(void *); +extern char *stpcpy(char *, const char *); +extern char _dig_vec_upper[]; +extern char _dig_vec_lower[]; +extern const double log_10[309]; +extern void bmove512(uchar *dst,const uchar *src,size_t len); +extern void bmove_upp(uchar *dst,const uchar *src,size_t len); +extern void bchange(uchar *dst,size_t old_len,const uchar *src, + size_t new_len,size_t tot_len); +extern void strappend(char *s,size_t len,pchar fill); +extern char *strend(const char *s); +extern char *strcend(const char *, pchar); +extern char *strfield(char *src,int fields,int chars,int blanks, + int tabch); +extern char *strfill(char * s,size_t len,pchar fill); +extern size_t strinstr(const char *str,const char *search); +extern size_t r_strinstr(const char *str, size_t from, const char *search); +extern char *strkey(char *dst,char *head,char *tail,char *flags); +extern char *strmake(char *dst,const char *src,size_t length); +extern char *strnmov(char *dst,const char *src,size_t n); +extern char *strsuff(const char *src,const char *suffix); +extern char *strcont(const char *src,const char *set); +extern char *strxcat (char *dst,const char *src, ...); +extern char *strxmov (char *dst,const char *src, ...); +extern char *strxcpy (char *dst,const char *src, ...); +extern char *strxncat (char *dst,size_t len, const char *src, ...); +extern char *strxnmov (char *dst,size_t len, const char *src, ...); +extern char *strxncpy (char *dst,size_t len, const char *src, ...); +extern int is_prefix(const char *, const char *); +double my_strtod(const char *str, char **end, int *error); +double my_atof(const char *nptr); +extern char *llstr(longlong value,char *buff); +extern char *ullstr(longlong value,char *buff); +extern char *int2str(long val, char *dst, int radix, int upcase); +extern char *int10_to_str(long val,char *dst,int radix); +extern char *str2int(const char *src,int radix,long lower,long upper, + long *val); +longlong my_strtoll10(const char *nptr, char **endptr, int *error); +extern char *longlong2str(longlong val,char *dst,int radix); +extern char *longlong10_to_str(longlong val,char *dst,int radix); +extern size_t my_vsnprintf(char *str, size_t n, + const char *format, va_list ap); +extern size_t my_snprintf(char *to, size_t n, const char *fmt, ...) + __attribute__((format(printf, 3, 4))); +struct st_mysql_lex_string +{ + char *str; + size_t length; +}; +typedef struct st_mysql_lex_string LEX_STRING; +#include <hash.h> +typedef uchar *(*hash_get_key)(const uchar *,size_t*,my_bool); +typedef void (*hash_free_key)(void *); +typedef struct st_hash { + size_t key_offset,key_length; + size_t blength; + ulong records; + uint flags; + DYNAMIC_ARRAY array; + hash_get_key get_key; + void (*free)(void *); + CHARSET_INFO *charset; +} HASH; +typedef uint HASH_SEARCH_STATE; +my_bool _hash_init(HASH *hash, uint growth_size,CHARSET_INFO *charset, + ulong default_array_elements, size_t key_offset, + size_t key_length, hash_get_key get_key, + void (*free_element)(void*), uint flags ); +void hash_free(HASH *tree); +void my_hash_reset(HASH *hash); +uchar *hash_element(HASH *hash,ulong idx); +uchar *hash_search(const HASH *info, const uchar *key, size_t length); +uchar *hash_first(const HASH *info, const uchar *key, size_t length, + HASH_SEARCH_STATE *state); +uchar *hash_next(const HASH *info, const uchar *key, size_t length, + HASH_SEARCH_STATE *state); +my_bool my_hash_insert(HASH *info,const uchar *data); +my_bool hash_delete(HASH *hash,uchar *record); +my_bool hash_update(HASH *hash,uchar *record,uchar *old_key,size_t old_key_length); +void hash_replace(HASH *hash, HASH_SEARCH_STATE *state, uchar *new_row); +my_bool hash_check(HASH *hash); +#include <signal.h> +#include <thr_lock.h> +#include <my_pthread.h> +#include <my_list.h> +typedef struct st_list { + struct st_list *prev,*next; + void *data; +} LIST; +typedef int (*list_walk_action)(void *,void *); +extern LIST *list_add(LIST *root,LIST *element); +extern LIST *list_delete(LIST *root,LIST *element); +extern LIST *list_cons(void *data,LIST *root); +extern LIST *list_reverse(LIST *root); +extern void list_free(LIST *root,unsigned int free_data); +extern unsigned int list_length(LIST *); +extern int list_walk(LIST *,list_walk_action action,unsigned char * argument); +struct st_thr_lock; +extern ulong locks_immediate,locks_waited ; +enum thr_lock_type { TL_IGNORE=-1, + TL_UNLOCK, + TL_READ, + TL_READ_WITH_SHARED_LOCKS, + TL_READ_HIGH_PRIORITY, + TL_READ_NO_INSERT, + TL_WRITE_ALLOW_WRITE, + TL_WRITE_ALLOW_READ, + TL_WRITE_CONCURRENT_INSERT, + TL_WRITE_DELAYED, + TL_WRITE_DEFAULT, + TL_WRITE_LOW_PRIORITY, + TL_WRITE, + TL_WRITE_ONLY}; +enum enum_thr_lock_result { THR_LOCK_SUCCESS= 0, THR_LOCK_ABORTED= 1, + THR_LOCK_WAIT_TIMEOUT= 2, THR_LOCK_DEADLOCK= 3 }; +extern ulong max_write_lock_count; +extern ulong table_lock_wait_timeout; +extern my_bool thr_lock_inited; +extern enum thr_lock_type thr_upgraded_concurrent_insert_lock; +typedef struct st_thr_lock_info +{ + pthread_t thread; + my_thread_id thread_id; + ulong n_cursors; +} THR_LOCK_INFO; +typedef struct st_thr_lock_owner +{ + THR_LOCK_INFO *info; +} THR_LOCK_OWNER; +typedef struct st_thr_lock_data { + THR_LOCK_OWNER *owner; + struct st_thr_lock_data *next,**prev; + struct st_thr_lock *lock; + pthread_cond_t *cond; + enum thr_lock_type type; + void *status_param; + void *debug_print_param; +} THR_LOCK_DATA; +struct st_lock_list { + THR_LOCK_DATA *data,**last; +}; +typedef struct st_thr_lock { + LIST list; + pthread_mutex_t mutex; + struct st_lock_list read_wait; + struct st_lock_list read; + struct st_lock_list write_wait; + struct st_lock_list write; + ulong write_lock_count; + uint read_no_write_count; + void (*get_status)(void*, int); + void (*copy_status)(void*,void*); + void (*update_status)(void*); + void (*restore_status)(void*); + my_bool (*check_status)(void *); +} THR_LOCK; +extern LIST *thr_lock_thread_list; +extern pthread_mutex_t THR_LOCK_lock; +my_bool init_thr_lock(void); +void thr_lock_info_init(THR_LOCK_INFO *info); +void thr_lock_init(THR_LOCK *lock); +void thr_lock_delete(THR_LOCK *lock); +void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, + void *status_param); +enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, + THR_LOCK_OWNER *owner, + enum thr_lock_type lock_type); +void thr_unlock(THR_LOCK_DATA *data); +enum enum_thr_lock_result thr_multi_lock(THR_LOCK_DATA **data, + uint count, THR_LOCK_OWNER *owner); +void thr_multi_unlock(THR_LOCK_DATA **data,uint count); +void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock); +my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread); +void thr_print_locks(void); +my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data); +void thr_downgrade_write_lock(THR_LOCK_DATA *data, + enum thr_lock_type new_lock_type); +my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data); +#include <my_base.h> +#include <my_global.h> +#include <my_dir.h> +#include <sys/stat.h> +typedef struct fileinfo +{ + char *name; + struct stat *mystat; +} FILEINFO; +typedef struct st_my_dir +{ + struct fileinfo *dir_entry; + uint number_off_files; +} MY_DIR; +extern MY_DIR *my_dir(const char *path,myf MyFlags); +extern void my_dirend(MY_DIR *buffer); +extern struct stat *my_stat(const char *path, struct stat *stat_area, myf my_flags); +extern int my_fstat(int filenr, struct stat *stat_area, myf MyFlags); +#include <my_sys.h> +#include <m_string.h> +#include <errno.h> +#include <my_list.h> +enum ha_rkey_function { + HA_READ_KEY_EXACT, + HA_READ_KEY_OR_NEXT, + HA_READ_KEY_OR_PREV, + HA_READ_AFTER_KEY, + HA_READ_BEFORE_KEY, + HA_READ_PREFIX, + HA_READ_PREFIX_LAST, + HA_READ_PREFIX_LAST_OR_PREV, + HA_READ_MBR_CONTAIN, + HA_READ_MBR_INTERSECT, + HA_READ_MBR_WITHIN, + HA_READ_MBR_DISJOINT, + HA_READ_MBR_EQUAL +}; +enum ha_key_alg { + HA_KEY_ALG_UNDEF= 0, + HA_KEY_ALG_BTREE= 1, + HA_KEY_ALG_RTREE= 2, + HA_KEY_ALG_HASH= 3, + HA_KEY_ALG_FULLTEXT= 4 +}; +enum ha_storage_media { + HA_SM_DEFAULT= 0, + HA_SM_DISK= 1, + HA_SM_MEMORY= 2 +}; +enum ha_extra_function { + HA_EXTRA_NORMAL=0, + HA_EXTRA_QUICK=1, + HA_EXTRA_NOT_USED=2, + HA_EXTRA_CACHE=3, + HA_EXTRA_NO_CACHE=4, + HA_EXTRA_NO_READCHECK=5, + HA_EXTRA_READCHECK=6, + HA_EXTRA_KEYREAD=7, + HA_EXTRA_NO_KEYREAD=8, + HA_EXTRA_NO_USER_CHANGE=9, + HA_EXTRA_KEY_CACHE=10, + HA_EXTRA_NO_KEY_CACHE=11, + HA_EXTRA_WAIT_LOCK=12, + HA_EXTRA_NO_WAIT_LOCK=13, + HA_EXTRA_WRITE_CACHE=14, + HA_EXTRA_FLUSH_CACHE=15, + HA_EXTRA_NO_KEYS=16, + HA_EXTRA_KEYREAD_CHANGE_POS=17, + HA_EXTRA_REMEMBER_POS=18, + HA_EXTRA_RESTORE_POS=19, + HA_EXTRA_REINIT_CACHE=20, + HA_EXTRA_FORCE_REOPEN=21, + HA_EXTRA_FLUSH, + HA_EXTRA_NO_ROWS, + HA_EXTRA_RESET_STATE, + HA_EXTRA_IGNORE_DUP_KEY, + HA_EXTRA_NO_IGNORE_DUP_KEY, + HA_EXTRA_PREPARE_FOR_DROP, + HA_EXTRA_PREPARE_FOR_UPDATE, + HA_EXTRA_PRELOAD_BUFFER_SIZE, + HA_EXTRA_CHANGE_KEY_TO_UNIQUE, + HA_EXTRA_CHANGE_KEY_TO_DUP, + HA_EXTRA_KEYREAD_PRESERVE_FIELDS, + HA_EXTRA_MMAP, + HA_EXTRA_IGNORE_NO_KEY, + HA_EXTRA_NO_IGNORE_NO_KEY, + HA_EXTRA_MARK_AS_LOG_TABLE, + HA_EXTRA_WRITE_CAN_REPLACE, + HA_EXTRA_WRITE_CANNOT_REPLACE, + HA_EXTRA_DELETE_CANNOT_BATCH, + HA_EXTRA_UPDATE_CANNOT_BATCH, + HA_EXTRA_INSERT_WITH_UPDATE, + HA_EXTRA_PREPARE_FOR_RENAME, + HA_EXTRA_ATTACH_CHILDREN, + HA_EXTRA_DETACH_CHILDREN +}; +enum ha_panic_function { + HA_PANIC_CLOSE, + HA_PANIC_WRITE, + HA_PANIC_READ +}; +enum ha_base_keytype { + HA_KEYTYPE_END=0, + HA_KEYTYPE_TEXT=1, + HA_KEYTYPE_BINARY=2, + HA_KEYTYPE_SHORT_INT=3, + HA_KEYTYPE_LONG_INT=4, + HA_KEYTYPE_FLOAT=5, + HA_KEYTYPE_DOUBLE=6, + HA_KEYTYPE_NUM=7, + HA_KEYTYPE_USHORT_INT=8, + HA_KEYTYPE_ULONG_INT=9, + HA_KEYTYPE_LONGLONG=10, + HA_KEYTYPE_ULONGLONG=11, + HA_KEYTYPE_INT24=12, + HA_KEYTYPE_UINT24=13, + HA_KEYTYPE_INT8=14, + HA_KEYTYPE_VARTEXT1=15, + HA_KEYTYPE_VARBINARY1=16, + HA_KEYTYPE_VARTEXT2=17, + HA_KEYTYPE_VARBINARY2=18, + HA_KEYTYPE_BIT=19 +}; +typedef ulong key_part_map; +enum en_fieldtype { + FIELD_LAST=-1,FIELD_NORMAL,FIELD_SKIP_ENDSPACE,FIELD_SKIP_PRESPACE, + FIELD_SKIP_ZERO,FIELD_BLOB,FIELD_CONSTANT,FIELD_INTERVALL,FIELD_ZERO, + FIELD_VARCHAR,FIELD_CHECK, + FIELD_enum_val_count +}; +enum data_file_type { + STATIC_RECORD, DYNAMIC_RECORD, COMPRESSED_RECORD, BLOCK_RECORD +}; +typedef struct st_key_range +{ + const uchar *key; + uint length; + key_part_map keypart_map; + enum ha_rkey_function flag; +} key_range; +typedef struct st_key_multi_range +{ + key_range start_key; + key_range end_key; + char *ptr; + uint range_flag; +} KEY_MULTI_RANGE; +typedef my_off_t ha_rows; +typedef void (* invalidator_by_filename)(const char * filename); +#include <queues.h> +typedef struct st_queue { + uchar **root; + void *first_cmp_arg; + uint elements; + uint max_elements; + uint offset_to_key; + int max_at_top; + int (*compare)(void *, uchar *,uchar *); + uint auto_extent; +} QUEUE; +typedef int (*queue_compare)(void *,uchar *, uchar *); +int init_queue(QUEUE *queue,uint max_elements,uint offset_to_key, + pbool max_at_top, queue_compare compare, + void *first_cmp_arg); +int init_queue_ex(QUEUE *queue,uint max_elements,uint offset_to_key, + pbool max_at_top, queue_compare compare, + void *first_cmp_arg, uint auto_extent); +int reinit_queue(QUEUE *queue,uint max_elements,uint offset_to_key, + pbool max_at_top, queue_compare compare, + void *first_cmp_arg); +int resize_queue(QUEUE *queue, uint max_elements); +void delete_queue(QUEUE *queue); +void queue_insert(QUEUE *queue,uchar *element); +int queue_insert_safe(QUEUE *queue, uchar *element); +uchar *queue_remove(QUEUE *queue,uint idx); +void _downheap(QUEUE *queue,uint idx); +void queue_fix(QUEUE *queue); +#include "sql_bitmap.h" +#include <my_bitmap.h> +#include <m_string.h> +typedef uint32 my_bitmap_map; +typedef struct st_bitmap +{ + my_bitmap_map *bitmap; + uint n_bits; + my_bitmap_map last_word_mask; + my_bitmap_map *last_word_ptr; + pthread_mutex_t *mutex; +} MY_BITMAP; +extern void create_last_word_mask(MY_BITMAP *map); +extern my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits, + my_bool thread_safe); +extern my_bool bitmap_is_clear_all(const MY_BITMAP *map); +extern my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size); +extern my_bool bitmap_is_set_all(const MY_BITMAP *map); +extern my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2); +extern my_bool bitmap_is_overlapping(const MY_BITMAP *map1, + const MY_BITMAP *map2); +extern my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit); +extern my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit); +extern my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit); +extern uint bitmap_set_next(MY_BITMAP *map); +extern uint bitmap_get_first(const MY_BITMAP *map); +extern uint bitmap_get_first_set(const MY_BITMAP *map); +extern uint bitmap_bits_set(const MY_BITMAP *map); +extern void bitmap_free(MY_BITMAP *map); +extern void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit); +extern void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size); +extern void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2); +extern void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2); +extern void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2); +extern void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2); +extern void bitmap_invert(MY_BITMAP *map); +extern void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2); +extern uint bitmap_lock_set_next(MY_BITMAP *map); +extern void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit); +static inline void +bitmap_set_bit(MY_BITMAP *map,uint bit) +{ + assert(bit < (map)->n_bits); + (((uchar*)(map)->bitmap)[(bit) / 8] |= (1 << ((bit) & 7))); +} +static inline void +bitmap_flip_bit(MY_BITMAP *map,uint bit) +{ + assert(bit < (map)->n_bits); + (((uchar*)(map)->bitmap)[(bit) / 8] ^= (1 << ((bit) & 7))); +} +static inline void +bitmap_clear_bit(MY_BITMAP *map,uint bit) +{ + assert(bit < (map)->n_bits); + (((uchar*)(map)->bitmap)[(bit) / 8] &= ~ (1 << ((bit) & 7))); +} +static inline uint +bitmap_is_set(const MY_BITMAP *map,uint bit) +{ + assert(bit < (map)->n_bits); + return (uint) (((uchar*)(map)->bitmap)[(bit) / 8] & (1 << ((bit) & 7))); +} +static inline my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2) +{ + *(map1)->last_word_ptr|= (map1)->last_word_mask; + *(map2)->last_word_ptr|= (map2)->last_word_mask; + return memcmp((map1)->bitmap, (map2)->bitmap, 4*((((map1))->n_bits + 31)/32))==0; +} +template <uint default_width> class Bitmap +{ + MY_BITMAP map; + uint32 buffer[(default_width+31)/32]; +public: + Bitmap() { init(); } + Bitmap(const Bitmap& from) { *this=from; } + explicit Bitmap(uint prefix_to_set) { init(prefix_to_set); } + void init() { bitmap_init(&map, buffer, default_width, 0); } + void init(uint prefix_to_set) { init(); set_prefix(prefix_to_set); } + uint length() const { return default_width; } + Bitmap& operator=(const Bitmap& map2) + { + init(); + memcpy(buffer, map2.buffer, sizeof(buffer)); + return *this; + } + void set_bit(uint n) { bitmap_set_bit(&map, n); } + void clear_bit(uint n) { bitmap_clear_bit(&map, n); } + void set_prefix(uint n) { bitmap_set_prefix(&map, n); } + void set_all() { (memset((&map)->bitmap, 0xFF, 4*((((&map))->n_bits + 31)/32))); } + void clear_all() { { memset((&map)->bitmap, 0, 4*((((&map))->n_bits + 31)/32)); }; } + void intersect(Bitmap& map2) { bitmap_intersect(&map, &map2.map); } + void intersect(ulonglong map2buff) + { + MY_BITMAP map2; + bitmap_init(&map2, (uint32 *)&map2buff, sizeof(ulonglong)*8, 0); + bitmap_intersect(&map, &map2); + } + void intersect_extended(ulonglong map2buff) + { + intersect(map2buff); + if (map.n_bits > sizeof(ulonglong) * 8) + bitmap_set_above(&map, sizeof(ulonglong), + ((map2buff & (1LL << (sizeof(ulonglong) * 8 - 1))) ? 1 : 0)); + } + void subtract(Bitmap& map2) { bitmap_subtract(&map, &map2.map); } + void merge(Bitmap& map2) { bitmap_union(&map, &map2.map); } + my_bool is_set(uint n) const { return bitmap_is_set(&map, n); } + my_bool is_prefix(uint n) const { return bitmap_is_prefix(&map, n); } + my_bool is_clear_all() const { return bitmap_is_clear_all(&map); } + my_bool is_set_all() const { return bitmap_is_set_all(&map); } + my_bool is_subset(const Bitmap& map2) const { return bitmap_is_subset(&map, &map2.map); } + my_bool is_overlapping(const Bitmap& map2) const { return bitmap_is_overlapping(&map, &map2.map); } + my_bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &map2.map); } + char *print(char *buf) const + { + char *s=buf; + const uchar *e=(uchar *)buffer, *b=e+sizeof(buffer)-1; + while (!*b && b>e) + b--; + if ((*s=_dig_vec_upper[*b >> 4]) != '0') + s++; + *s++=_dig_vec_upper[*b & 15]; + while (--b>=e) + { + *s++=_dig_vec_upper[*b >> 4]; + *s++=_dig_vec_upper[*b & 15]; + } + *s=0; + return buf; + } + ulonglong to_ulonglong() const + { + if (sizeof(buffer) >= 8) + return (*((ulonglong *) (buffer))); + assert(sizeof(buffer) >= 4); + return (ulonglong) (*((uint32 *) (buffer))); + } +}; +template <> class Bitmap<64> +{ + ulonglong map; +public: + Bitmap<64>() { } + explicit Bitmap<64>(uint prefix_to_set) { set_prefix(prefix_to_set); } + void init() { } + void init(uint prefix_to_set) { set_prefix(prefix_to_set); } + uint length() const { return 64; } + void set_bit(uint n) { map|= ((ulonglong)1) << n; } + void clear_bit(uint n) { map&= ~(((ulonglong)1) << n); } + void set_prefix(uint n) + { + if (n >= length()) + set_all(); + else + map= (((ulonglong)1) << n)-1; + } + void set_all() { map=~(ulonglong)0; } + void clear_all() { map=(ulonglong)0; } + void intersect(Bitmap<64>& map2) { map&= map2.map; } + void intersect(ulonglong map2) { map&= map2; } + void intersect_extended(ulonglong map2) { map&= map2; } + void subtract(Bitmap<64>& map2) { map&= ~map2.map; } + void merge(Bitmap<64>& map2) { map|= map2.map; } + my_bool is_set(uint n) const { return ((map & (((ulonglong)1) << n)) ? 1 : 0); } + my_bool is_prefix(uint n) const { return map == (((ulonglong)1) << n)-1; } + my_bool is_clear_all() const { return map == (ulonglong)0; } + my_bool is_set_all() const { return map == ~(ulonglong)0; } + my_bool is_subset(const Bitmap<64>& map2) const { return !(map & ~map2.map); } + my_bool is_overlapping(const Bitmap<64>& map2) const { return (map & map2.map)!= 0; } + my_bool operator==(const Bitmap<64>& map2) const { return map == map2.map; } + char *print(char *buf) const { longlong2str(map,buf,16); return buf; } + ulonglong to_ulonglong() const { return map; } +}; +#include "sql_array.h" +#include <my_sys.h> +template <class Elem> class Dynamic_array +{ + DYNAMIC_ARRAY array; +public: + Dynamic_array(uint prealloc=16, uint increment=16) + { + init_dynamic_array2(&array,sizeof(Elem),NULL,prealloc,increment ); + } + Elem& at(int idx) + { + return *(((Elem*)array.buffer) + idx); + } + Elem *front() + { + return (Elem*)array.buffer; + } + Elem *back() + { + return ((Elem*)array.buffer) + array.elements; + } + In_C_you_should_use_my_bool_instead() append(Elem &el) + { + return (insert_dynamic(&array, (uchar*)&el)); + } + int elements() + { + return array.elements; + } + ~Dynamic_array() + { + delete_dynamic(&array); + } + typedef int (*CMP_FUNC)(const Elem *el1, const Elem *el2); + void sort(CMP_FUNC cmp_func) + { + my_qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func); + } +}; +#include "sql_plugin.h" +class sys_var; +#include <mysql/plugin.h> +typedef struct st_mysql_lex_string MYSQL_LEX_STRING; +struct st_mysql_xid { + long formatID; + long gtrid_length; + long bqual_length; + char data[128]; +}; +typedef struct st_mysql_xid MYSQL_XID; +enum enum_mysql_show_type +{ + SHOW_UNDEF, SHOW_BOOL, SHOW_INT, SHOW_LONG, + SHOW_LONGLONG, SHOW_CHAR, SHOW_CHAR_PTR, + SHOW_ARRAY, SHOW_FUNC, SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_LONGLONG, SHOW_LONG_STATUS, SHOW_DOUBLE_STATUS, SHOW_HAVE, SHOW_MY_BOOL, SHOW_HA_ROWS, SHOW_SYS, SHOW_LONG_NOFLUSH, SHOW_LONGLONG_STATUS, SHOW_DOUBLE +}; +struct st_mysql_show_var { + const char *name; + char *value; + enum enum_mysql_show_type type; +}; +typedef int (*mysql_show_var_func)(void*, struct st_mysql_show_var*, char *); +struct st_mysql_sys_var; +struct st_mysql_value; +typedef int (*mysql_var_check_func)(void* thd, + struct st_mysql_sys_var *var, + void *save, struct st_mysql_value *value); +typedef void (*mysql_var_update_func)(void* thd, + struct st_mysql_sys_var *var, + void *var_ptr, const void *save); +struct st_mysql_plugin +{ + int type; + void *info; + const char *name; + const char *author; + const char *descr; + int license; + int (*init)(void *); + int (*deinit)(void *); + unsigned int version; + struct st_mysql_show_var *status_vars; + struct st_mysql_sys_var **system_vars; + void * __reserved1; +}; +enum enum_ftparser_mode +{ + MYSQL_FTPARSER_SIMPLE_MODE= 0, + MYSQL_FTPARSER_WITH_STOPWORDS= 1, + MYSQL_FTPARSER_FULL_BOOLEAN_INFO= 2 +}; +enum enum_ft_token_type +{ + FT_TOKEN_EOF= 0, + FT_TOKEN_WORD= 1, + FT_TOKEN_LEFT_PAREN= 2, + FT_TOKEN_RIGHT_PAREN= 3, + FT_TOKEN_STOPWORD= 4 +}; +typedef struct st_mysql_ftparser_boolean_info +{ + enum enum_ft_token_type type; + int yesno; + int weight_adjust; + char wasign; + char trunc; + char prev; + char *quot; +} MYSQL_FTPARSER_BOOLEAN_INFO; +typedef struct st_mysql_ftparser_param +{ + int (*mysql_parse)(struct st_mysql_ftparser_param *, + char *doc, int doc_len); + int (*mysql_add_word)(struct st_mysql_ftparser_param *, + char *word, int word_len, + MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info); + void *ftparser_state; + void *mysql_ftparam; + struct charset_info_st *cs; + char *doc; + int length; + int flags; + enum enum_ftparser_mode mode; +} MYSQL_FTPARSER_PARAM; +struct st_mysql_ftparser +{ + int interface_version; + int (*parse)(MYSQL_FTPARSER_PARAM *param); + int (*init)(MYSQL_FTPARSER_PARAM *param); + int (*deinit)(MYSQL_FTPARSER_PARAM *param); +}; +struct st_mysql_storage_engine +{ + int interface_version; +}; +struct handlerton; +struct st_mysql_daemon +{ + int interface_version; +}; +struct st_mysql_information_schema +{ + int interface_version; +}; +struct st_mysql_value +{ + int (*value_type)(struct st_mysql_value *); + const char *(*val_str)(struct st_mysql_value *, char *buffer, int *length); + int (*val_real)(struct st_mysql_value *, double *realbuf); + int (*val_int)(struct st_mysql_value *, long long *intbuf); +}; +int thd_in_lock_tables(const void* thd); +int thd_tablespace_op(const void* thd); +long long thd_test_options(const void* thd, long long test_options); +int thd_sql_command(const void* thd); +const char *thd_proc_info(void* thd, const char *info); +void **thd_ha_data(const void* thd, const struct handlerton *hton); +int thd_tx_isolation(const void* thd); +char *thd_security_context(void* thd, char *buffer, unsigned int length, + unsigned int max_query_len); +void thd_inc_row_count(void* thd); +int mysql_tmpfile(const char *prefix); +int thd_killed(const void* thd); +unsigned long thd_get_thread_id(const void* thd); +void *thd_alloc(void* thd, unsigned int size); +void *thd_calloc(void* thd, unsigned int size); +char *thd_strdup(void* thd, const char *str); +char *thd_strmake(void* thd, const char *str, unsigned int size); +void *thd_memdup(void* thd, const void* str, unsigned int size); +MYSQL_LEX_STRING *thd_make_lex_string(void* thd, MYSQL_LEX_STRING *lex_str, + const char *str, unsigned int size, + int allocate_lex_string); +void thd_get_xid(const void* thd, MYSQL_XID *xid); +void mysql_query_cache_invalidate4(void* thd, + const char *key, unsigned int key_length, + int using_trx); +typedef enum enum_mysql_show_type SHOW_TYPE; +typedef struct st_mysql_show_var SHOW_VAR; +struct st_plugin_dl +{ + LEX_STRING dl; + void *handle; + struct st_mysql_plugin *plugins; + int version; + uint ref_count; +}; +struct st_plugin_int +{ + LEX_STRING name; + struct st_mysql_plugin *plugin; + struct st_plugin_dl *plugin_dl; + uint state; + uint ref_count; + void *data; + MEM_ROOT mem_root; + sys_var *system_vars; +}; +typedef struct st_plugin_int **plugin_ref; +typedef int (*plugin_type_init)(struct st_plugin_int *); +extern char *opt_plugin_load; +extern char *opt_plugin_dir_ptr; +extern char opt_plugin_dir[512]; +extern const LEX_STRING plugin_type_names[]; +extern int plugin_init(int *argc, char **argv, int init_flags); +extern void plugin_shutdown(void); +extern void my_print_help_inc_plugins(struct my_option *options, uint size); +extern In_C_you_should_use_my_bool_instead() plugin_is_ready(const LEX_STRING *name, int type); +extern plugin_ref plugin_lock(THD *thd, plugin_ref *ptr ); +extern plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name, + int type ); +extern void plugin_unlock(THD *thd, plugin_ref plugin); +extern void plugin_unlock_list(THD *thd, plugin_ref *list, uint count); +extern In_C_you_should_use_my_bool_instead() mysql_install_plugin(THD *thd, const LEX_STRING *name, + const LEX_STRING *dl); +extern In_C_you_should_use_my_bool_instead() mysql_uninstall_plugin(THD *thd, const LEX_STRING *name); +extern In_C_you_should_use_my_bool_instead() plugin_register_builtin(struct st_mysql_plugin *plugin); +extern void plugin_thdvar_init(THD *thd); +extern void plugin_thdvar_cleanup(THD *thd); +typedef my_bool (plugin_foreach_func)(THD *thd, + plugin_ref plugin, + void *arg); +extern In_C_you_should_use_my_bool_instead() plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func, + int type, uint state_mask, void *arg); +#include "scheduler.h" +class THD; +class scheduler_functions +{ +public: + uint max_threads; + In_C_you_should_use_my_bool_instead() (*init)(void); + In_C_you_should_use_my_bool_instead() (*init_new_connection_thread)(void); + void (*add_connection)(THD *thd); + void (*post_kill_notification)(THD *thd); + In_C_you_should_use_my_bool_instead() (*end_thread)(THD *thd, In_C_you_should_use_my_bool_instead() cache_thread); + void (*end)(void); + scheduler_functions(); +}; +enum scheduler_types +{ + SCHEDULER_ONE_THREAD_PER_CONNECTION=0, + 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 +}; +class thd_scheduler +{}; +enum enum_query_type +{ + QT_ORDINARY, + QT_IS +}; +typedef ulonglong table_map; +typedef Bitmap<64> key_map; +typedef ulong nesting_map; +typedef ulonglong nested_join_map; +typedef ulonglong query_id_t; +extern query_id_t global_query_id; +inline query_id_t next_query_id() { return global_query_id++; } +extern const key_map key_map_empty; +extern key_map key_map_full; +extern const char *primary_key_name; +#include "mysql_com.h" +enum enum_server_command +{ + COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST, + COM_CREATE_DB, COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS, + COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING, + COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, + COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE, + COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE, + COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH, COM_DAEMON, + COM_END +}; +struct st_vio; +typedef struct st_vio Vio; +typedef struct st_net { + Vio *vio; + unsigned char *buff,*buff_end,*write_pos,*read_pos; + my_socket fd; + unsigned long remain_in_buf,length, buf_length, where_b; + unsigned long max_packet,max_packet_size; + unsigned int pkt_nr,compress_pkt_nr; + unsigned int write_timeout, read_timeout, retry_count; + int fcntl; + unsigned int *return_status; + unsigned char reading_or_writing; + char save_char; + my_bool unused0; + my_bool unused; + my_bool compress; + my_bool unused1; + unsigned char *query_cache_query; + unsigned int last_errno; + unsigned char error; + my_bool unused2; + my_bool return_errno; + char last_error[512]; + char sqlstate[5 +1]; + void *extension; +} NET; +enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, + MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG, + MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE, + MYSQL_TYPE_NULL, MYSQL_TYPE_TIMESTAMP, + MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24, + MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, + MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR, + MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR, + MYSQL_TYPE_BIT, + MYSQL_TYPE_NEWDECIMAL=246, + MYSQL_TYPE_ENUM=247, + MYSQL_TYPE_SET=248, + MYSQL_TYPE_TINY_BLOB=249, + MYSQL_TYPE_MEDIUM_BLOB=250, + MYSQL_TYPE_LONG_BLOB=251, + MYSQL_TYPE_BLOB=252, + MYSQL_TYPE_VAR_STRING=253, + MYSQL_TYPE_STRING=254, + MYSQL_TYPE_GEOMETRY=255 +}; +enum mysql_enum_shutdown_level { + SHUTDOWN_DEFAULT = 0, + SHUTDOWN_WAIT_CONNECTIONS= (unsigned char)(1 << 0), + SHUTDOWN_WAIT_TRANSACTIONS= (unsigned char)(1 << 1), + SHUTDOWN_WAIT_UPDATES= (unsigned char)(1 << 3), + SHUTDOWN_WAIT_ALL_BUFFERS= ((unsigned char)(1 << 3) << 1), + SHUTDOWN_WAIT_CRITICAL_BUFFERS= ((unsigned char)(1 << 3) << 1) + 1, + KILL_QUERY= 254, + KILL_CONNECTION= 255 +}; +enum enum_cursor_type +{ + CURSOR_TYPE_NO_CURSOR= 0, + CURSOR_TYPE_READ_ONLY= 1, + CURSOR_TYPE_FOR_UPDATE= 2, + CURSOR_TYPE_SCROLLABLE= 4 +}; +enum enum_mysql_set_option +{ + MYSQL_OPTION_MULTI_STATEMENTS_ON, + MYSQL_OPTION_MULTI_STATEMENTS_OFF +}; +my_bool my_net_init(NET *net, Vio* vio); +void my_net_local_init(NET *net); +void net_end(NET *net); + void net_clear(NET *net, my_bool clear_buffer); +my_bool net_realloc(NET *net, size_t length); +my_bool net_flush(NET *net); +my_bool my_net_write(NET *net,const unsigned char *packet, size_t len); +my_bool net_write_command(NET *net,unsigned char command, + const unsigned char *header, size_t head_len, + const unsigned char *packet, size_t len); +int net_real_write(NET *net,const unsigned char *packet, size_t len); +unsigned long my_net_read(NET *net); +void my_net_set_write_timeout(NET *net, uint timeout); +void my_net_set_read_timeout(NET *net, uint timeout); +struct sockaddr; +int my_connect(my_socket s, const struct sockaddr *name, unsigned int namelen, + unsigned int timeout); +struct rand_struct { + unsigned long seed1,seed2,max_value; + double max_value_dbl; +}; +enum Item_result {STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT, + DECIMAL_RESULT}; +typedef struct st_udf_args +{ + unsigned int arg_count; + enum Item_result *arg_type; + char **args; + unsigned long *lengths; + char *maybe_null; + char **attributes; + unsigned long *attribute_lengths; + void *extension; +} UDF_ARGS; +typedef struct st_udf_init +{ + my_bool maybe_null; + unsigned int decimals; + unsigned long max_length; + char *ptr; + my_bool const_item; + void *extension; +} UDF_INIT; +void randominit(struct rand_struct *, unsigned long seed1, + unsigned long seed2); +double my_rnd(struct rand_struct *); +void create_random_string(char *to, unsigned int length, struct rand_struct *rand_st); +void hash_password(unsigned long *to, const char *password, unsigned int password_len); +void make_scrambled_password_323(char *to, const char *password); +void scramble_323(char *to, const char *message, const char *password); +my_bool check_scramble_323(const char *, const char *message, + unsigned long *salt); +void get_salt_from_password_323(unsigned long *res, const char *password); +void make_password_from_salt_323(char *to, const unsigned long *salt); +void make_scrambled_password(char *to, const char *password); +void scramble(char *to, const char *message, const char *password); +my_bool check_scramble(const char *reply, const char *message, + const unsigned char *hash_stage2); +void get_salt_from_password(unsigned char *res, const char *password); +void make_password_from_salt(char *to, const unsigned char *hash_stage2); +char *octet2hex(char *to, const char *str, unsigned int len); +char *get_tty_password(const char *opt_message); +const char *mysql_errno_to_sqlstate(unsigned int mysql_errno); +my_bool my_thread_init(void); +void my_thread_end(void); +ulong net_field_length(uchar **packet); +my_ulonglong net_field_length_ll(uchar **packet); +uchar *net_store_length(uchar *pkg, ulonglong length); +#include <violite.h> +#include "my_net.h" +#include <errno.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/poll.h> +#include <sys/ioctl.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +void my_inet_ntoa(struct in_addr in, char *buf); +struct hostent; +struct hostent *my_gethostbyname_r(const char *name, + struct hostent *result, char *buffer, + int buflen, int *h_errnop); +enum enum_vio_type +{ + VIO_CLOSED, VIO_TYPE_TCPIP, VIO_TYPE_SOCKET, VIO_TYPE_NAMEDPIPE, + VIO_TYPE_SSL, VIO_TYPE_SHARED_MEMORY +}; +Vio* vio_new(my_socket sd, enum enum_vio_type type, uint flags); +void vio_delete(Vio* vio); +int vio_close(Vio* vio); +void vio_reset(Vio* vio, enum enum_vio_type type, + my_socket sd, void * hPipe, uint flags); +size_t vio_read(Vio *vio, uchar * buf, size_t size); +size_t vio_read_buff(Vio *vio, uchar * buf, size_t size); +size_t vio_write(Vio *vio, const uchar * buf, size_t size); +int vio_blocking(Vio *vio, my_bool onoff, my_bool *old_mode); +my_bool vio_is_blocking(Vio *vio); +int vio_fastsend(Vio *vio); +int vio_keepalive(Vio *vio, my_bool onoff); +my_bool vio_should_retry(Vio *vio); +my_bool vio_was_interrupted(Vio *vio); +const char* vio_description(Vio *vio); +enum enum_vio_type vio_type(Vio* vio); +int vio_errno(Vio*vio); +my_socket vio_fd(Vio*vio); +my_bool vio_peer_addr(Vio* vio, char *buf, uint16 *port); +void vio_in_addr(Vio *vio, struct in_addr *in); +my_bool vio_poll_read(Vio *vio,uint timeout); +void vio_end(void); +enum SSL_type +{ + SSL_TYPE_NOT_SPECIFIED= -1, + SSL_TYPE_NONE, + SSL_TYPE_ANY, + SSL_TYPE_X509, + SSL_TYPE_SPECIFIED +}; +struct st_vio +{ + my_socket sd; + void * hPipe; + my_bool localhost; + int fcntl_mode; + struct sockaddr_in local; + struct sockaddr_in remote; + enum enum_vio_type type; + char desc[30]; + char *read_buffer; + char *read_pos; + char *read_end; + void (*viodelete)(Vio*); + int (*vioerrno)(Vio*); + size_t (*read)(Vio*, uchar *, size_t); + size_t (*write)(Vio*, const uchar *, size_t); + int (*vioblocking)(Vio*, my_bool, my_bool *); + my_bool (*is_blocking)(Vio*); + int (*viokeepalive)(Vio*, my_bool); + int (*fastsend)(Vio*); + my_bool (*peer_addr)(Vio*, char *, uint16*); + void (*in_addr)(Vio*, struct in_addr*); + my_bool (*should_retry)(Vio*); + my_bool (*was_interrupted)(Vio*); + int (*vioclose)(Vio*); + void (*timeout)(Vio*, unsigned int which, unsigned int timeout); +}; +#include "unireg.h" +#include "mysqld_error.h" +#include "structs.h" +struct st_table; +class Field; +typedef struct st_date_time_format { + uchar positions[8]; + char time_separator; + uint flag; + LEX_STRING format; +} DATE_TIME_FORMAT; +typedef struct st_keyfile_info { + uchar ref[8]; + uchar dupp_ref[8]; + uint ref_length; + uint block_size; + File filenr; + ha_rows records; + ha_rows deleted; + ulonglong data_file_length; + ulonglong max_data_file_length; + ulonglong index_file_length; + ulonglong max_index_file_length; + ulonglong delete_length; + ulonglong auto_increment_value; + int errkey,sortkey; + time_t create_time; + time_t check_time; + time_t update_time; + ulong mean_rec_length; +} KEYFILE_INFO; +typedef struct st_key_part_info { + Field *field; + uint offset; + uint null_offset; + uint16 length; + uint16 store_length; + uint16 key_type; + uint16 fieldnr; + uint16 key_part_flag; + uint8 type; + uint8 null_bit; +} KEY_PART_INFO ; +typedef struct st_key { + uint key_length; + ulong flags; + uint key_parts; + uint extra_length; + uint usable_key_parts; + uint block_size; + enum ha_key_alg algorithm; + union + { + plugin_ref parser; + LEX_STRING *parser_name; + }; + KEY_PART_INFO *key_part; + char *name; + ulong *rec_per_key; + union { + int bdb_return_if_eq; + } handler; + struct st_table *table; +} KEY; +struct st_join_table; +typedef struct st_reginfo { + struct st_join_table *join_tab; + enum thr_lock_type lock_type; + In_C_you_should_use_my_bool_instead() not_exists_optimize; + In_C_you_should_use_my_bool_instead() impossible_range; +} REGINFO; +struct st_read_record; +class SQL_SELECT; +class THD; +class handler; +typedef struct st_read_record { + struct st_table *table; + handler *file; + struct st_table **forms; + int (*read_record)(struct st_read_record *); + THD *thd; + SQL_SELECT *select; + uint cache_records; + uint ref_length,struct_length,reclength,rec_cache_size,error_offset; + uint index; + uchar *ref_pos; + uchar *record; + uchar *rec_buf; + uchar *cache,*cache_pos,*cache_end,*read_positions; + IO_CACHE *io_cache; + In_C_you_should_use_my_bool_instead() print_error, ignore_not_found_rows; +} READ_RECORD; +typedef enum enum_mysql_timestamp_type timestamp_type; +typedef struct { + ulong year,month,day,hour; + ulonglong minute,second,second_part; + In_C_you_should_use_my_bool_instead() neg; +} INTERVAL; +typedef struct st_known_date_time_format { + const char *format_name; + const char *date_format; + const char *datetime_format; + const char *time_format; +} KNOWN_DATE_TIME_FORMAT; +enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED}; +extern const char *show_comp_option_name[]; +typedef int *(*update_var)(THD *, struct st_mysql_show_var *); +typedef struct st_lex_user { + LEX_STRING user, host, password; +} LEX_USER; +typedef struct user_resources { + uint questions; + uint updates; + uint conn_per_hour; + uint user_conn; + enum {QUERIES_PER_HOUR= 1, UPDATES_PER_HOUR= 2, CONNECTIONS_PER_HOUR= 4, + USER_CONNECTIONS= 8}; + uint specified_limits; +} USER_RESOURCES; +typedef struct user_conn { + char *user; + char *host; + ulonglong reset_utime; + uint len; + uint connections; + uint conn_per_hour, updates, questions; + USER_RESOURCES user_resources; +} USER_CONN; +class Discrete_interval { +private: + ulonglong interval_min; + ulonglong interval_values; + ulonglong interval_max; +public: + Discrete_interval *next; + void replace(ulonglong start, ulonglong val, ulonglong incr) + { + interval_min= start; + interval_values= val; + interval_max= (val == ((unsigned long long)(~0ULL))) ? val : start + val * incr; + } + Discrete_interval(ulonglong start, ulonglong val, ulonglong incr) : + next(NULL) { replace(start, val, incr); }; + Discrete_interval() : next(NULL) { replace(0, 0, 0); }; + ulonglong minimum() const { return interval_min; }; + ulonglong values() const { return interval_values; }; + ulonglong maximum() const { return interval_max; }; + In_C_you_should_use_my_bool_instead() merge_if_contiguous(ulonglong start, ulonglong val, ulonglong incr) + { + if (interval_max == start) + { + if (val == ((unsigned long long)(~0ULL))) + { + interval_values= interval_max= val; + } + else + { + interval_values+= val; + interval_max= start + val * incr; + } + return 0; + } + return 1; + }; +}; +class Discrete_intervals_list { +private: + Discrete_interval *head; + Discrete_interval *tail; + Discrete_interval *current; + uint elements; + void copy_(const Discrete_intervals_list& from) + { + for (Discrete_interval *i= from.head; i; i= i->next) + { + Discrete_interval j= *i; + append(&j); + } + } +public: + Discrete_intervals_list() : head(NULL), current(NULL), elements(0) {}; + Discrete_intervals_list(const Discrete_intervals_list& from) + { + copy_(from); + } + void operator=(const Discrete_intervals_list& from) + { + empty(); + copy_(from); + } + void empty_no_free() + { + head= current= NULL; + elements= 0; + } + void empty() + { + for (Discrete_interval *i= head; i;) + { + Discrete_interval *next= i->next; + delete i; + i= next; + } + empty_no_free(); + } + const Discrete_interval* get_next() + { + Discrete_interval *tmp= current; + if (current != NULL) + current= current->next; + return tmp; + } + ~Discrete_intervals_list() { empty(); }; + In_C_you_should_use_my_bool_instead() append(ulonglong start, ulonglong val, ulonglong incr); + In_C_you_should_use_my_bool_instead() append(Discrete_interval *interval); + ulonglong minimum() const { return (head ? head->minimum() : 0); }; + ulonglong maximum() const { return (head ? tail->maximum() : 0); }; + uint nb_elements() const { return elements; } +}; +void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size); +void *sql_alloc(size_t); +void *sql_calloc(size_t); +char *sql_strdup(const char *str); +char *sql_strmake(const char *str, size_t len); +void *sql_memdup(const void * ptr, size_t size); +void sql_element_free(void *ptr); +char *sql_strmake_with_convert(const char *str, size_t arg_length, + CHARSET_INFO *from_cs, + size_t max_res_length, + CHARSET_INFO *to_cs, size_t *result_length); +uint kill_one_thread(THD *thd, ulong id, In_C_you_should_use_my_bool_instead() only_kill_query); +void sql_kill(THD *thd, ulong id, In_C_you_should_use_my_bool_instead() only_kill_query); +In_C_you_should_use_my_bool_instead() net_request_file(NET* net, const char* fname); +char* query_table_status(THD *thd,const char *db,const char *table_name); +extern CHARSET_INFO *system_charset_info, *files_charset_info ; +extern CHARSET_INFO *national_charset_info, *table_alias_charset; +enum Derivation +{ + DERIVATION_IGNORABLE= 5, + DERIVATION_COERCIBLE= 4, + DERIVATION_SYSCONST= 3, + DERIVATION_IMPLICIT= 2, + DERIVATION_NONE= 1, + DERIVATION_EXPLICIT= 0 +}; +typedef struct my_locale_st +{ + uint number; + const char *name; + const char *description; + const In_C_you_should_use_my_bool_instead() is_ascii; + TYPELIB *month_names; + TYPELIB *ab_month_names; + TYPELIB *day_names; + TYPELIB *ab_day_names; +} MY_LOCALE; +extern MY_LOCALE my_locale_en_US; +extern MY_LOCALE *my_locales[]; +extern MY_LOCALE *my_default_lc_time_names; +MY_LOCALE *my_locale_by_name(const char *name); +MY_LOCALE *my_locale_by_number(uint number); +class Object_creation_ctx +{ +public: + Object_creation_ctx *set_n_backup(THD *thd); + void restore_env(THD *thd, Object_creation_ctx *backup_ctx); +protected: + Object_creation_ctx() {} + virtual Object_creation_ctx *create_backup_ctx(THD *thd) const = 0; + virtual void change_env(THD *thd) const = 0; +public: + virtual ~Object_creation_ctx() + { } +}; +class Default_object_creation_ctx : public Object_creation_ctx +{ +public: + CHARSET_INFO *get_client_cs() + { + return m_client_cs; + } + CHARSET_INFO *get_connection_cl() + { + return m_connection_cl; + } +protected: + Default_object_creation_ctx(THD *thd); + Default_object_creation_ctx(CHARSET_INFO *client_cs, + CHARSET_INFO *connection_cl); +protected: + virtual Object_creation_ctx *create_backup_ctx(THD *thd) const; + virtual void change_env(THD *thd) const; +protected: + CHARSET_INFO *m_client_cs; + CHARSET_INFO *m_connection_cl; +}; +struct TABLE_LIST; +class String; +void view_store_options(THD *thd, TABLE_LIST *table, String *buff); +enum enum_parsing_place +{ + NO_MATTER, + IN_HAVING, + SELECT_LIST, + IN_WHERE, + IN_ON +}; +struct st_table; +class THD; +enum enum_check_fields +{ + CHECK_FIELD_IGNORE, + CHECK_FIELD_WARN, + CHECK_FIELD_ERROR_FOR_NULL +}; +typedef struct st_sql_list { + uint elements; + uchar *first; + uchar **next; + st_sql_list() {} + inline void empty() + { + elements=0; + first=0; + next= &first; + } + inline void link_in_list(uchar *element,uchar **next_ptr) + { + elements++; + (*next)=element; + next= next_ptr; + *next=0; + } + inline void save_and_clear(struct st_sql_list *save) + { + *save= *this; + empty(); + } + inline void push_front(struct st_sql_list *save) + { + *save->next= first; + first= save->first; + elements+= save->elements; + } + inline void push_back(struct st_sql_list *save) + { + if (save->first) + { + *next= save->first; + next= save->next; + elements+= save->elements; + } + } +} SQL_LIST; +extern pthread_key_t THR_THD; +inline THD *_current_thd(void) +{ + return ((THD*) pthread_getspecific((THR_THD))); +} +extern "C" +const char *set_thd_proc_info(THD *thd, const char *info, + const char *calling_func, + const char *calling_file, + const unsigned int calling_line); +enum enum_table_ref_type +{ + TABLE_REF_NULL= 0, + TABLE_REF_VIEW, + TABLE_REF_BASE_TABLE, + TABLE_REF_I_S_TABLE, + TABLE_REF_TMP_TABLE +}; +extern ulong server_id, concurrency; +typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, + uint key_length, + ulonglong *engine_data); +#include "sql_string.h" +class String; +int sortcmp(const String *a,const String *b, CHARSET_INFO *cs); +String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); +uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, + const char *from, uint32 from_length, + CHARSET_INFO *from_cs, uint *errors); +uint32 well_formed_copy_nchars(CHARSET_INFO *to_cs, + char *to, uint to_length, + CHARSET_INFO *from_cs, + const char *from, uint from_length, + uint nchars, + const char **well_formed_error_pos, + const char **cannot_convert_error_pos, + const char **from_end_pos); +size_t my_copy_with_hex_escaping(CHARSET_INFO *cs, + char *dst, size_t dstlen, + const char *src, size_t srclen); +class String +{ + char *Ptr; + uint32 str_length,Alloced_length; + In_C_you_should_use_my_bool_instead() alloced; + CHARSET_INFO *str_charset; +public: + String() + { + Ptr=0; str_length=Alloced_length=0; alloced=0; + str_charset= &my_charset_bin; + } + String(uint32 length_arg) + { + alloced=0; Alloced_length=0; (void) real_alloc(length_arg); + str_charset= &my_charset_bin; + } + String(const char *str, CHARSET_INFO *cs) + { + Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0; + str_charset=cs; + } + String(const char *str,uint32 len, CHARSET_INFO *cs) + { + Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0; + str_charset=cs; + } + String(char *str,uint32 len, CHARSET_INFO *cs) + { + Ptr=(char*) str; Alloced_length=str_length=len; alloced=0; + str_charset=cs; + } + String(const String &str) + { + Ptr=str.Ptr ; str_length=str.str_length ; + Alloced_length=str.Alloced_length; alloced=0; + str_charset=str.str_charset; + } + static void *operator new(size_t size, MEM_ROOT *mem_root) + { return (void*) alloc_root(mem_root, (uint) size); } + static void operator delete(void *ptr_arg,size_t size) + { ; } + static void operator delete(void *ptr_arg, MEM_ROOT *mem_root) + { } + ~String() { free(); } + 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;} + inline char& operator [] (uint32 i) const { return Ptr[i]; } + inline void length(uint32 len) { str_length=len ; } + inline In_C_you_should_use_my_bool_instead() is_empty() { return (str_length == 0); } + inline void mark_as_const() { Alloced_length= 0;} + inline const char *ptr() const { return Ptr; } + inline char *c_ptr() + { + if (!Ptr || Ptr[str_length]) + (void) realloc(str_length); + return Ptr; + } + inline char *c_ptr_quick() + { + if (Ptr && str_length < Alloced_length) + Ptr[str_length]=0; + return Ptr; + } + inline char *c_ptr_safe() + { + if (Ptr && str_length < Alloced_length) + Ptr[str_length]=0; + else + (void) realloc(str_length); + return Ptr; + } + void set(String &str,uint32 offset,uint32 arg_length) + { + assert(&str != this); + free(); + Ptr=(char*) str.ptr()+offset; str_length=arg_length; alloced=0; + if (str.Alloced_length) + Alloced_length=str.Alloced_length-offset; + else + Alloced_length=0; + str_charset=str.str_charset; + } + inline void set(char *str,uint32 arg_length, CHARSET_INFO *cs) + { + free(); + Ptr=(char*) str; str_length=Alloced_length=arg_length ; alloced=0; + str_charset=cs; + } + inline void set(const char *str,uint32 arg_length, CHARSET_INFO *cs) + { + free(); + Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0; + str_charset=cs; + } + In_C_you_should_use_my_bool_instead() set_ascii(const char *str, uint32 arg_length); + inline void set_quick(char *str,uint32 arg_length, CHARSET_INFO *cs) + { + if (!alloced) + { + Ptr=(char*) str; str_length=Alloced_length=arg_length; + } + str_charset=cs; + } + In_C_you_should_use_my_bool_instead() set_int(longlong num, In_C_you_should_use_my_bool_instead() unsigned_flag, CHARSET_INFO *cs); + In_C_you_should_use_my_bool_instead() set(longlong num, CHARSET_INFO *cs) + { return set_int(num, false, cs); } + In_C_you_should_use_my_bool_instead() set(ulonglong num, CHARSET_INFO *cs) + { return set_int((longlong)num, true, cs); } + In_C_you_should_use_my_bool_instead() set_real(double num,uint decimals, CHARSET_INFO *cs); + inline void chop() + { + Ptr[str_length--]= '\0'; + } + inline void free() + { + if (alloced) + { + alloced=0; + Alloced_length=0; + ((void)(myf) (0),my_no_flags_free(Ptr)); + Ptr=0; + str_length=0; + } + } + inline In_C_you_should_use_my_bool_instead() alloc(uint32 arg_length) + { + if (arg_length < Alloced_length) + return 0; + return real_alloc(arg_length); + } + In_C_you_should_use_my_bool_instead() real_alloc(uint32 arg_length); + In_C_you_should_use_my_bool_instead() realloc(uint32 arg_length); + inline void shrink(uint32 arg_length) + { + if (arg_length < Alloced_length) + { + char *new_ptr; + if (!(new_ptr=(char*) my_realloc(Ptr,arg_length,(myf) (0)))) + { + Alloced_length = 0; + real_alloc(arg_length); + } + else + { + Ptr=new_ptr; + Alloced_length=arg_length; + } + } + } + In_C_you_should_use_my_bool_instead() is_alloced() { return alloced; } + inline String& operator = (const String &s) + { + if (&s != this) + { + assert(!s.uses_buffer_owned_by(this)); + free(); + Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length; + alloced=0; + } + return *this; + } + In_C_you_should_use_my_bool_instead() copy(); + In_C_you_should_use_my_bool_instead() copy(const String &s); + In_C_you_should_use_my_bool_instead() copy(const char *s,uint32 arg_length, CHARSET_INFO *cs); + static In_C_you_should_use_my_bool_instead() needs_conversion(uint32 arg_length, + CHARSET_INFO *cs_from, CHARSET_INFO *cs_to, + uint32 *offset); + In_C_you_should_use_my_bool_instead() copy_aligned(const char *s, uint32 arg_length, uint32 offset, + CHARSET_INFO *cs); + In_C_you_should_use_my_bool_instead() set_or_copy_aligned(const char *s, uint32 arg_length, CHARSET_INFO *cs); + In_C_you_should_use_my_bool_instead() copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom, + CHARSET_INFO *csto, uint *errors); + In_C_you_should_use_my_bool_instead() append(const String &s); + In_C_you_should_use_my_bool_instead() append(const char *s); + In_C_you_should_use_my_bool_instead() append(const char *s,uint32 arg_length); + In_C_you_should_use_my_bool_instead() append(const char *s,uint32 arg_length, CHARSET_INFO *cs); + In_C_you_should_use_my_bool_instead() append(IO_CACHE* file, uint32 arg_length); + In_C_you_should_use_my_bool_instead() append_with_prefill(const char *s, uint32 arg_length, + uint32 full_length, char fill_char); + int strstr(const String &search,uint32 offset=0); + int strrstr(const String &search,uint32 offset=0); + In_C_you_should_use_my_bool_instead() replace(uint32 offset,uint32 arg_length,const char *to,uint32 length); + In_C_you_should_use_my_bool_instead() replace(uint32 offset,uint32 arg_length,const String &to); + inline In_C_you_should_use_my_bool_instead() append(char chr) + { + if (str_length < Alloced_length) + { + Ptr[str_length++]=chr; + } + else + { + if (realloc(str_length+1)) + return 1; + Ptr[str_length++]=chr; + } + return 0; + } + In_C_you_should_use_my_bool_instead() fill(uint32 max_length,char fill); + void strip_sp(); + friend int sortcmp(const String *a,const String *b, CHARSET_INFO *cs); + friend int stringcmp(const String *a,const String *b); + friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); + uint32 numchars(); + int charpos(int i,uint32 offset=0); + int reserve(uint32 space_needed) + { + return realloc(str_length + space_needed); + } + int reserve(uint32 space_needed, uint32 grow_by); + void q_append(const char c) + { + Ptr[str_length++] = c; + } + void q_append(const uint32 n) + { + *((long *) (Ptr + str_length))= (long) (n); + str_length += 4; + } + void q_append(double d) + { + do { *((long *) (Ptr + str_length)) = ((doubleget_union *)&(d))->m[0]; *(((long *) (Ptr + str_length))+1) = ((doubleget_union *)&(d))->m[1]; } while (0); + str_length += 8; + } + void q_append(double *d) + { + do { *((long *) (Ptr + str_length)) = ((doubleget_union *)&(*d))->m[0]; *(((long *) (Ptr + str_length))+1) = ((doubleget_union *)&(*d))->m[1]; } while (0); + str_length += 8; + } + void q_append(const char *data, uint32 data_len) + { + memcpy(Ptr + str_length, data, data_len); + str_length += data_len; + } + void write_at_position(int position, uint32 value) + { + *((long *) (Ptr + position))= (long) (value); + } + void qs_append(const char *str, uint32 len); + void qs_append(double d); + void qs_append(double *d); + inline void qs_append(const char c) + { + Ptr[str_length]= c; + str_length++; + } + void qs_append(int i); + void qs_append(uint i); + inline char *prep_append(uint32 arg_length, uint32 step_alloc) + { + uint32 new_length= arg_length + str_length; + if (new_length > Alloced_length) + { + if (realloc(new_length + step_alloc)) + return 0; + } + uint32 old_length= str_length; + str_length+= arg_length; + return Ptr+ old_length; + } + inline In_C_you_should_use_my_bool_instead() append(const char *s, uint32 arg_length, uint32 step_alloc) + { + uint32 new_length= arg_length + str_length; + if (new_length > Alloced_length && realloc(new_length + step_alloc)) + return (1); + memcpy(Ptr+str_length, s, arg_length); + str_length+= arg_length; + return (0); + } + void print(String *print); + void swap(String &s); + inline In_C_you_should_use_my_bool_instead() uses_buffer_owned_by(const String *s) const + { + return (s->alloced && Ptr >= s->Ptr && Ptr < s->Ptr + s->str_length); + } +}; +static inline In_C_you_should_use_my_bool_instead() check_if_only_end_space(CHARSET_INFO *cs, char *str, + char *end) +{ + return str+ cs->cset->scan(cs, str, end, 2) == end; +} +#include "sql_list.h" +class Sql_alloc +{ +public: + static void *operator new(size_t size) throw () + { + return sql_alloc(size); + } + static void *operator new[](size_t size) + { + return sql_alloc(size); + } + static void *operator new[](size_t size, MEM_ROOT *mem_root) throw () + { return alloc_root(mem_root, size); } + static void *operator new(size_t size, MEM_ROOT *mem_root) throw () + { return alloc_root(mem_root, size); } + static void operator delete(void *ptr, size_t size) { ; } + static void operator delete(void *ptr, MEM_ROOT *mem_root) + { } + static void operator delete[](void *ptr, MEM_ROOT *mem_root) + { } + static void operator delete[](void *ptr, size_t size) { ; } + inline Sql_alloc() {} + inline ~Sql_alloc() {} +}; +struct list_node :public Sql_alloc +{ + list_node *next; + void *info; + list_node(void *info_par,list_node *next_par) + :next(next_par),info(info_par) + {} + list_node() + { + info= 0; + next= this; + } +}; +extern list_node end_of_list; +class base_list :public Sql_alloc +{ +protected: + list_node *first,**last; +public: + uint elements; + inline void empty() { elements=0; first= &end_of_list; last=&first;} + inline base_list() { empty(); } + inline base_list(const base_list &tmp) :Sql_alloc() + { + elements= tmp.elements; + first= tmp.first; + last= elements ? tmp.last : &first; + } + base_list(const base_list &rhs, MEM_ROOT *mem_root); + inline base_list(In_C_you_should_use_my_bool_instead() error) { } + inline In_C_you_should_use_my_bool_instead() push_back(void *info) + { + if (((*last)=new list_node(info, &end_of_list))) + { + last= &(*last)->next; + elements++; + return 0; + } + return 1; + } + inline In_C_you_should_use_my_bool_instead() push_back(void *info, MEM_ROOT *mem_root) + { + if (((*last)=new (mem_root) list_node(info, &end_of_list))) + { + last= &(*last)->next; + elements++; + return 0; + } + return 1; + } + inline In_C_you_should_use_my_bool_instead() push_front(void *info) + { + list_node *node=new list_node(info,first); + if (node) + { + if (last == &first) + last= &node->next; + first=node; + elements++; + return 0; + } + return 1; + } + void remove(list_node **prev) + { + list_node *node=(*prev)->next; + if (!--elements) + last= &first; + else if (last == &(*prev)->next) + last= prev; + delete *prev; + *prev=node; + } + inline void concat(base_list *list) + { + if (!list->is_empty()) + { + *last= list->first; + last= list->last; + elements+= list->elements; + } + } + inline void *pop(void) + { + if (first == &end_of_list) return 0; + list_node *tmp=first; + first=first->next; + if (!--elements) + last= &first; + return tmp->info; + } + inline void disjoin(base_list *list) + { + list_node **prev= &first; + list_node *node= first; + list_node *list_first= list->first; + elements=0; + while (node && node != list_first) + { + prev= &node->next; + node= node->next; + elements++; + } + *prev= *last; + last= prev; + } + inline void prepand(base_list *list) + { + if (!list->is_empty()) + { + *list->last= first; + first= list->first; + elements+= list->elements; + } + } + inline void swap(base_list &rhs) + { + { list_node * dummy; dummy= first; first= rhs.first; rhs.first= dummy; }; + { list_node ** dummy; dummy= last; last= rhs.last; rhs.last= dummy; }; + { uint dummy; dummy= elements; elements= rhs.elements; rhs.elements= dummy; }; + } + inline list_node* last_node() { return *last; } + inline list_node* first_node() { return first;} + inline void *head() { return first->info; } + inline void **head_ref() { return first != &end_of_list ? &first->info : 0; } + inline In_C_you_should_use_my_bool_instead() is_empty() { return first == &end_of_list ; } + inline list_node *last_ref() { return &end_of_list; } + friend class base_list_iterator; + friend class error_list; + friend class error_list_iterator; +protected: + void after(void *info,list_node *node) + { + list_node *new_node=new list_node(info,node->next); + node->next=new_node; + elements++; + if (last == &(node->next)) + last= &new_node->next; + } +}; +class base_list_iterator +{ +protected: + base_list *list; + list_node **el,**prev,*current; + void sublist(base_list &ls, uint elm) + { + ls.first= *el; + ls.last= list->last; + ls.elements= elm; + } +public: + base_list_iterator() + :list(0), el(0), prev(0), current(0) + {} + base_list_iterator(base_list &list_par) + { init(list_par); } + inline void init(base_list &list_par) + { + list= &list_par; + el= &list_par.first; + prev= 0; + current= 0; + } + inline void *next(void) + { + prev=el; + current= *el; + el= ¤t->next; + return current->info; + } + inline void *next_fast(void) + { + list_node *tmp; + tmp= *el; + el= &tmp->next; + return tmp->info; + } + inline void rewind(void) + { + el= &list->first; + } + inline void *replace(void *element) + { + void *tmp=current->info; + assert(current->info != 0); + current->info=element; + return tmp; + } + void *replace(base_list &new_list) + { + void *ret_value=current->info; + if (!new_list.is_empty()) + { + *new_list.last=current->next; + current->info=new_list.first->info; + current->next=new_list.first->next; + if ((list->last == ¤t->next) && (new_list.elements > 1)) + list->last= new_list.last; + list->elements+=new_list.elements-1; + } + return ret_value; + } + inline void remove(void) + { + list->remove(prev); + el=prev; + current=0; + } + void after(void *element) + { + list->after(element,current); + current=current->next; + el= ¤t->next; + } + inline void **ref(void) + { + return ¤t->info; + } + inline In_C_you_should_use_my_bool_instead() is_last(void) + { + return el == &list->last_ref()->next; + } + friend class error_list_iterator; +}; +template <class T> class List :public base_list +{ +public: + inline List() :base_list() {} + inline List(const List<T> &tmp) :base_list(tmp) {} + inline List(const List<T> &tmp, MEM_ROOT *mem_root) : + base_list(tmp, mem_root) {} + inline In_C_you_should_use_my_bool_instead() push_back(T *a) { return base_list::push_back(a); } + inline In_C_you_should_use_my_bool_instead() push_back(T *a, MEM_ROOT *mem_root) + { return base_list::push_back(a, mem_root); } + inline In_C_you_should_use_my_bool_instead() push_front(T *a) { return base_list::push_front(a); } + inline T* head() {return (T*) base_list::head(); } + inline T** head_ref() {return (T**) base_list::head_ref(); } + inline T* pop() {return (T*) base_list::pop(); } + inline void concat(List<T> *list) { base_list::concat(list); } + inline void disjoin(List<T> *list) { base_list::disjoin(list); } + inline void prepand(List<T> *list) { base_list::prepand(list); } + void delete_elements(void) + { + list_node *element,*next; + for (element=first; element != &end_of_list; element=next) + { + next=element->next; + delete (T*) element->info; + } + empty(); + } +}; +template <class T> class List_iterator :public base_list_iterator +{ +public: + List_iterator(List<T> &a) : base_list_iterator(a) {} + List_iterator() : base_list_iterator() {} + inline void init(List<T> &a) { base_list_iterator::init(a); } + inline T* operator++(int) { return (T*) base_list_iterator::next(); } + inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); } + inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); } + inline void rewind(void) { base_list_iterator::rewind(); } + inline void remove() { base_list_iterator::remove(); } + inline void after(T *a) { base_list_iterator::after(a); } + inline T** ref(void) { return (T**) base_list_iterator::ref(); } +}; +template <class T> class List_iterator_fast :public base_list_iterator +{ +protected: + inline T *replace(T *a) { return (T*) 0; } + inline T *replace(List<T> &a) { return (T*) 0; } + inline void remove(void) { } + inline void after(T *a) { } + inline T** ref(void) { return (T**) 0; } +public: + inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {} + inline List_iterator_fast() : base_list_iterator() {} + inline void init(List<T> &a) { base_list_iterator::init(a); } + inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); } + inline void rewind(void) { base_list_iterator::rewind(); } + void sublist(List<T> &list_arg, uint el_arg) + { + base_list_iterator::sublist(list_arg, el_arg); + } +}; +struct ilink +{ + struct ilink **prev,*next; + static void *operator new(size_t size) + { + return (void*)my_malloc((uint)size, (myf) (16 | 8)); + } + static void operator delete(void* ptr_arg, size_t size) + { + ((void)(myf) (16|64),my_no_flags_free((uchar*)ptr_arg)); + } + inline ilink() + { + prev=0; next=0; + } + inline void unlink() + { + if (prev) *prev= next; + if (next) next->prev=prev; + prev=0 ; next=0; + } + virtual ~ilink() { unlink(); } +}; +class i_string: public ilink +{ +public: + const char* ptr; + i_string():ptr(0) { } + i_string(const char* s) : ptr(s) {} +}; +class i_string_pair: public ilink +{ +public: + const char* key; + const char* val; + i_string_pair():key(0),val(0) { } + i_string_pair(const char* key_arg, const char* val_arg) : + key(key_arg),val(val_arg) {} +}; +template <class T> class I_List_iterator; +class base_ilist +{ +public: + struct ilink *first,last; + inline void empty() { first= &last; last.prev= &first; } + base_ilist() { empty(); } + inline In_C_you_should_use_my_bool_instead() is_empty() { return first == &last; } + inline void append(ilink *a) + { + first->prev= &a->next; + a->next=first; a->prev= &first; first=a; + } + inline void push_back(ilink *a) + { + *last.prev= a; + a->next= &last; + a->prev= last.prev; + last.prev= &a->next; + } + inline struct ilink *get() + { + struct ilink *first_link=first; + if (first_link == &last) + return 0; + first_link->unlink(); + return first_link; + } + inline struct ilink *head() + { + return (first != &last) ? first : 0; + } + friend class base_list_iterator; +}; +class base_ilist_iterator +{ + base_ilist *list; + struct ilink **el,*current; +public: + base_ilist_iterator(base_ilist &list_par) :list(&list_par), + el(&list_par.first),current(0) {} + void *next(void) + { + current= *el; + if (current == &list->last) return 0; + el= ¤t->next; + return current; + } +}; +template <class T> +class I_List :private base_ilist +{ +public: + I_List() :base_ilist() {} + inline void empty() { base_ilist::empty(); } + inline In_C_you_should_use_my_bool_instead() is_empty() { return base_ilist::is_empty(); } + inline void append(T* a) { base_ilist::append(a); } + inline void push_back(T* a) { base_ilist::push_back(a); } + inline T* get() { return (T*) base_ilist::get(); } + inline T* head() { return (T*) base_ilist::head(); } + friend class I_List_iterator<T>; +}; +template <class T> class I_List_iterator :public base_ilist_iterator +{ +public: + I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {} + inline T* operator++(int) { return (T*) base_ilist_iterator::next(); } +}; +template <typename T> +inline +void +list_copy_and_replace_each_value(List<T> &list, MEM_ROOT *mem_root) +{ + List_iterator<T> it(list); + T *el; + while ((el= it++)) + it.replace(el->clone(mem_root)); +} +#include "sql_map.h" +class mapped_files; +mapped_files *map_file(const char * name,uchar *magic,uint magic_length); +void unmap_file(mapped_files *map); +class mapped_files :public ilink { + uchar *map; + ha_rows size; + char *name; + File file; + int error; + uint use_count; +public: + mapped_files(const char * name,uchar *magic,uint magic_length); + ~mapped_files(); + friend class mapped_file; + friend mapped_files *map_file(const char * name,uchar *magic, + uint magic_length); + friend void unmap_file(mapped_files *map); +}; +class mapped_file +{ + mapped_files *file; +public: + mapped_file(const char * name,uchar *magic,uint magic_length) + { + file=map_file(name,magic,magic_length); + } + ~mapped_file() + { + unmap_file(file); + } + uchar *map() + { + return file->map; + } +}; +#include "my_decimal.h" +#include <decimal.h> +typedef enum +{TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR} + decimal_round_mode; +typedef int32 decimal_digit_t; +typedef struct st_decimal_t { + int intg, frac, len; + my_bool sign; + decimal_digit_t *buf; +} decimal_t; +int internal_str2dec(const char *from, decimal_t *to, char **end, + my_bool fixed); +int decimal2string(decimal_t *from, char *to, int *to_len, + int fixed_precision, int fixed_decimals, + char filler); +int decimal2ulonglong(decimal_t *from, ulonglong *to); +int ulonglong2decimal(ulonglong from, decimal_t *to); +int decimal2longlong(decimal_t *from, longlong *to); +int longlong2decimal(longlong from, decimal_t *to); +int decimal2double(decimal_t *from, double *to); +int double2decimal(double from, decimal_t *to); +int decimal_actual_fraction(decimal_t *from); +int decimal2bin(decimal_t *from, uchar *to, int precision, int scale); +int bin2decimal(const uchar *from, decimal_t *to, int precision, int scale); +int decimal_size(int precision, int scale); +int decimal_bin_size(int precision, int scale); +int decimal_result_size(decimal_t *from1, decimal_t *from2, char op, + int param); +int decimal_intg(decimal_t *from); +int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_cmp(decimal_t *from1, decimal_t *from2); +int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to, + int scale_incr); +int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_round(decimal_t *from, decimal_t *to, int new_scale, + decimal_round_mode mode); +int decimal_is_zero(decimal_t *from); +void max_decimal(int precision, int frac, decimal_t *to); +inline uint my_decimal_size(uint precision, uint scale) +{ + return decimal_size(precision, scale) + 1; +} +inline int my_decimal_int_part(uint precision, uint decimals) +{ + return precision - ((decimals == 31) ? 0 : decimals); +} +class my_decimal :public decimal_t +{ + decimal_digit_t buffer[9]; +public: + void init() + { + len= 9; + buf= buffer; + for (uint i= 0; i < 9; i++) + buffer[i]= i; + } + my_decimal() + { + init(); + } + void fix_buffer_pointer() { buf= buffer; } + In_C_you_should_use_my_bool_instead() sign() const { return decimal_t::sign; } + void sign(In_C_you_should_use_my_bool_instead() s) { decimal_t::sign= s; } + uint precision() const { return intg + frac; } + void swap(my_decimal &rhs) + { + { my_decimal dummy; dummy= *this; *this= rhs; rhs= dummy; }; + { decimal_digit_t * dummy; dummy= buf; buf= rhs.buf; rhs.buf= dummy; }; + } +}; +void print_decimal(const my_decimal *dec); +void print_decimal_buff(const my_decimal *dec, const uchar* ptr, int length); +const char *dbug_decimal_as_string(char *buff, const my_decimal *val); +int decimal_operation_results(int result); +inline +void max_my_decimal(my_decimal *to, int precision, int frac) +{ + assert((precision <= ((9 * 9) - 8*2))&& (frac <= 30)); + max_decimal(precision, frac, (decimal_t*) to); +} +inline void max_internal_decimal(my_decimal *to) +{ + max_my_decimal(to, ((9 * 9) - 8*2), 0); +} +inline int check_result(uint mask, int result) +{ + if (result & mask) + decimal_operation_results(result); + return result; +} +inline int check_result_and_overflow(uint mask, int result, my_decimal *val) +{ + if (check_result(mask, result) & 2) + { + In_C_you_should_use_my_bool_instead() sign= val->sign(); + val->fix_buffer_pointer(); + max_internal_decimal(val); + val->sign(sign); + } + return result; +} +inline uint my_decimal_length_to_precision(uint length, uint scale, + In_C_you_should_use_my_bool_instead() unsigned_flag) +{ + assert(length || !scale); + return (uint) (length - (scale>0 ? 1:0) - + (unsigned_flag || !length ? 0:1)); +} +inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale, + In_C_you_should_use_my_bool_instead() unsigned_flag) +{ + assert(precision || !scale); + do { if ((precision) > (((9 * 9) - 8*2))) (precision)=(((9 * 9) - 8*2)); } while(0); + return (uint32)(precision + (scale>0 ? 1:0) + + (unsigned_flag || !precision ? 0:1)); +} +inline +int my_decimal_string_length(const my_decimal *d) +{ + return (((d)->intg ? (d)->intg : 1) + (d)->frac + ((d)->frac > 0) + 2); +} +inline +int my_decimal_max_length(const my_decimal *d) +{ + return (((d)->intg ? (d)->intg : 1) + (d)->frac + ((d)->frac > 0) + 2) - 1; +} +inline +int my_decimal_get_binary_size(uint precision, uint scale) +{ + return decimal_bin_size((int)precision, (int)scale); +} +inline +void my_decimal2decimal(const my_decimal *from, my_decimal *to) +{ + *to= *from; + to->fix_buffer_pointer(); +} +int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec, + int scale); +inline +int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec, + int scale) +{ + return check_result(mask, bin2decimal(bin, (decimal_t*) d, prec, scale)); +} +inline +int my_decimal_set_zero(my_decimal *d) +{ + do { (((decimal_t*) d))->buf[0]=0; (((decimal_t*) d))->intg=1; (((decimal_t*) d))->frac=0; (((decimal_t*) d))->sign=0; } while(0); + return 0; +} +inline +In_C_you_should_use_my_bool_instead() my_decimal_is_zero(const my_decimal *decimal_value) +{ + return decimal_is_zero((decimal_t*) decimal_value); +} +inline +int my_decimal_round(uint mask, const my_decimal *from, int scale, + In_C_you_should_use_my_bool_instead() truncate, my_decimal *to) +{ + return check_result(mask, decimal_round((decimal_t*) from, to, scale, + (truncate ? TRUNCATE : HALF_UP))); +} +inline +int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to) +{ + return check_result(mask, decimal_round((decimal_t*) from, to, 0, FLOOR)); +} +inline +int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to) +{ + return check_result(mask, decimal_round((decimal_t*) from, to, 0, CEILING)); +} +int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec, + uint fixed_dec, char filler, String *str); +inline +int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag, + longlong *l) +{ + my_decimal rounded; + decimal_round((decimal_t*)d, &rounded, 0, HALF_UP); + return check_result(mask, (unsigned_flag ? + decimal2ulonglong(&rounded, (ulonglong *)l) : + decimal2longlong(&rounded, l))); +} +inline +int my_decimal2double(uint mask, const my_decimal *d, double *result) +{ + return decimal2double((decimal_t*) d, result); +} +inline +int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end) +{ + return check_result_and_overflow(mask, internal_str2dec((str), ((decimal_t*)d), (end), 0), + d); +} +int str2my_decimal(uint mask, const char *from, uint length, + CHARSET_INFO *charset, my_decimal *decimal_value); +inline +int double2my_decimal(uint mask, double val, my_decimal *d) +{ + return check_result_and_overflow(mask, double2decimal(val, (decimal_t*)d), d); +} +inline +int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d) +{ + return check_result(mask, (unsigned_flag ? + ulonglong2decimal((ulonglong)i, d) : + longlong2decimal(i, d))); +} +inline +void my_decimal_neg(decimal_t *arg) +{ + if (decimal_is_zero(arg)) + { + arg->sign= 0; + return; + } + do { (arg)->sign^=1; } while(0); +} +inline +int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b) +{ + return check_result_and_overflow(mask, + decimal_add((decimal_t*)a,(decimal_t*)b,res), + res); +} +inline +int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b) +{ + return check_result_and_overflow(mask, + decimal_sub((decimal_t*)a,(decimal_t*)b,res), + res); +} +inline +int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b) +{ + return check_result_and_overflow(mask, + decimal_mul((decimal_t*)a,(decimal_t*)b,res), + res); +} +inline +int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b, int div_scale_inc) +{ + return check_result_and_overflow(mask, + decimal_div((decimal_t*)a,(decimal_t*)b,res, + div_scale_inc), + res); +} +inline +int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b) +{ + return check_result_and_overflow(mask, + decimal_mod((decimal_t*)a,(decimal_t*)b,res), + res); +} +inline +int my_decimal_cmp(const my_decimal *a, const my_decimal *b) +{ + return decimal_cmp((decimal_t*) a, (decimal_t*) b); +} +inline +int my_decimal_intg(const my_decimal *a) +{ + return decimal_intg((decimal_t*) a); +} +void my_decimal_trim(ulong *precision, uint *scale); +#include "handler.h" +#include <my_handler.h> +#include "myisampack.h" +typedef struct st_HA_KEYSEG +{ + CHARSET_INFO *charset; + uint32 start; + uint32 null_pos; + uint16 bit_pos; + uint16 flag; + uint16 length; + uint8 type; + uint8 language; + uint8 null_bit; + uint8 bit_start,bit_end; + uint8 bit_length; +} HA_KEYSEG; +extern int ha_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint , + my_bool, my_bool); +extern int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, + register uchar *b, uint key_length, uint nextflag, + uint *diff_pos); +extern HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a); +extern void my_handler_error_register(void); +extern void my_handler_error_unregister(void); +#include <ft_global.h> +typedef struct st_ft_info FT_INFO; +struct _ft_vft +{ + int (*read_next)(FT_INFO *, char *); + float (*find_relevance)(FT_INFO *, uchar *, uint); + void (*close_search)(FT_INFO *); + float (*get_relevance)(FT_INFO *); + void (*reinit_search)(FT_INFO *); +}; +struct st_ft_info +{ + struct _ft_vft *please; +}; +extern const char *ft_stopword_file; +extern const char *ft_precompiled_stopwords[]; +extern ulong ft_min_word_len; +extern ulong ft_max_word_len; +extern ulong ft_query_expansion_limit; +extern char ft_boolean_syntax[15]; +extern struct st_mysql_ftparser ft_default_parser; +int ft_init_stopwords(void); +void ft_free_stopwords(void); +FT_INFO *ft_init_search(uint,void *, uint, uchar *, uint,CHARSET_INFO *, uchar *); +my_bool ft_boolean_check_syntax_string(const uchar *); +#include <keycache.h> +struct st_block_link; +typedef struct st_block_link BLOCK_LINK; +struct st_keycache_page; +typedef struct st_keycache_page KEYCACHE_PAGE; +struct st_hash_link; +typedef struct st_hash_link HASH_LINK; +typedef struct st_keycache_wqueue +{ + struct st_my_thread_var *last_thread; +} KEYCACHE_WQUEUE; +typedef struct st_key_cache +{ + my_bool key_cache_inited; + my_bool in_resize; + my_bool resize_in_flush; + my_bool can_be_used; + size_t key_cache_mem_size; + uint key_cache_block_size; + ulong min_warm_blocks; + ulong age_threshold; + ulonglong keycache_time; + uint hash_entries; + int hash_links; + int hash_links_used; + int disk_blocks; + ulong blocks_used; + ulong blocks_unused; + ulong blocks_changed; + ulong warm_blocks; + ulong cnt_for_resize_op; + long blocks_available; + HASH_LINK **hash_root; + HASH_LINK *hash_link_root; + HASH_LINK *free_hash_list; + BLOCK_LINK *free_block_list; + BLOCK_LINK *block_root; + uchar *block_mem; + BLOCK_LINK *used_last; + BLOCK_LINK *used_ins; + pthread_mutex_t cache_lock; + KEYCACHE_WQUEUE resize_queue; + KEYCACHE_WQUEUE waiting_for_resize_cnt; + KEYCACHE_WQUEUE waiting_for_hash_link; + KEYCACHE_WQUEUE waiting_for_block; + BLOCK_LINK *changed_blocks[128]; + BLOCK_LINK *file_blocks[128]; + ulonglong param_buff_size; + ulong param_block_size; + ulong param_division_limit; + ulong param_age_threshold; + ulong global_blocks_changed; + ulonglong global_cache_w_requests; + ulonglong global_cache_write; + ulonglong global_cache_r_requests; + ulonglong global_cache_read; + int blocks; + my_bool in_init; +} KEY_CACHE; +extern KEY_CACHE dflt_key_cache_var, *dflt_key_cache; +extern int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, + size_t use_mem, uint division_limit, + uint age_threshold); +extern int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, + size_t use_mem, uint division_limit, + uint age_threshold); +extern void change_key_cache_param(KEY_CACHE *keycache, uint division_limit, + uint age_threshold); +extern uchar *key_cache_read(KEY_CACHE *keycache, + File file, my_off_t filepos, int level, + uchar *buff, uint length, + uint block_length,int return_buffer); +extern int key_cache_insert(KEY_CACHE *keycache, + File file, my_off_t filepos, int level, + uchar *buff, uint length); +extern int key_cache_write(KEY_CACHE *keycache, + File file, my_off_t filepos, int level, + uchar *buff, uint length, + uint block_length,int force_write); +extern int flush_key_blocks(KEY_CACHE *keycache, + int file, enum flush_type type); +extern void end_key_cache(KEY_CACHE *keycache, my_bool cleanup); +extern my_bool multi_keycache_init(void); +extern void multi_keycache_free(void); +extern KEY_CACHE *multi_key_cache_search(uchar *key, uint length); +extern my_bool multi_key_cache_set(const uchar *key, uint length, + KEY_CACHE *key_cache); +extern void multi_key_cache_change(KEY_CACHE *old_data, + KEY_CACHE *new_data); +extern int reset_key_cache_counters(const char *name, + KEY_CACHE *key_cache); +enum legacy_db_type +{ + DB_TYPE_UNKNOWN=0,DB_TYPE_DIAB_ISAM=1, + DB_TYPE_HASH,DB_TYPE_MISAM,DB_TYPE_PISAM, + DB_TYPE_RMS_ISAM, DB_TYPE_HEAP, DB_TYPE_ISAM, + DB_TYPE_MRG_ISAM, DB_TYPE_MYISAM, DB_TYPE_MRG_MYISAM, + DB_TYPE_BERKELEY_DB, DB_TYPE_INNODB, + DB_TYPE_GEMINI, DB_TYPE_NDBCLUSTER, + DB_TYPE_EXAMPLE_DB, DB_TYPE_ARCHIVE_DB, DB_TYPE_CSV_DB, + DB_TYPE_FEDERATED_DB, + DB_TYPE_BLACKHOLE_DB, + DB_TYPE_PARTITION_DB, + DB_TYPE_BINLOG, + DB_TYPE_SOLID, + DB_TYPE_PBXT, + DB_TYPE_TABLE_FUNCTION, + DB_TYPE_MEMCACHE, + DB_TYPE_FALCON, + DB_TYPE_MARIA, + DB_TYPE_FIRST_DYNAMIC=42, + DB_TYPE_DEFAULT=127 +}; +enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED, + ROW_TYPE_DYNAMIC, ROW_TYPE_COMPRESSED, + ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT, ROW_TYPE_PAGE }; +enum enum_binlog_func { + BFN_RESET_LOGS= 1, + BFN_RESET_SLAVE= 2, + BFN_BINLOG_WAIT= 3, + BFN_BINLOG_END= 4, + BFN_BINLOG_PURGE_FILE= 5 +}; +enum enum_binlog_command { + LOGCOM_CREATE_TABLE, + LOGCOM_ALTER_TABLE, + LOGCOM_RENAME_TABLE, + LOGCOM_DROP_TABLE, + LOGCOM_CREATE_DB, + LOGCOM_ALTER_DB, + LOGCOM_DROP_DB +}; +typedef ulonglong my_xid; +struct xid_t { + long formatID; + long gtrid_length; + long bqual_length; + char data[128]; + xid_t() {} + In_C_you_should_use_my_bool_instead() eq(struct xid_t *xid) + { return eq(xid->gtrid_length, xid->bqual_length, xid->data); } + In_C_you_should_use_my_bool_instead() eq(long g, long b, const char *d) + { return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); } + void set(struct xid_t *xid) + { memcpy(this, xid, xid->length()); } + void set(long f, const char *g, long gl, const char *b, long bl) + { + formatID= f; + memcpy(data, g, gtrid_length= gl); + memcpy(data+gl, b, bqual_length= bl); + } + void set(ulonglong xid) + { + my_xid tmp; + formatID= 1; + set(8, 0, "MySQLXid"); + memcpy(data+8, &server_id, sizeof(server_id)); + tmp= xid; + memcpy(data+(8 +sizeof(server_id)), &tmp, sizeof(tmp)); + gtrid_length=((8 +sizeof(server_id))+sizeof(my_xid)); + } + void set(long g, long b, const char *d) + { + formatID= 1; + gtrid_length= g; + bqual_length= b; + memcpy(data, d, g+b); + } + In_C_you_should_use_my_bool_instead() is_null() { return formatID == -1; } + void null() { formatID= -1; } + my_xid quick_get_my_xid() + { + my_xid tmp; + memcpy(&tmp, data+(8 +sizeof(server_id)), sizeof(tmp)); + return tmp; + } + my_xid get_my_xid() + { + return gtrid_length == ((8 +sizeof(server_id))+sizeof(my_xid)) && bqual_length == 0 && + !memcmp(data+8, &server_id, sizeof(server_id)) && + !memcmp(data, "MySQLXid", 8) ? + quick_get_my_xid() : 0; + } + uint length() + { + return sizeof(formatID)+sizeof(gtrid_length)+sizeof(bqual_length)+ + gtrid_length+bqual_length; + } + uchar *key() + { + return (uchar *)>rid_length; + } + uint key_length() + { + return sizeof(gtrid_length)+sizeof(bqual_length)+gtrid_length+bqual_length; + } +}; +typedef struct xid_t XID; +enum ts_command_type +{ + TS_CMD_NOT_DEFINED = -1, + CREATE_TABLESPACE = 0, + ALTER_TABLESPACE = 1, + CREATE_LOGFILE_GROUP = 2, + ALTER_LOGFILE_GROUP = 3, + DROP_TABLESPACE = 4, + DROP_LOGFILE_GROUP = 5, + CHANGE_FILE_TABLESPACE = 6, + ALTER_ACCESS_MODE_TABLESPACE = 7 +}; +enum ts_alter_tablespace_type +{ + TS_ALTER_TABLESPACE_TYPE_NOT_DEFINED = -1, + ALTER_TABLESPACE_ADD_FILE = 1, + ALTER_TABLESPACE_DROP_FILE = 2 +}; +enum tablespace_access_mode +{ + TS_NOT_DEFINED= -1, + TS_READ_ONLY = 0, + TS_READ_WRITE = 1, + TS_NOT_ACCESSIBLE = 2 +}; +struct handlerton; +class st_alter_tablespace : public Sql_alloc +{ + public: + const char *tablespace_name; + const char *logfile_group_name; + enum ts_command_type ts_cmd_type; + enum ts_alter_tablespace_type ts_alter_tablespace_type; + const char *data_file_name; + const char *undo_file_name; + const char *redo_file_name; + ulonglong extent_size; + ulonglong undo_buffer_size; + ulonglong redo_buffer_size; + ulonglong initial_size; + ulonglong autoextend_size; + ulonglong max_size; + uint nodegroup_id; + handlerton *storage_engine; + In_C_you_should_use_my_bool_instead() wait_until_completed; + const char *ts_comment; + enum tablespace_access_mode ts_access_mode; + st_alter_tablespace() + { + tablespace_name= NULL; + logfile_group_name= "DEFAULT_LG"; + ts_cmd_type= TS_CMD_NOT_DEFINED; + data_file_name= NULL; + undo_file_name= NULL; + redo_file_name= NULL; + extent_size= 1024*1024; + undo_buffer_size= 8*1024*1024; + redo_buffer_size= 8*1024*1024; + initial_size= 128*1024*1024; + autoextend_size= 0; + max_size= 0; + storage_engine= NULL; + nodegroup_id= 65535; + wait_until_completed= (1); + ts_comment= NULL; + ts_access_mode= TS_NOT_DEFINED; + } +}; +struct st_table; +typedef struct st_table TABLE; +typedef struct st_table_share TABLE_SHARE; +struct st_foreign_key_info; +typedef struct st_foreign_key_info FOREIGN_KEY_INFO; +typedef In_C_you_should_use_my_bool_instead() (stat_print_fn)(THD *thd, const char *type, uint type_len, + const char *file, uint file_len, + const char *status, uint status_len); +enum ha_stat_type { HA_ENGINE_STATUS, HA_ENGINE_LOGS, HA_ENGINE_MUTEX }; +extern st_plugin_int *hton2plugin[15]; +enum log_status +{ + HA_LOG_STATUS_FREE= 0, + HA_LOG_STATUS_INUSE= 1, + HA_LOG_STATUS_NOSUCHLOG= 2 +}; +void signal_log_not_needed(struct handlerton, char *log_file); +struct handler_log_file_data { + LEX_STRING filename; + enum log_status status; +}; +enum handler_iterator_type +{ + HA_TRANSACTLOG_ITERATOR= 1 +}; +enum handler_create_iterator_result +{ + HA_ITERATOR_OK, + HA_ITERATOR_UNSUPPORTED, + HA_ITERATOR_ERROR +}; +struct handler_iterator { + int (*next)(struct handler_iterator *, void *iterator_object); + void (*destroy)(struct handler_iterator *); + void *buffer; +}; +struct handlerton +{ + SHOW_COMP_OPTION state; + enum legacy_db_type db_type; + uint slot; + uint savepoint_offset; + int (*close_connection)(handlerton *hton, THD *thd); + int (*savepoint_set)(handlerton *hton, THD *thd, void *sv); + int (*savepoint_rollback)(handlerton *hton, THD *thd, void *sv); + int (*savepoint_release)(handlerton *hton, THD *thd, void *sv); + int (*commit)(handlerton *hton, THD *thd, In_C_you_should_use_my_bool_instead() all); + int (*rollback)(handlerton *hton, THD *thd, In_C_you_should_use_my_bool_instead() all); + int (*prepare)(handlerton *hton, THD *thd, In_C_you_should_use_my_bool_instead() all); + int (*recover)(handlerton *hton, XID *xid_list, uint len); + int (*commit_by_xid)(handlerton *hton, XID *xid); + int (*rollback_by_xid)(handlerton *hton, XID *xid); + void *(*create_cursor_read_view)(handlerton *hton, THD *thd); + void (*set_cursor_read_view)(handlerton *hton, THD *thd, void *read_view); + void (*close_cursor_read_view)(handlerton *hton, THD *thd, void *read_view); + handler *(*create)(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); + void (*drop_database)(handlerton *hton, char* path); + int (*panic)(handlerton *hton, enum ha_panic_function flag); + int (*start_consistent_snapshot)(handlerton *hton, THD *thd); + In_C_you_should_use_my_bool_instead() (*flush_logs)(handlerton *hton); + In_C_you_should_use_my_bool_instead() (*show_status)(handlerton *hton, THD *thd, stat_print_fn *print, enum ha_stat_type stat); + uint (*partition_flags)(); + uint (*alter_table_flags)(uint flags); + int (*alter_tablespace)(handlerton *hton, THD *thd, st_alter_tablespace *ts_info); + int (*fill_files_table)(handlerton *hton, THD *thd, + TABLE_LIST *tables, + class Item *cond); + uint32 flags; + int (*binlog_func)(handlerton *hton, THD *thd, enum_binlog_func fn, void *arg); + void (*binlog_log_query)(handlerton *hton, THD *thd, + enum_binlog_command binlog_command, + const char *query, uint query_length, + const char *db, const char *table_name); + int (*release_temporary_latches)(handlerton *hton, THD *thd); + enum log_status (*get_log_status)(handlerton *hton, char *log); + enum handler_create_iterator_result + (*create_iterator)(handlerton *hton, enum handler_iterator_type type, + struct handler_iterator *fill_this_in); + int (*discover)(handlerton *hton, THD* thd, const char *db, + const char *name, + uchar **frmblob, + size_t *frmlen); + int (*find_files)(handlerton *hton, THD *thd, + const char *db, + const char *path, + const char *wild, In_C_you_should_use_my_bool_instead() dir, List<LEX_STRING> *files); + int (*table_exists_in_engine)(handlerton *hton, THD* thd, const char *db, + const char *name); + uint32 license; + void *data; +}; +class Ha_trx_info; +struct THD_TRANS +{ + In_C_you_should_use_my_bool_instead() no_2pc; + Ha_trx_info *ha_list; + In_C_you_should_use_my_bool_instead() modified_non_trans_table; + void reset() { no_2pc= (0); modified_non_trans_table= (0); } +}; +class Ha_trx_info +{ +public: + void register_ha(THD_TRANS *trans, handlerton *ht_arg) + { + assert(m_flags == 0); + assert(m_ht == NULL); + assert(m_next == NULL); + m_ht= ht_arg; + m_flags= (int) TRX_READ_ONLY; + m_next= trans->ha_list; + trans->ha_list= this; + } + void reset() + { + m_next= NULL; + m_ht= NULL; + m_flags= 0; + } + Ha_trx_info() { reset(); } + void set_trx_read_write() + { + assert(is_started()); + m_flags|= (int) TRX_READ_WRITE; + } + In_C_you_should_use_my_bool_instead() is_trx_read_write() const + { + assert(is_started()); + return m_flags & (int) TRX_READ_WRITE; + } + In_C_you_should_use_my_bool_instead() is_started() const { return m_ht != NULL; } + void coalesce_trx_with(const Ha_trx_info *stmt_trx) + { + assert(is_started()); + if (stmt_trx->is_trx_read_write()) + set_trx_read_write(); + } + Ha_trx_info *next() const + { + assert(is_started()); + return m_next; + } + handlerton *ht() const + { + assert(is_started()); + return m_ht; + } +private: + enum { TRX_READ_ONLY= 0, TRX_READ_WRITE= 1 }; + Ha_trx_info *m_next; + handlerton *m_ht; + uchar m_flags; +}; +enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED, + ISO_REPEATABLE_READ, ISO_SERIALIZABLE}; +enum ndb_distribution { ND_KEYHASH= 0, ND_LINHASH= 1 }; +typedef struct { + ulonglong data_file_length; + ulonglong max_data_file_length; + ulonglong index_file_length; + ulonglong delete_length; + ha_rows records; + ulong mean_rec_length; + time_t create_time; + time_t check_time; + time_t update_time; + ulonglong check_sum; +} PARTITION_INFO; +class Item; +struct st_table_log_memory_entry; +class partition_info; +struct st_partition_iter; +enum ha_choice { HA_CHOICE_UNDEF, HA_CHOICE_NO, HA_CHOICE_YES }; +typedef struct st_ha_create_information +{ + CHARSET_INFO *table_charset, *default_table_charset; + LEX_STRING connect_string; + const char *password, *tablespace; + LEX_STRING comment; + const char *data_file_name, *index_file_name; + const char *alias; + ulonglong max_rows,min_rows; + ulonglong auto_increment_value; + ulong table_options; + ulong avg_row_length; + ulong used_fields; + ulong key_block_size; + SQL_LIST merge_list; + handlerton *db_type; + enum row_type row_type; + uint null_bits; + uint options; + uint merge_insert_method; + uint extra_size; + enum ha_choice transactional; + In_C_you_should_use_my_bool_instead() table_existed; + In_C_you_should_use_my_bool_instead() frm_only; + In_C_you_should_use_my_bool_instead() varchar; + enum ha_storage_media storage_media; + enum ha_choice page_checksum; +} HA_CREATE_INFO; +typedef struct st_key_create_information +{ + enum ha_key_alg algorithm; + ulong block_size; + LEX_STRING parser_name; +} KEY_CREATE_INFO; +class TABLEOP_HOOKS +{ +public: + TABLEOP_HOOKS() {} + virtual ~TABLEOP_HOOKS() {} + inline void prelock(TABLE **tables, uint count) + { + do_prelock(tables, count); + } + inline int postlock(TABLE **tables, uint count) + { + return do_postlock(tables, count); + } +private: + virtual void do_prelock(TABLE **tables, uint count) + { + } + virtual int do_postlock(TABLE **tables, uint count) + { + return 0; + } +}; +typedef struct st_savepoint SAVEPOINT; +extern ulong savepoint_alloc_size; +extern KEY_CREATE_INFO default_key_create_info; +typedef class Item COND; +typedef struct st_ha_check_opt +{ + st_ha_check_opt() {} + ulong sort_buffer_size; + uint flags; + uint sql_flags; + KEY_CACHE *key_cache; + void init(); +} HA_CHECK_OPT; +typedef struct st_handler_buffer +{ + const uchar *buffer; + const uchar *buffer_end; + uchar *end_of_used_area; +} HANDLER_BUFFER; +typedef struct system_status_var SSV; +class ha_statistics +{ +public: + ulonglong data_file_length; + ulonglong max_data_file_length; + ulonglong index_file_length; + ulonglong max_index_file_length; + ulonglong delete_length; + ulonglong auto_increment_value; + ha_rows records; + ha_rows deleted; + ulong mean_rec_length; + time_t create_time; + time_t check_time; + time_t update_time; + uint block_size; + ha_statistics(): + data_file_length(0), max_data_file_length(0), + index_file_length(0), delete_length(0), auto_increment_value(0), + records(0), deleted(0), mean_rec_length(0), create_time(0), + check_time(0), update_time(0), block_size(0) + {} +}; +uint calculate_key_len(TABLE *, uint, const uchar *, key_part_map); +class handler :public Sql_alloc +{ +public: + typedef ulonglong Table_flags; +protected: + struct st_table_share *table_share; + struct st_table *table; + Table_flags cached_table_flags; + ha_rows estimation_rows_to_insert; +public: + handlerton *ht; + uchar *ref; + uchar *dup_ref; + ha_statistics stats; + In_C_you_should_use_my_bool_instead() multi_range_sorted; + KEY_MULTI_RANGE *multi_range_curr; + KEY_MULTI_RANGE *multi_range_end; + HANDLER_BUFFER *multi_range_buffer; + key_range save_end_range, *end_range; + KEY_PART_INFO *range_key_part; + int key_compare_result_on_equal; + In_C_you_should_use_my_bool_instead() eq_range; + uint errkey; + uint key_used_on_scan; + uint active_index; + uint ref_length; + FT_INFO *ft_handler; + enum {NONE=0, INDEX, RND} inited; + In_C_you_should_use_my_bool_instead() locked; + In_C_you_should_use_my_bool_instead() implicit_emptied; + const COND *pushed_cond; + ulonglong next_insert_id; + ulonglong insert_id_for_cur_row; + Discrete_interval auto_inc_interval_for_cur_row; + handler(handlerton *ht_arg, TABLE_SHARE *share_arg) + :table_share(share_arg), table(0), + estimation_rows_to_insert(0), ht(ht_arg), + ref(0), key_used_on_scan(64), active_index(64), + ref_length(sizeof(my_off_t)), + ft_handler(0), inited(NONE), + locked((0)), implicit_emptied(0), + pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0) + {} + virtual ~handler(void) + { + assert(locked == (0)); + } + virtual handler *clone(MEM_ROOT *mem_root); + void init() + { + cached_table_flags= table_flags(); + } + int ha_open(TABLE *table, const char *name, int mode, int test_if_locked); + int ha_index_init(uint idx, In_C_you_should_use_my_bool_instead() sorted) + { + int result; + const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("ha_index_init","./sql/handler.h",1159,&_db_func_,&_db_file_,&_db_level_, &_db_framep_); + assert(inited==NONE); + if (!(result= index_init(idx, sorted))) + inited=INDEX; + do {_db_return_ (1163, &_db_func_, &_db_file_, &_db_level_); return(result);} while(0); + } + int ha_index_end() + { + const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("ha_index_end","./sql/handler.h",1167,&_db_func_,&_db_file_,&_db_level_, &_db_framep_); + assert(inited==INDEX); + inited=NONE; + do {_db_return_ (1170, &_db_func_, &_db_file_, &_db_level_); return(index_end());} while(0); + } + int ha_rnd_init(In_C_you_should_use_my_bool_instead() scan) + { + int result; + const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("ha_rnd_init","./sql/handler.h",1175,&_db_func_,&_db_file_,&_db_level_, &_db_framep_); + assert(inited==NONE || (inited==RND && scan)); + inited= (result= rnd_init(scan)) ? NONE: RND; + do {_db_return_ (1178, &_db_func_, &_db_file_, &_db_level_); return(result);} while(0); + } + int ha_rnd_end() + { + const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("ha_rnd_end","./sql/handler.h",1182,&_db_func_,&_db_file_,&_db_level_, &_db_framep_); + assert(inited==RND); + inited=NONE; + do {_db_return_ (1185, &_db_func_, &_db_file_, &_db_level_); return(rnd_end());} while(0); + } + int ha_reset(); + int ha_index_or_rnd_end() + { + return inited == INDEX ? ha_index_end() : inited == RND ? ha_rnd_end() : 0; + } + Table_flags ha_table_flags() const { return cached_table_flags; } + int ha_external_lock(THD *thd, int lock_type); + int ha_write_row(uchar * buf); + int ha_update_row(const uchar * old_data, uchar * new_data); + int ha_delete_row(const uchar * buf); + void ha_release_auto_increment(); + int ha_check_for_upgrade(HA_CHECK_OPT *check_opt); + int ha_check(THD *thd, HA_CHECK_OPT *check_opt); + int ha_repair(THD* thd, HA_CHECK_OPT* check_opt); + void ha_start_bulk_insert(ha_rows rows) + { + estimation_rows_to_insert= rows; + start_bulk_insert(rows); + } + int ha_end_bulk_insert() + { + estimation_rows_to_insert= 0; + return end_bulk_insert(); + } + int ha_bulk_update_row(const uchar *old_data, uchar *new_data, + uint *dup_key_found); + int ha_delete_all_rows(); + int ha_reset_auto_increment(ulonglong value); + int ha_backup(THD* thd, HA_CHECK_OPT* check_opt); + int ha_restore(THD* thd, HA_CHECK_OPT* check_opt); + int ha_optimize(THD* thd, HA_CHECK_OPT* check_opt); + int ha_analyze(THD* thd, HA_CHECK_OPT* check_opt); + In_C_you_should_use_my_bool_instead() ha_check_and_repair(THD *thd); + int ha_disable_indexes(uint mode); + int ha_enable_indexes(uint mode); + int ha_discard_or_import_tablespace(my_bool discard); + void ha_prepare_for_alter(); + int ha_rename_table(const char *from, const char *to); + int ha_delete_table(const char *name); + void ha_drop_table(const char *name); + int ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info); + int ha_create_handler_files(const char *name, const char *old_name, + int action_flag, HA_CREATE_INFO *info); + int ha_change_partitions(HA_CREATE_INFO *create_info, + const char *path, + ulonglong *copied, + ulonglong *deleted, + const uchar *pack_frm_data, + size_t pack_frm_len); + int ha_drop_partitions(const char *path); + int ha_rename_partitions(const char *path); + int ha_optimize_partitions(THD *thd); + int ha_analyze_partitions(THD *thd); + int ha_check_partitions(THD *thd); + int ha_repair_partitions(THD *thd); + void adjust_next_insert_id_after_explicit_value(ulonglong nr); + int update_auto_increment(); + void print_keydup_error(uint key_nr, const char *msg); + virtual void print_error(int error, myf errflag); + virtual In_C_you_should_use_my_bool_instead() get_error_message(int error, String *buf); + uint get_dup_key(int error); + virtual void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share) + { + table= table_arg; + table_share= share; + } + virtual double scan_time() + { return ((double) (ulonglong) (stats.data_file_length)) / 4096 + 2; } + virtual double read_time(uint index, uint ranges, ha_rows rows) + { return ((double) (ulonglong) (ranges+rows)); } + virtual const key_map *keys_to_use_for_scanning() { return &key_map_empty; } + In_C_you_should_use_my_bool_instead() has_transactions() + { return (ha_table_flags() & (1 << 0)) == 0; } + virtual uint extra_rec_buf_length() const { return 0; } + virtual In_C_you_should_use_my_bool_instead() is_fatal_error(int error, uint flags) + { + if (!error || + ((flags & 1) && + (error == 121 || + error == 141))) + return (0); + return (1); + } + virtual ha_rows records() { return stats.records; } + virtual ha_rows estimate_rows_upper_bound() + { return stats.records+10; } + virtual enum row_type get_row_type() const { return ROW_TYPE_NOT_USED; } + virtual const char *index_type(uint key_number) { assert(0); return "";} + virtual void column_bitmaps_signal(); + uint get_index(void) const { return active_index; } + virtual int close(void)=0; + virtual In_C_you_should_use_my_bool_instead() start_bulk_update() { return 1; } + virtual In_C_you_should_use_my_bool_instead() start_bulk_delete() { return 1; } + virtual int exec_bulk_update(uint *dup_key_found) + { + assert((0)); + return 131; + } + virtual void end_bulk_update() { return; } + virtual int end_bulk_delete() + { + assert((0)); + return 131; + } + virtual int index_read_map(uchar * buf, const uchar * key, + key_part_map keypart_map, + enum ha_rkey_function find_flag) + { + uint key_len= calculate_key_len(table, active_index, key, keypart_map); + return index_read(buf, key, key_len, find_flag); + } + virtual int index_read_idx_map(uchar * buf, uint index, const uchar * key, + key_part_map keypart_map, + enum ha_rkey_function find_flag); + virtual int index_next(uchar * buf) + { return 131; } + virtual int index_prev(uchar * buf) + { return 131; } + virtual int index_first(uchar * buf) + { return 131; } + virtual int index_last(uchar * buf) + { return 131; } + virtual int index_next_same(uchar *buf, const uchar *key, uint keylen); + virtual int index_read_last_map(uchar * buf, const uchar * key, + key_part_map keypart_map) + { + uint key_len= calculate_key_len(table, active_index, key, keypart_map); + return index_read_last(buf, key, key_len); + } + virtual int read_multi_range_first(KEY_MULTI_RANGE **found_range_p, + KEY_MULTI_RANGE *ranges, uint range_count, + In_C_you_should_use_my_bool_instead() sorted, HANDLER_BUFFER *buffer); + virtual int read_multi_range_next(KEY_MULTI_RANGE **found_range_p); + virtual int read_range_first(const key_range *start_key, + const key_range *end_key, + In_C_you_should_use_my_bool_instead() eq_range, In_C_you_should_use_my_bool_instead() sorted); + virtual int read_range_next(); + int compare_key(key_range *range); + virtual int ft_init() { return 131; } + void ft_end() { ft_handler=NULL; } + virtual FT_INFO *ft_init_ext(uint flags, uint inx,String *key) + { return NULL; } + virtual int ft_read(uchar *buf) { return 131; } + virtual int rnd_next(uchar *buf)=0; + virtual int rnd_pos(uchar * buf, uchar *pos)=0; + virtual int rnd_pos_by_record(uchar *record) + { + position(record); + return rnd_pos(record, ref); + } + virtual int read_first_row(uchar *buf, uint primary_key); + virtual int restart_rnd_next(uchar *buf, uchar *pos) + { return 131; } + virtual int rnd_same(uchar *buf, uint inx) + { return 131; } + virtual ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key) + { return (ha_rows) 10; } + virtual void position(const uchar *record)=0; + virtual int info(uint)=0; + virtual void get_dynamic_partition_info(PARTITION_INFO *stat_info, + uint part_id); + virtual int extra(enum ha_extra_function operation) + { return 0; } + virtual int extra_opt(enum ha_extra_function operation, ulong cache_size) + { return extra(operation); } + virtual In_C_you_should_use_my_bool_instead() was_semi_consistent_read() { return 0; } + virtual void try_semi_consistent_read(In_C_you_should_use_my_bool_instead()) {} + virtual void unlock_row() {} + virtual int start_stmt(THD *thd, thr_lock_type lock_type) {return 0;} + virtual void get_auto_increment(ulonglong offset, ulonglong increment, + ulonglong nb_desired_values, + ulonglong *first_value, + ulonglong *nb_reserved_values); + void set_next_insert_id(ulonglong id) + { + do {_db_pargs_(1488,"info"); _db_doprnt_ ("auto_increment: next value %lu", (ulong)id);} while(0); + next_insert_id= id; + } + void restore_auto_increment(ulonglong prev_insert_id) + { + next_insert_id= (prev_insert_id > 0) ? prev_insert_id : + insert_id_for_cur_row; + } + virtual void update_create_info(HA_CREATE_INFO *create_info) {} + int check_old_types(); + virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT* check_opt) + { return -1; } + virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt) + { return -1; } + virtual int dump(THD* thd, int fd = -1) { return 131; } + virtual int indexes_are_disabled(void) {return 0;} + virtual int net_read_dump(NET* net) { return 131; } + virtual char *update_table_comment(const char * comment) + { return (char*) comment;} + virtual void append_create_info(String *packet) {} + virtual In_C_you_should_use_my_bool_instead() is_fk_defined_on_table_or_index(uint index) + { return (0); } + virtual char* get_foreign_key_create_info() + { return(NULL);} + virtual char* get_tablespace_name(THD *thd, char *name, uint name_len) + { return(NULL);} + virtual In_C_you_should_use_my_bool_instead() can_switch_engines() { return 1; } + virtual int get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list) + { return 0; } + virtual uint referenced_by_foreign_key() { return 0;} + virtual void init_table_handle_for_HANDLER() + { return; } + virtual void free_foreign_key_create_info(char* str) {} + virtual const char *table_type() const =0; + virtual const char **bas_ext() const =0; + virtual int get_default_no_partitions(HA_CREATE_INFO *info) { return 1;} + virtual void set_auto_partitions(partition_info *part_info) { return; } + virtual In_C_you_should_use_my_bool_instead() get_no_parts(const char *name, + uint *no_parts) + { + *no_parts= 0; + return 0; + } + virtual void set_part_info(partition_info *part_info) {return;} + virtual ulong index_flags(uint idx, uint part, In_C_you_should_use_my_bool_instead() all_parts) const =0; + virtual int add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys) + { return (131); } + virtual int prepare_drop_index(TABLE *table_arg, uint *key_num, + uint num_of_keys) + { return (131); } + virtual int final_drop_index(TABLE *table_arg) + { return (131); } + uint max_record_length() const + { return ((65535) < (max_supported_record_length()) ? (65535) : (max_supported_record_length())); } + uint max_keys() const + { return ((64) < (max_supported_keys()) ? (64) : (max_supported_keys())); } + uint max_key_parts() const + { return ((16) < (max_supported_key_parts()) ? (16) : (max_supported_key_parts())); } + uint max_key_length() const + { return ((3072) < (max_supported_key_length()) ? (3072) : (max_supported_key_length())); } + uint max_key_part_length() const + { return ((3072) < (max_supported_key_part_length()) ? (3072) : (max_supported_key_part_length())); } + virtual uint max_supported_record_length() const { return 65535; } + virtual uint max_supported_keys() const { return 0; } + virtual uint max_supported_key_parts() const { return 16; } + virtual uint max_supported_key_length() const { return 3072; } + virtual uint max_supported_key_part_length() const { return 255; } + virtual uint min_record_length(uint options) const { return 1; } + virtual In_C_you_should_use_my_bool_instead() low_byte_first() const { return 1; } + virtual uint checksum() const { return 0; } + virtual In_C_you_should_use_my_bool_instead() is_crashed() const { return 0; } + virtual In_C_you_should_use_my_bool_instead() auto_repair() const { return 0; } + virtual uint lock_count(void) const { return 1; } + virtual THR_LOCK_DATA **store_lock(THD *thd, + THR_LOCK_DATA **to, + enum thr_lock_type lock_type)=0; + virtual uint8 table_cache_type() { return 0; } + virtual my_bool register_query_cache_table(THD *thd, char *table_key, + uint key_length, + qc_engine_callback + *engine_callback, + ulonglong *engine_data) + { + *engine_callback= 0; + return (1); + } + virtual In_C_you_should_use_my_bool_instead() primary_key_is_clustered() { return (0); } + virtual int cmp_ref(const uchar *ref1, const uchar *ref2) + { + return memcmp(ref1, ref2, ref_length); + } + virtual const COND *cond_push(const COND *cond) { return cond; }; + virtual void cond_pop() { return; }; + virtual In_C_you_should_use_my_bool_instead() check_if_incompatible_data(HA_CREATE_INFO *create_info, + uint table_changes) + { return 1; } + virtual void use_hidden_primary_key(); +protected: + void ha_statistic_increment(ulong SSV::*offset) const; + void **ha_data(THD *) const; + THD *ha_thd(void) const; + virtual int rename_table(const char *from, const char *to); + virtual int delete_table(const char *name); +private: + inline void mark_trx_read_write(); +private: + virtual int open(const char *name, int mode, uint test_if_locked)=0; + virtual int index_init(uint idx, In_C_you_should_use_my_bool_instead() sorted) { active_index= idx; return 0; } + virtual int index_end() { active_index= 64; return 0; } + virtual int rnd_init(In_C_you_should_use_my_bool_instead() scan)= 0; + virtual int rnd_end() { return 0; } + virtual int write_row(uchar *buf __attribute__((unused))) + { + return 131; + } + virtual int update_row(const uchar *old_data __attribute__((unused)), + uchar *new_data __attribute__((unused))) + { + return 131; + } + virtual int delete_row(const uchar *buf __attribute__((unused))) + { + return 131; + } + virtual int reset() { return 0; } + virtual Table_flags table_flags(void) const= 0; + virtual int external_lock(THD *thd __attribute__((unused)), + int lock_type __attribute__((unused))) + { + return 0; + } + virtual void release_auto_increment() { return; }; + virtual int check_for_upgrade(HA_CHECK_OPT *check_opt) + { return 0; } + virtual int check(THD* thd, HA_CHECK_OPT* check_opt) + { return -1; } + virtual int repair(THD* thd, HA_CHECK_OPT* check_opt) + { return -1; } + virtual void start_bulk_insert(ha_rows rows) {} + virtual int end_bulk_insert() { return 0; } + virtual int index_read(uchar * buf, const uchar * key, uint key_len, + enum ha_rkey_function find_flag) + { return 131; } + virtual int index_read_last(uchar * buf, const uchar * key, uint key_len) + { return ((_my_thread_var())->thr_errno= 131); } + virtual int bulk_update_row(const uchar *old_data, uchar *new_data, + uint *dup_key_found) + { + assert((0)); + return 131; + } + virtual int delete_all_rows() + { return ((_my_thread_var())->thr_errno=131); } + virtual int reset_auto_increment(ulonglong value) + { return 131; } + virtual int backup(THD* thd, HA_CHECK_OPT* check_opt) + { return -1; } + virtual int restore(THD* thd, HA_CHECK_OPT* check_opt) + { return -1; } + virtual int optimize(THD* thd, HA_CHECK_OPT* check_opt) + { return -1; } + virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt) + { return -1; } + virtual In_C_you_should_use_my_bool_instead() check_and_repair(THD *thd) { return (1); } + virtual int disable_indexes(uint mode) { return 131; } + virtual int enable_indexes(uint mode) { return 131; } + virtual int discard_or_import_tablespace(my_bool discard) + { return ((_my_thread_var())->thr_errno=131); } + virtual void prepare_for_alter() { return; } + virtual void drop_table(const char *name); + virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; + virtual int create_handler_files(const char *name, const char *old_name, + int action_flag, HA_CREATE_INFO *info) + { return (0); } + virtual int change_partitions(HA_CREATE_INFO *create_info, + const char *path, + ulonglong *copied, + ulonglong *deleted, + const uchar *pack_frm_data, + size_t pack_frm_len) + { return 131; } + virtual int drop_partitions(const char *path) + { return 131; } + virtual int rename_partitions(const char *path) + { return 131; } + virtual int optimize_partitions(THD *thd) + { return 131; } + virtual int analyze_partitions(THD *thd) + { return 131; } + virtual int check_partitions(THD *thd) + { return 131; } + virtual int repair_partitions(THD *thd) + { return 131; } +}; +extern const char *ha_row_type[]; +extern const char *tx_isolation_names[]; +extern const char *binlog_format_names[]; +extern TYPELIB tx_isolation_typelib; +extern TYPELIB myisam_stats_method_typelib; +extern ulong total_ha, total_ha_2pc; +handlerton *ha_default_handlerton(THD *thd); +plugin_ref ha_resolve_by_name(THD *thd, const LEX_STRING *name); +plugin_ref ha_lock_engine(THD *thd, handlerton *hton); +handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type); +handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc, + handlerton *db_type); +handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type, + In_C_you_should_use_my_bool_instead() no_substitute, In_C_you_should_use_my_bool_instead() report_error); +static inline enum legacy_db_type ha_legacy_type(const handlerton *db_type) +{ + return (db_type == NULL) ? DB_TYPE_UNKNOWN : db_type->db_type; +} +static inline const char *ha_resolve_storage_engine_name(const handlerton *db_type) +{ + return db_type == NULL ? "UNKNOWN" : hton2plugin[db_type->slot]->name.str; +} +static inline In_C_you_should_use_my_bool_instead() ha_check_storage_engine_flag(const handlerton *db_type, uint32 flag) +{ + return db_type == NULL ? (0) : ((db_type->flags & flag) ? 1 : 0); +} +static inline In_C_you_should_use_my_bool_instead() ha_storage_engine_is_enabled(const handlerton *db_type) +{ + return (db_type && db_type->create) ? + (db_type->state == SHOW_OPTION_YES) : (0); +} +int ha_init_errors(void); +int ha_init(void); +int ha_end(void); +int ha_initialize_handlerton(st_plugin_int *plugin); +int ha_finalize_handlerton(st_plugin_int *plugin); +TYPELIB *ha_known_exts(void); +int ha_panic(enum ha_panic_function flag); +void ha_close_connection(THD* thd); +In_C_you_should_use_my_bool_instead() ha_flush_logs(handlerton *db_type); +void ha_drop_database(char* path); +int ha_create_table(THD *thd, const char *path, + const char *db, const char *table_name, + HA_CREATE_INFO *create_info, + In_C_you_should_use_my_bool_instead() update_create_info); +int ha_delete_table(THD *thd, handlerton *db_type, const char *path, + const char *db, const char *alias, In_C_you_should_use_my_bool_instead() generate_warning); +In_C_you_should_use_my_bool_instead() ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat); +int ha_create_table_from_engine(THD* thd, const char *db, const char *name); +int ha_discover(THD* thd, const char* dbname, const char* name, + uchar** frmblob, size_t* frmlen); +int ha_find_files(THD *thd,const char *db,const char *path, + const char *wild, In_C_you_should_use_my_bool_instead() dir, List<LEX_STRING>* files); +int ha_table_exists_in_engine(THD* thd, const char* db, const char* name); +extern "C" int ha_init_key_cache(const char *name, KEY_CACHE *key_cache); +int ha_resize_key_cache(KEY_CACHE *key_cache); +int ha_change_key_cache_param(KEY_CACHE *key_cache); +int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache); +int ha_end_key_cache(KEY_CACHE *key_cache); +int ha_release_temporary_latches(THD *thd); +int ha_start_consistent_snapshot(THD *thd); +int ha_commit_or_rollback_by_xid(XID *xid, In_C_you_should_use_my_bool_instead() commit); +int ha_commit_one_phase(THD *thd, In_C_you_should_use_my_bool_instead() all); +int ha_rollback_trans(THD *thd, In_C_you_should_use_my_bool_instead() all); +int ha_prepare(THD *thd); +int ha_recover(HASH *commit_list); +int ha_commit_trans(THD *thd, In_C_you_should_use_my_bool_instead() all); +int ha_autocommit_or_rollback(THD *thd, int error); +int ha_enable_transaction(THD *thd, In_C_you_should_use_my_bool_instead() on); +int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv); +int ha_savepoint(THD *thd, SAVEPOINT *sv); +int ha_release_savepoint(THD *thd, SAVEPOINT *sv); +void trans_register_ha(THD *thd, In_C_you_should_use_my_bool_instead() all, handlerton *ht); +#include "parse_file.h" +enum file_opt_type { + FILE_OPTIONS_STRING, + FILE_OPTIONS_ESTRING, + FILE_OPTIONS_ULONGLONG, + FILE_OPTIONS_REV, + FILE_OPTIONS_TIMESTAMP, + FILE_OPTIONS_STRLIST, + FILE_OPTIONS_ULLLIST +}; +struct File_option +{ + LEX_STRING name; + int offset; + file_opt_type type; +}; +class Unknown_key_hook +{ +public: + Unknown_key_hook() {} + virtual ~Unknown_key_hook() {} + virtual In_C_you_should_use_my_bool_instead() process_unknown_string(char *&unknown_key, uchar* base, + MEM_ROOT *mem_root, char *end)= 0; +}; +class File_parser_dummy_hook: public Unknown_key_hook +{ +public: + File_parser_dummy_hook() {} + virtual In_C_you_should_use_my_bool_instead() process_unknown_string(char *&unknown_key, uchar* base, + MEM_ROOT *mem_root, char *end); +}; +extern File_parser_dummy_hook file_parser_dummy_hook; +In_C_you_should_use_my_bool_instead() get_file_options_ulllist(char *&ptr, char *end, char *line, + uchar* base, File_option *parameter, + MEM_ROOT *mem_root); +char * +parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str); +class File_parser; +File_parser *sql_parse_prepare(const LEX_STRING *file_name, + MEM_ROOT *mem_root, In_C_you_should_use_my_bool_instead() bad_format_errors); +my_bool +sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, + const LEX_STRING *type, + uchar* base, File_option *parameters, uint versions); +my_bool rename_in_schema_file(const char *schema, const char *old_name, + const char *new_name, ulonglong revision, + uint num_view_backups); +class File_parser: public Sql_alloc +{ + char *buff, *start, *end; + LEX_STRING file_type; + my_bool content_ok; +public: + File_parser() :buff(0), start(0), end(0), content_ok(0) + { file_type.str= 0; file_type.length= 0; } + my_bool ok() { return content_ok; } + LEX_STRING *type() { return &file_type; } + my_bool parse(uchar* base, MEM_ROOT *mem_root, + struct File_option *parameters, uint required, + Unknown_key_hook *hook); + friend File_parser *sql_parse_prepare(const LEX_STRING *file_name, + MEM_ROOT *mem_root, + In_C_you_should_use_my_bool_instead() bad_format_errors); +}; +#include "table.h" +class Item; +class Item_subselect; +class GRANT_TABLE; +class st_select_lex_unit; +class st_select_lex; +class partition_info; +class COND_EQUAL; +class Security_context; +class View_creation_ctx : public Default_object_creation_ctx, + public Sql_alloc +{ +public: + static View_creation_ctx *create(THD *thd); + static View_creation_ctx *create(THD *thd, + TABLE_LIST *view); +private: + View_creation_ctx(THD *thd) + : Default_object_creation_ctx(thd) + { } +}; +typedef struct st_order { + struct st_order *next; + Item **item; + Item *item_ptr; + Item **item_copy; + int counter; + In_C_you_should_use_my_bool_instead() asc; + In_C_you_should_use_my_bool_instead() free_me; + In_C_you_should_use_my_bool_instead() in_field_list; + In_C_you_should_use_my_bool_instead() counter_used; + Field *field; + char *buff; + table_map used, depend_map; +} ORDER; +typedef struct st_grant_info +{ + GRANT_TABLE *grant_table; + uint version; + ulong privilege; + ulong want_privilege; + ulong orig_want_privilege; +} GRANT_INFO; +enum tmp_table_type +{ + NO_TMP_TABLE, NON_TRANSACTIONAL_TMP_TABLE, TRANSACTIONAL_TMP_TABLE, + INTERNAL_TMP_TABLE, SYSTEM_TMP_TABLE +}; +enum trg_event_type +{ + TRG_EVENT_INSERT= 0, + TRG_EVENT_UPDATE= 1, + TRG_EVENT_DELETE= 2, + TRG_EVENT_MAX +}; +enum frm_type_enum +{ + FRMTYPE_ERROR= 0, + FRMTYPE_TABLE, + FRMTYPE_VIEW +}; +enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP }; +typedef struct st_filesort_info +{ + IO_CACHE *io_cache; + uchar **sort_keys; + uchar *buffpek; + uint buffpek_len; + uchar *addon_buf; + size_t addon_length; + struct st_sort_addon_field *addon_field; + void (*unpack)(struct st_sort_addon_field *, uchar *); + uchar *record_pointers; + ha_rows found_records; +} FILESORT_INFO; +enum timestamp_auto_set_type +{ + TIMESTAMP_NO_AUTO_SET= 0, TIMESTAMP_AUTO_SET_ON_INSERT= 1, + TIMESTAMP_AUTO_SET_ON_UPDATE= 2, TIMESTAMP_AUTO_SET_ON_BOTH= 3 +}; +class Field_timestamp; +class Field_blob; +class Table_triggers_list; +enum enum_table_category +{ + TABLE_UNKNOWN_CATEGORY=0, + TABLE_CATEGORY_TEMPORARY=1, + TABLE_CATEGORY_USER=2, + TABLE_CATEGORY_SYSTEM=3, + TABLE_CATEGORY_INFORMATION=4, + TABLE_CATEGORY_PERFORMANCE=5 +}; +typedef enum enum_table_category TABLE_CATEGORY; +TABLE_CATEGORY get_table_category(const LEX_STRING *db, + const LEX_STRING *name); +typedef struct st_table_share +{ + st_table_share() {} + TABLE_CATEGORY table_category; + HASH name_hash; + MEM_ROOT mem_root; + TYPELIB keynames; + TYPELIB fieldnames; + TYPELIB *intervals; + pthread_mutex_t mutex; + pthread_cond_t cond; + struct st_table_share *next, + **prev; + Field **field; + Field **found_next_number_field; + Field *timestamp_field; + KEY *key_info; + uint *blob_field; + uchar *default_values; + LEX_STRING comment; + CHARSET_INFO *table_charset; + MY_BITMAP all_set; + LEX_STRING table_cache_key; + LEX_STRING db; + LEX_STRING table_name; + LEX_STRING path; + LEX_STRING normalized_path; + LEX_STRING connect_string; + key_map keys_in_use; + key_map keys_for_keyread; + ha_rows min_rows, max_rows; + ulong avg_row_length; + ulong raid_chunksize; + ulong version, mysql_version; + ulong timestamp_offset; + ulong reclength; + plugin_ref db_plugin; + inline handlerton *db_type() const + { + return db_plugin ? ((handlerton*)((db_plugin)[0]->data)) : NULL; + } + enum row_type row_type; + enum tmp_table_type tmp_table; + enum ha_choice transactional; + enum ha_choice page_checksum; + uint ref_count; + uint open_count; + uint blob_ptr_size; + uint key_block_size; + uint null_bytes, last_null_bit_pos; + uint fields; + uint rec_buff_length; + uint keys, key_parts; + uint max_key_length, max_unique_length, total_key_length; + uint uniques; + uint null_fields; + uint blob_fields; + uint timestamp_field_offset; + uint varchar_fields; + uint db_create_options; + uint db_options_in_use; + uint db_record_offset; + uint raid_type, raid_chunks; + uint rowid_field_offset; + uint primary_key; + uint next_number_index; + uint next_number_key_offset; + uint next_number_keypart; + uint error, open_errno, errarg; + uint column_bitmap_size; + uchar frm_version; + In_C_you_should_use_my_bool_instead() null_field_first; + In_C_you_should_use_my_bool_instead() system; + In_C_you_should_use_my_bool_instead() crypted; + In_C_you_should_use_my_bool_instead() db_low_byte_first; + In_C_you_should_use_my_bool_instead() crashed; + In_C_you_should_use_my_bool_instead() is_view; + In_C_you_should_use_my_bool_instead() name_lock, replace_with_name_lock; + In_C_you_should_use_my_bool_instead() waiting_on_cond; + ulong table_map_id; + ulonglong table_map_version; + int cached_row_logging_check; + void set_table_cache_key(char *key_buff, uint key_length) + { + table_cache_key.str= key_buff; + table_cache_key.length= key_length; + db.str= table_cache_key.str; + db.length= strlen(db.str); + table_name.str= db.str + db.length + 1; + table_name.length= strlen(table_name.str); + } + void set_table_cache_key(char *key_buff, const char *key, uint key_length) + { + memcpy(key_buff, key, key_length); + set_table_cache_key(key_buff, key_length); + } + inline In_C_you_should_use_my_bool_instead() honor_global_locks() + { + return ((table_category == TABLE_CATEGORY_USER) + || (table_category == TABLE_CATEGORY_SYSTEM)); + } + inline In_C_you_should_use_my_bool_instead() require_write_privileges() + { + return (table_category == TABLE_CATEGORY_PERFORMANCE); + } + inline ulong get_table_def_version() + { + return table_map_id; + } + enum enum_table_ref_type get_table_ref_type() const + { + if (is_view) + return TABLE_REF_VIEW; + switch (tmp_table) { + case NO_TMP_TABLE: + return TABLE_REF_BASE_TABLE; + case SYSTEM_TMP_TABLE: + return TABLE_REF_I_S_TABLE; + default: + return TABLE_REF_TMP_TABLE; + } + } + ulong get_table_ref_version() const + { + return (tmp_table == SYSTEM_TMP_TABLE || is_view) ? 0 : table_map_id; + } +} TABLE_SHARE; +extern ulong refresh_version; +enum index_hint_type +{ + INDEX_HINT_IGNORE, + INDEX_HINT_USE, + INDEX_HINT_FORCE +}; +struct st_table { + st_table() {} + TABLE_SHARE *s; + handler *file; + struct st_table *next, *prev; + struct st_table *parent; + TABLE_LIST *child_l; + TABLE_LIST **child_last_l; + THD *in_use; + Field **field; + uchar *record[2]; + uchar *write_row_record; + uchar *insert_values; + key_map covering_keys; + key_map quick_keys, merge_keys; + key_map keys_in_use_for_query; + key_map keys_in_use_for_group_by; + key_map keys_in_use_for_order_by; + KEY *key_info; + Field *next_number_field; + Field *found_next_number_field; + Field_timestamp *timestamp_field; + Table_triggers_list *triggers; + TABLE_LIST *pos_in_table_list; + ORDER *group; + const char *alias; + uchar *null_flags; + my_bitmap_map *bitmap_init_value; + MY_BITMAP def_read_set, def_write_set, tmp_set; + MY_BITMAP *read_set, *write_set; + query_id_t query_id; + ha_rows quick_rows[64]; + key_part_map const_key_parts[64]; + uint quick_key_parts[64]; + uint quick_n_ranges[64]; + ha_rows quick_condition_rows; + timestamp_auto_set_type timestamp_field_type; + table_map map; + uint lock_position; + uint lock_data_start; + uint lock_count; + uint tablenr,used_fields; + uint temp_pool_slot; + uint status; + uint db_stat; + uint derived_select_number; + int current_lock; + my_bool copy_blobs; + uint maybe_null; + my_bool null_row; + my_bool force_index; + my_bool distinct,const_table,no_rows; + my_bool key_read, no_keyread; + my_bool open_placeholder; + my_bool locked_by_logger; + my_bool no_replicate; + my_bool locked_by_name; + my_bool fulltext_searched; + my_bool no_cache; + my_bool open_by_handler; + my_bool auto_increment_field_not_null; + my_bool insert_or_update; + my_bool alias_name_used; + my_bool get_fields_in_item_tree; + my_bool children_attached; + REGINFO reginfo; + MEM_ROOT mem_root; + GRANT_INFO grant; + FILESORT_INFO sort; + In_C_you_should_use_my_bool_instead() fill_item_list(List<Item> *item_list) const; + void reset_item_list(List<Item> *item_list) const; + void clear_column_bitmaps(void); + void prepare_for_position(void); + void mark_columns_used_by_index_no_reset(uint index, MY_BITMAP *map); + void mark_columns_used_by_index(uint index); + void restore_column_maps_after_mark_index(); + void mark_auto_increment_column(void); + void mark_columns_needed_for_update(void); + void mark_columns_needed_for_delete(void); + void mark_columns_needed_for_insert(void); + inline void column_bitmaps_set(MY_BITMAP *read_set_arg, + MY_BITMAP *write_set_arg) + { + read_set= read_set_arg; + write_set= write_set_arg; + if (file) + file->column_bitmaps_signal(); + } + inline void column_bitmaps_set_no_signal(MY_BITMAP *read_set_arg, + MY_BITMAP *write_set_arg) + { + read_set= read_set_arg; + write_set= write_set_arg; + } + inline void use_all_columns() + { + column_bitmaps_set(&s->all_set, &s->all_set); + } + inline void default_column_bitmaps() + { + read_set= &def_read_set; + write_set= &def_write_set; + } + inline In_C_you_should_use_my_bool_instead() is_name_opened() { return db_stat || open_placeholder; } + inline In_C_you_should_use_my_bool_instead() needs_reopen_or_name_lock() + { return s->version != refresh_version; } + In_C_you_should_use_my_bool_instead() is_children_attached(void); +}; +enum enum_schema_table_state +{ + NOT_PROCESSED= 0, + PROCESSED_BY_CREATE_SORT_INDEX, + PROCESSED_BY_JOIN_EXEC +}; +typedef struct st_foreign_key_info +{ + LEX_STRING *forein_id; + LEX_STRING *referenced_db; + 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; +enum enum_schema_tables +{ + SCH_CHARSETS= 0, + SCH_COLLATIONS, + SCH_COLLATION_CHARACTER_SET_APPLICABILITY, + SCH_COLUMNS, + SCH_COLUMN_PRIVILEGES, + SCH_ENGINES, + SCH_EVENTS, + SCH_FILES, + SCH_GLOBAL_STATUS, + SCH_GLOBAL_VARIABLES, + SCH_KEY_COLUMN_USAGE, + SCH_OPEN_TABLES, + SCH_PARTITIONS, + SCH_PLUGINS, + SCH_PROCESSLIST, + SCH_PROFILES, + SCH_REFERENTIAL_CONSTRAINTS, + SCH_PROCEDURES, + SCH_SCHEMATA, + SCH_SCHEMA_PRIVILEGES, + SCH_SESSION_STATUS, + SCH_SESSION_VARIABLES, + SCH_STATISTICS, + SCH_STATUS, + SCH_TABLES, + SCH_TABLE_CONSTRAINTS, + SCH_TABLE_NAMES, + SCH_TABLE_PRIVILEGES, + SCH_TRIGGERS, + SCH_USER_PRIVILEGES, + SCH_VARIABLES, + SCH_VIEWS +}; +typedef struct st_field_info +{ + const char* field_name; + uint field_length; + enum enum_field_types field_type; + int value; + uint field_flags; + const char* old_name; + uint open_method; +} ST_FIELD_INFO; +struct TABLE_LIST; +typedef class Item COND; +typedef struct st_schema_table +{ + const char* table_name; + ST_FIELD_INFO *fields_info; + TABLE *(*create_table) (THD *thd, TABLE_LIST *table_list); + int (*fill_table) (THD *thd, TABLE_LIST *tables, COND *cond); + int (*old_format) (THD *thd, struct st_schema_table *schema_table); + int (*process_table) (THD *thd, TABLE_LIST *tables, TABLE *table, + In_C_you_should_use_my_bool_instead() res, LEX_STRING *db_name, LEX_STRING *table_name); + int idx_field1, idx_field2; + In_C_you_should_use_my_bool_instead() hidden; + uint i_s_requested_object; +} ST_SCHEMA_TABLE; +struct st_lex; +class select_union; +class TMP_TABLE_PARAM; +Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, + const char *name); +struct Field_translator +{ + Item *item; + const char *name; +}; +class Natural_join_column: public Sql_alloc +{ +public: + Field_translator *view_field; + Field *table_field; + TABLE_LIST *table_ref; + In_C_you_should_use_my_bool_instead() is_common; +public: + Natural_join_column(Field_translator *field_param, TABLE_LIST *tab); + Natural_join_column(Field *field_param, TABLE_LIST *tab); + const char *name(); + Item *create_item(THD *thd); + Field *field(); + const char *table_name(); + const char *db_name(); + GRANT_INFO *grant(); +}; +class Index_hint; +struct TABLE_LIST +{ + TABLE_LIST() {} + inline void init_one_table(const char *db_name_arg, + const char *table_name_arg, + enum thr_lock_type lock_type_arg) + { + bzero((char*) this, sizeof(*this)); + db= (char*) db_name_arg; + table_name= alias= (char*) table_name_arg; + lock_type= lock_type_arg; + } + TABLE_LIST *next_local; + TABLE_LIST *next_global, **prev_global; + char *db, *alias, *table_name, *schema_table_name; + char *option; + Item *on_expr; + Item *prep_on_expr; + COND_EQUAL *cond_equal; + TABLE_LIST *natural_join; + In_C_you_should_use_my_bool_instead() is_natural_join; + List<String> *join_using_fields; + List<Natural_join_column> *join_columns; + In_C_you_should_use_my_bool_instead() is_join_columns_complete; + TABLE_LIST *next_name_resolution_table; + List<Index_hint> *index_hints; + TABLE *table; + uint table_id; + select_union *derived_result; + TABLE_LIST *correspondent_table; + st_select_lex_unit *derived; + ST_SCHEMA_TABLE *schema_table; + st_select_lex *schema_select_lex; + In_C_you_should_use_my_bool_instead() schema_table_reformed; + TMP_TABLE_PARAM *schema_table_param; + st_select_lex *select_lex; + st_lex *view; + Field_translator *field_translation; + Field_translator *field_translation_end; + TABLE_LIST *merge_underlying_list; + List<TABLE_LIST> *view_tables; + TABLE_LIST *belong_to_view; + TABLE_LIST *referencing_view; + TABLE_LIST *parent_l; + Security_context *security_ctx; + Security_context *view_sctx; + In_C_you_should_use_my_bool_instead() allowed_show; + TABLE_LIST *next_leaf; + Item *where; + Item *check_option; + LEX_STRING select_stmt; + LEX_STRING md5; + LEX_STRING source; + LEX_STRING view_db; + LEX_STRING view_name; + LEX_STRING timestamp; + st_lex_user definer; + ulonglong file_version; + ulonglong updatable_view; + ulonglong revision; + ulonglong algorithm; + ulonglong view_suid; + ulonglong with_check; + uint8 effective_with_check; + uint8 effective_algorithm; + GRANT_INFO grant; + ulonglong engine_data; + qc_engine_callback callback_func; + thr_lock_type lock_type; + uint outer_join; + uint shared; + size_t db_length; + size_t table_name_length; + In_C_you_should_use_my_bool_instead() updatable; + In_C_you_should_use_my_bool_instead() straight; + In_C_you_should_use_my_bool_instead() updating; + In_C_you_should_use_my_bool_instead() force_index; + In_C_you_should_use_my_bool_instead() ignore_leaves; + table_map dep_tables; + table_map on_expr_dep_tables; + struct st_nested_join *nested_join; + TABLE_LIST *embedding; + List<TABLE_LIST> *join_list; + In_C_you_should_use_my_bool_instead() cacheable_table; + In_C_you_should_use_my_bool_instead() table_in_first_from_clause; + In_C_you_should_use_my_bool_instead() skip_temporary; + In_C_you_should_use_my_bool_instead() contain_auto_increment; + In_C_you_should_use_my_bool_instead() multitable_view; + In_C_you_should_use_my_bool_instead() compact_view_format; + In_C_you_should_use_my_bool_instead() where_processed; + In_C_you_should_use_my_bool_instead() check_option_processed; + enum frm_type_enum required_type; + handlerton *db_type; + char timestamp_buffer[20]; + In_C_you_should_use_my_bool_instead() prelocking_placeholder; + In_C_you_should_use_my_bool_instead() create; + In_C_you_should_use_my_bool_instead() internal_tmp_table; + View_creation_ctx *view_creation_ctx; + LEX_STRING view_client_cs_name; + LEX_STRING view_connection_cl_name; + LEX_STRING view_body_utf8; + uint8 trg_event_map; + uint i_s_requested_object; + In_C_you_should_use_my_bool_instead() has_db_lookup_value; + In_C_you_should_use_my_bool_instead() has_table_lookup_value; + uint table_open_method; + enum enum_schema_table_state schema_table_state; + void calc_md5(char *buffer); + void set_underlying_merge(); + int view_check_option(THD *thd, In_C_you_should_use_my_bool_instead() ignore_failure); + In_C_you_should_use_my_bool_instead() setup_underlying(THD *thd); + void cleanup_items(); + In_C_you_should_use_my_bool_instead() placeholder() + { + return derived || view || schema_table || create && !table->db_stat || + !table; + } + void print(THD *thd, String *str, enum_query_type query_type); + In_C_you_should_use_my_bool_instead() check_single_table(TABLE_LIST **table, table_map map, + TABLE_LIST *view); + In_C_you_should_use_my_bool_instead() set_insert_values(MEM_ROOT *mem_root); + void hide_view_error(THD *thd); + TABLE_LIST *find_underlying_table(TABLE *table); + TABLE_LIST *first_leaf_for_name_resolution(); + TABLE_LIST *last_leaf_for_name_resolution(); + In_C_you_should_use_my_bool_instead() is_leaf_for_name_resolution(); + inline TABLE_LIST *top_table() + { return belong_to_view ? belong_to_view : this; } + inline In_C_you_should_use_my_bool_instead() prepare_check_option(THD *thd) + { + In_C_you_should_use_my_bool_instead() res= (0); + if (effective_with_check) + res= prep_check_option(thd, effective_with_check); + return res; + } + inline In_C_you_should_use_my_bool_instead() prepare_where(THD *thd, Item **conds, + In_C_you_should_use_my_bool_instead() no_where_clause) + { + if (effective_algorithm == 2) + return prep_where(thd, conds, no_where_clause); + return (0); + } + void register_want_access(ulong want_access); + In_C_you_should_use_my_bool_instead() prepare_security(THD *thd); + Security_context *find_view_security_context(THD *thd); + In_C_you_should_use_my_bool_instead() prepare_view_securety_context(THD *thd); + void reinit_before_use(THD *thd); + Item_subselect *containing_subselect(); + In_C_you_should_use_my_bool_instead() process_index_hints(TABLE *table); + inline ulong get_child_def_version() + { + return child_def_version; + } + inline void set_child_def_version(ulong version) + { + child_def_version= version; + } + inline void init_child_def_version() + { + child_def_version= ~0UL; + } + inline + In_C_you_should_use_my_bool_instead() is_table_ref_id_equal(TABLE_SHARE *s) const + { + return (m_table_ref_type == s->get_table_ref_type() && + m_table_ref_version == s->get_table_ref_version()); + } + inline + void set_table_ref_id(TABLE_SHARE *s) + { + m_table_ref_type= s->get_table_ref_type(); + m_table_ref_version= s->get_table_ref_version(); + } +private: + In_C_you_should_use_my_bool_instead() prep_check_option(THD *thd, uint8 check_opt_type); + In_C_you_should_use_my_bool_instead() prep_where(THD *thd, Item **conds, In_C_you_should_use_my_bool_instead() no_where_clause); + ulong child_def_version; + enum enum_table_ref_type m_table_ref_type; + ulong m_table_ref_version; +}; +class Item; +class Field_iterator: public Sql_alloc +{ +public: + Field_iterator() {} + virtual ~Field_iterator() {} + virtual void set(TABLE_LIST *)= 0; + virtual void next()= 0; + virtual In_C_you_should_use_my_bool_instead() end_of_fields()= 0; + virtual const char *name()= 0; + virtual Item *create_item(THD *)= 0; + virtual Field *field()= 0; +}; +class Field_iterator_table: public Field_iterator +{ + Field **ptr; +public: + Field_iterator_table() :ptr(0) {} + void set(TABLE_LIST *table) { ptr= table->table->field; } + void set_table(TABLE *table) { ptr= table->field; } + void next() { ptr++; } + In_C_you_should_use_my_bool_instead() end_of_fields() { return *ptr == 0; } + const char *name(); + Item *create_item(THD *thd); + Field *field() { return *ptr; } +}; +class Field_iterator_view: public Field_iterator +{ + Field_translator *ptr, *array_end; + TABLE_LIST *view; +public: + Field_iterator_view() :ptr(0), array_end(0) {} + void set(TABLE_LIST *table); + void next() { ptr++; } + In_C_you_should_use_my_bool_instead() end_of_fields() { return ptr == array_end; } + const char *name(); + Item *create_item(THD *thd); + Item **item_ptr() {return &ptr->item; } + Field *field() { return 0; } + inline Item *item() { return ptr->item; } + Field_translator *field_translator() { return ptr; } +}; +class Field_iterator_natural_join: public Field_iterator +{ + List_iterator_fast<Natural_join_column> column_ref_it; + Natural_join_column *cur_column_ref; +public: + Field_iterator_natural_join() :cur_column_ref(NULL) {} + ~Field_iterator_natural_join() {} + void set(TABLE_LIST *table); + void next(); + In_C_you_should_use_my_bool_instead() end_of_fields() { return !cur_column_ref; } + const char *name() { return cur_column_ref->name(); } + Item *create_item(THD *thd) { return cur_column_ref->create_item(thd); } + Field *field() { return cur_column_ref->field(); } + Natural_join_column *column_ref() { return cur_column_ref; } +}; +class Field_iterator_table_ref: public Field_iterator +{ + TABLE_LIST *table_ref, *first_leaf, *last_leaf; + Field_iterator_table table_field_it; + Field_iterator_view view_field_it; + Field_iterator_natural_join natural_join_it; + Field_iterator *field_it; + void set_field_iterator(); +public: + Field_iterator_table_ref() :field_it(NULL) {} + void set(TABLE_LIST *table); + void next(); + In_C_you_should_use_my_bool_instead() end_of_fields() + { return (table_ref == last_leaf && field_it->end_of_fields()); } + const char *name() { return field_it->name(); } + const char *table_name(); + const char *db_name(); + GRANT_INFO *grant(); + Item *create_item(THD *thd) { return field_it->create_item(thd); } + Field *field() { return field_it->field(); } + Natural_join_column *get_or_create_column_ref(TABLE_LIST *parent_table_ref); + Natural_join_column *get_natural_column_ref(); +}; +typedef struct st_nested_join +{ + List<TABLE_LIST> join_list; + table_map used_tables; + table_map not_null_tables; + struct st_join_table *first_nested; + uint counter; + nested_join_map nj_map; +} NESTED_JOIN; +typedef struct st_changed_table_list +{ + struct st_changed_table_list *next; + char *key; + uint32 key_length; +} CHANGED_TABLE_LIST; +typedef struct st_open_table_list{ + struct st_open_table_list *next; + char *db,*table; + uint32 in_use,locked; +} OPEN_TABLE_LIST; +typedef struct st_table_field_w_type +{ + LEX_STRING name; + LEX_STRING type; + LEX_STRING cset; +} TABLE_FIELD_W_TYPE; +my_bool +table_check_intact(TABLE *table, const uint table_f_count, + const TABLE_FIELD_W_TYPE *table_def); +static inline my_bitmap_map *tmp_use_all_columns(TABLE *table, + MY_BITMAP *bitmap) +{ + my_bitmap_map *old= bitmap->bitmap; + bitmap->bitmap= table->s->all_set.bitmap; + return old; +} +static inline void tmp_restore_column_map(MY_BITMAP *bitmap, + my_bitmap_map *old) +{ + bitmap->bitmap= old; +} +static inline my_bitmap_map *dbug_tmp_use_all_columns(TABLE *table, + MY_BITMAP *bitmap) +{ + return tmp_use_all_columns(table, bitmap); +} +static inline void dbug_tmp_restore_column_map(MY_BITMAP *bitmap, + my_bitmap_map *old) +{ + tmp_restore_column_map(bitmap, old); +} +size_t max_row_length(TABLE *table, const uchar *data); +#include "sql_error.h" +class MYSQL_ERROR: public Sql_alloc +{ +public: + enum enum_warning_level + { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END}; + uint code; + enum_warning_level level; + char *msg; + MYSQL_ERROR(THD *thd, uint code_arg, enum_warning_level level_arg, + const char *msg_arg) + :code(code_arg), level(level_arg) + { + if (msg_arg) + set_msg(thd, msg_arg); + } + void set_msg(THD *thd, const char *msg_arg); +}; +MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, + uint code, const char *msg); +void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level, + uint code, const char *format, ...); +void mysql_reset_errors(THD *thd, In_C_you_should_use_my_bool_instead() force); +In_C_you_should_use_my_bool_instead() mysqld_show_warnings(THD *thd, ulong levels_to_show); +extern const LEX_STRING warning_level_names[]; +#include "field.h" +const uint32 max_field_size= (uint32) 4294967295U; +class Send_field; +class Protocol; +class Create_field; +struct st_cache_field; +int field_conv(Field *to,Field *from); +inline uint get_enum_pack_length(int elements) +{ + return elements < 256 ? 1 : 2; +} +inline uint get_set_pack_length(int elements) +{ + uint len= (elements + 7) / 8; + return len > 4 ? 8 : len; +} +class Field +{ + Field(const Item &); + void operator=(Field &); +public: + static void *operator new(size_t size) {return sql_alloc(size); } + static void operator delete(void *ptr_arg, size_t size) { ; } + uchar *ptr; + uchar *null_ptr; + struct st_table *table; + struct st_table *orig_table; + const char **table_name, *field_name; + LEX_STRING comment; + key_map key_start, part_of_key, part_of_key_not_clustered; + key_map part_of_sortkey; + enum utype { NONE,DATE,SHIELD,NOEMPTY,CASEUP,PNR,BGNR,PGNR,YES,NO,REL, + CHECK,EMPTY,UNKNOWN_FIELD,CASEDN,NEXT_NUMBER,INTERVAL_FIELD, + BIT_FIELD, TIMESTAMP_OLD_FIELD, CAPITALIZE, BLOB_FIELD, + TIMESTAMP_DN_FIELD, TIMESTAMP_UN_FIELD, TIMESTAMP_DNUN_FIELD}; + enum geometry_type + { + GEOM_GEOMETRY = 0, GEOM_POINT = 1, GEOM_LINESTRING = 2, GEOM_POLYGON = 3, + GEOM_MULTIPOINT = 4, GEOM_MULTILINESTRING = 5, GEOM_MULTIPOLYGON = 6, + GEOM_GEOMETRYCOLLECTION = 7 + }; + enum imagetype { itRAW, itMBR}; + utype unireg_check; + uint32 field_length; + uint32 flags; + uint16 field_index; + uchar null_bit; + In_C_you_should_use_my_bool_instead() is_created_from_null_item; + Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg); + virtual ~Field() {} + virtual int store(const char *to, uint length,CHARSET_INFO *cs)=0; + virtual int store(double nr)=0; + virtual int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val)=0; + virtual int store_decimal(const my_decimal *d)=0; + virtual int store_time(MYSQL_TIME *ltime, timestamp_type t_type); + int store(const char *to, uint length, CHARSET_INFO *cs, + enum_check_fields check_level); + virtual double val_real(void)=0; + virtual longlong val_int(void)=0; + virtual my_decimal *val_decimal(my_decimal *); + inline String *val_str(String *str) { return val_str(str, str); } + virtual String *val_str(String*,String *)=0; + String *val_int_as_str(String *val_buffer, my_bool unsigned_flag); + virtual In_C_you_should_use_my_bool_instead() str_needs_quotes() { return (0); } + virtual Item_result result_type () const=0; + virtual Item_result cmp_type () const { return result_type(); } + virtual Item_result cast_to_int_type () const { return result_type(); } + static In_C_you_should_use_my_bool_instead() type_can_have_key_part(enum_field_types); + static enum_field_types field_type_merge(enum_field_types, enum_field_types); + static Item_result result_merge_type(enum_field_types); + virtual In_C_you_should_use_my_bool_instead() eq(Field *field) + { + return (ptr == field->ptr && null_ptr == field->null_ptr && + null_bit == field->null_bit); + } + virtual In_C_you_should_use_my_bool_instead() eq_def(Field *field); + virtual uint32 pack_length() const { return (uint32) field_length; } + virtual uint32 pack_length_in_rec() const { return pack_length(); } + virtual int compatible_field_size(uint field_metadata); + virtual uint pack_length_from_metadata(uint field_metadata) + { return field_metadata; } + virtual uint row_pack_length() { return 0; } + virtual int save_field_metadata(uchar *first_byte) + { return do_save_field_metadata(first_byte); } + virtual uint32 data_length() { return pack_length(); } + virtual uint32 sort_length() const { return pack_length(); } + virtual uint32 max_data_length() const { + return pack_length(); + }; + virtual int reset(void) { bzero(ptr,pack_length()); return 0; } + virtual void reset_fields() {} + virtual void set_default() + { + my_ptrdiff_t l_offset= (my_ptrdiff_t) (table->s->default_values - + table->record[0]); + memcpy(ptr, ptr + l_offset, pack_length()); + if (null_ptr) + *null_ptr= ((*null_ptr & (uchar) ~null_bit) | + null_ptr[l_offset] & null_bit); + } + virtual In_C_you_should_use_my_bool_instead() binary() const { return 1; } + virtual In_C_you_should_use_my_bool_instead() zero_pack() const { return 1; } + virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + virtual uint32 key_length() const { return pack_length(); } + virtual enum_field_types type() const =0; + virtual enum_field_types real_type() const { return type(); } + inline int cmp(const uchar *str) { return cmp(ptr,str); } + virtual int cmp_max(const uchar *a, const uchar *b, uint max_len) + { return cmp(a, b); } + virtual int cmp(const uchar *,const uchar *)=0; + virtual int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0L) + { return memcmp(a,b,pack_length()); } + virtual int cmp_offset(uint row_offset) + { return cmp(ptr,ptr+row_offset); } + virtual int cmp_binary_offset(uint row_offset) + { return cmp_binary(ptr, ptr+row_offset); }; + virtual int key_cmp(const uchar *a,const uchar *b) + { return cmp(a, b); } + virtual int key_cmp(const uchar *str, uint length) + { return cmp(ptr,str); } + virtual uint decimals() const { return 0; } + virtual void sql_type(String &str) const =0; + virtual uint size_of() const =0; + inline In_C_you_should_use_my_bool_instead() is_null(my_ptrdiff_t row_offset= 0) + { return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : table->null_row; } + inline In_C_you_should_use_my_bool_instead() is_real_null(my_ptrdiff_t row_offset= 0) + { return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : 0; } + inline In_C_you_should_use_my_bool_instead() is_null_in_record(const uchar *record) + { + if (!null_ptr) + return 0; + return ((record[(uint) (null_ptr -table->record[0])] & null_bit) ? 1 : 0); + } + inline In_C_you_should_use_my_bool_instead() is_null_in_record_with_offset(my_ptrdiff_t offset) + { + if (!null_ptr) + return 0; + return ((null_ptr[offset] & null_bit) ? 1 : 0); + } + inline void set_null(my_ptrdiff_t row_offset= 0) + { if (null_ptr) null_ptr[row_offset]|= null_bit; } + inline void set_notnull(my_ptrdiff_t row_offset= 0) + { if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; } + inline In_C_you_should_use_my_bool_instead() maybe_null(void) { return null_ptr != 0 || table->maybe_null; } + inline In_C_you_should_use_my_bool_instead() real_maybe_null(void) { return null_ptr != 0; } + enum { + LAST_NULL_BYTE_UNDEF= 0 + }; + size_t last_null_byte() const { + size_t bytes= do_last_null_byte(); + do {_db_pargs_(284,"debug"); _db_doprnt_ ("last_null_byte() ==> %ld", (long) bytes);} while(0); + assert(bytes <= table->s->null_bytes); + return bytes; + } + virtual void make_field(Send_field *); + virtual void sort_string(uchar *buff,uint length)=0; + virtual In_C_you_should_use_my_bool_instead() optimize_range(uint idx, uint part); + virtual In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (0); } + virtual void free() {} + virtual Field *new_field(MEM_ROOT *root, struct st_table *new_table, + In_C_you_should_use_my_bool_instead() keep_type); + virtual Field *new_key_field(MEM_ROOT *root, struct st_table *new_table, + uchar *new_ptr, uchar *new_null_ptr, + uint new_null_bit); + Field *clone(MEM_ROOT *mem_root, struct st_table *new_table); + inline void move_field(uchar *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg) + { + ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg; + } + inline void move_field(uchar *ptr_arg) { ptr=ptr_arg; } + virtual void move_field_offset(my_ptrdiff_t ptr_diff) + { + ptr=(uchar*) ((uchar*) (ptr)+ptr_diff); + if (null_ptr) + null_ptr=(uchar*) ((uchar*) (null_ptr)+ptr_diff); + } + virtual void get_image(uchar *buff, uint length, CHARSET_INFO *cs) + { memcpy(buff,ptr,length); } + virtual void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) + { memcpy(ptr,buff,length); } + virtual uint get_key_image(uchar *buff, uint length, imagetype type) + { + get_image(buff, length, &my_charset_bin); + return length; + } + virtual void set_key_image(const uchar *buff,uint length) + { set_image(buff,length, &my_charset_bin); } + inline longlong val_int_offset(uint row_offset) + { + ptr+=row_offset; + longlong tmp=val_int(); + ptr-=row_offset; + return tmp; + } + inline longlong val_int(const uchar *new_ptr) + { + uchar *old_ptr= ptr; + longlong return_value; + ptr= (uchar*) new_ptr; + return_value= val_int(); + ptr= old_ptr; + return return_value; + } + inline String *val_str(String *str, const uchar *new_ptr) + { + uchar *old_ptr= ptr; + ptr= (uchar*) new_ptr; + val_str(str); + ptr= old_ptr; + return str; + } + virtual In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first); + uchar *pack(uchar *to, const uchar *from) + { + const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("Field::pack","./sql/field.h",390,&_db_func_,&_db_file_,&_db_level_, &_db_framep_); + uchar *result= this->pack(to, from, UINT_MAX, table->s->db_low_byte_first); + do {_db_return_ (392, &_db_func_, &_db_file_, &_db_level_); return(result);} while(0); + } + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first); + const uchar *unpack(uchar* to, const uchar *from) + { + const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("Field::unpack","./sql/field.h",402,&_db_func_,&_db_file_,&_db_level_, &_db_framep_); + const uchar *result= unpack(to, from, 0U, table->s->db_low_byte_first); + do {_db_return_ (404, &_db_func_, &_db_file_, &_db_level_); return(result);} while(0); + } + virtual uchar *pack_key(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first) + { + return pack(to, from, max_length, low_byte_first); + } + virtual uchar *pack_key_from_key_image(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first) + { + return pack(to, from, max_length, low_byte_first); + } + virtual const uchar *unpack_key(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first) + { + return unpack(to, from, max_length, low_byte_first); + } + virtual uint packed_col_length(const uchar *to, uint length) + { return length;} + virtual uint max_packed_col_length(uint max_length) + { return max_length;} + virtual int pack_cmp(const uchar *a,const uchar *b, uint key_length_arg, + my_bool insert_or_update) + { return cmp(a,b); } + virtual int pack_cmp(const uchar *b, uint key_length_arg, + my_bool insert_or_update) + { return cmp(ptr,b); } + uint offset(uchar *record) + { + return (uint) (ptr - record); + } + void copy_from_tmp(int offset); + uint fill_cache_field(struct st_cache_field *copy); + virtual In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate); + virtual In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime); + virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; } + virtual CHARSET_INFO *sort_charset(void) const { return charset(); } + virtual In_C_you_should_use_my_bool_instead() has_charset(void) const { return (0); } + virtual void set_charset(CHARSET_INFO *charset_arg) { } + virtual enum Derivation derivation(void) const + { return DERIVATION_IMPLICIT; } + virtual void set_derivation(enum Derivation derivation_arg) { } + In_C_you_should_use_my_bool_instead() set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code, + int cuted_increment); + void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code, + const char *str, uint str_len, + timestamp_type ts_type, int cuted_increment); + void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code, + longlong nr, timestamp_type ts_type, + int cuted_increment); + void set_datetime_warning(MYSQL_ERROR::enum_warning_level, const uint code, + double nr, timestamp_type ts_type); + inline In_C_you_should_use_my_bool_instead() check_overflow(int op_result) + { + return (op_result == 2); + } + int warn_if_overflow(int op_result); + void init(TABLE *table_arg) + { + orig_table= table= table_arg; + table_name= &table_arg->alias; + } + virtual uint32 max_display_length()= 0; + virtual uint is_equal(Create_field *new_field); + longlong convert_decimal2longlong(const my_decimal *val, In_C_you_should_use_my_bool_instead() unsigned_flag, + int *err); + inline uint32 char_length() const + { + return field_length / charset()->mbmaxlen; + } + virtual geometry_type get_geometry_type() + { + assert(0); + return GEOM_GEOMETRY; + } + virtual void hash(ulong *nr, ulong *nr2); + friend In_C_you_should_use_my_bool_instead() reopen_table(THD *,struct st_table *,In_C_you_should_use_my_bool_instead()); + friend int cre_myisam(char * name, register TABLE *form, uint options, + ulonglong auto_increment_value); + friend class Copy_field; + friend class Item_avg_field; + friend class Item_std_field; + friend class Item_sum_num; + friend class Item_sum_sum; + friend class Item_sum_str; + friend class Item_sum_count; + friend class Item_sum_avg; + friend class Item_sum_std; + friend class Item_sum_min; + friend class Item_sum_max; + friend class Item_func_group_concat; +private: + virtual size_t do_last_null_byte() const; + virtual int do_save_field_metadata(uchar *metadata_ptr) + { return 0; } +}; +class Field_num :public Field { +public: + const uint8 dec; + In_C_you_should_use_my_bool_instead() zerofill,unsigned_flag; + Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + uint8 dec_arg, In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg); + Item_result result_type () const { return REAL_RESULT; } + void prepend_zeros(String *value); + void add_zerofill_and_unsigned(String &res) const; + friend class Create_field; + void make_field(Send_field *); + uint decimals() const { return (uint) dec; } + uint size_of() const { return sizeof(*this); } + In_C_you_should_use_my_bool_instead() eq_def(Field *field); + int store_decimal(const my_decimal *); + my_decimal *val_decimal(my_decimal *); + uint is_equal(Create_field *new_field); + int check_int(CHARSET_INFO *cs, const char *str, int length, + const char *int_end, int error); + In_C_you_should_use_my_bool_instead() get_int(CHARSET_INFO *cs, const char *from, uint len, + longlong *rnd, ulonglong unsigned_max, + longlong signed_min, longlong signed_max); +}; +class Field_str :public Field { +protected: + CHARSET_INFO *field_charset; + enum Derivation field_derivation; +public: + Field_str(uchar *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); + Item_result result_type () const { return STRING_RESULT; } + uint decimals() const { return 31; } + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val)=0; + int store_decimal(const my_decimal *); + 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_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; } + In_C_you_should_use_my_bool_instead() binary() const { return field_charset == &my_charset_bin; } + uint32 max_display_length() { return field_length; } + friend class Create_field; + my_decimal *val_decimal(my_decimal *); + virtual In_C_you_should_use_my_bool_instead() str_needs_quotes() { return (1); } + In_C_you_should_use_my_bool_instead() compare_str_field_flags(Create_field *new_field, uint32 flags); + uint is_equal(Create_field *new_field); +}; +class Field_longstr :public Field_str +{ +protected: + int report_if_important_data(const char *ptr, const char *end, + In_C_you_should_use_my_bool_instead() count_spaces); +public: + Field_longstr(uchar *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_arg) + :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, charset_arg) + {} + int store_decimal(const my_decimal *d); + uint32 max_data_length() const; +}; +class Field_real :public Field_num { +public: + my_bool not_fixed; + Field_real(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + uint8 dec_arg, In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, dec_arg, zero_arg, unsigned_arg), + not_fixed(dec_arg >= 31) + {} + int store_decimal(const my_decimal *); + my_decimal *val_decimal(my_decimal *); + int truncate(double *nr, double max_length); + uint32 max_display_length() { return field_length; } + uint size_of() const { return sizeof(*this); } + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first); + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first); +}; +class Field_decimal :public Field_real { +public: + Field_decimal(uchar *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,In_C_you_should_use_my_bool_instead() zero_arg,In_C_you_should_use_my_bool_instead() 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) + {} + enum_field_types type() const { return MYSQL_TYPE_DECIMAL;} + enum ha_base_keytype key_type() const + { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } + int reset(void); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + void overflow(In_C_you_should_use_my_bool_instead() negative); + In_C_you_should_use_my_bool_instead() zero_pack() const { return 0; } + void sql_type(String &str) const; + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first) + { + return Field::unpack(to, from, param_data, low_byte_first); + } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first) + { + return Field::pack(to, from, max_length, low_byte_first); + } +}; +class Field_new_decimal :public Field_num { +private: + int do_save_field_metadata(uchar *first_byte); +public: + uint precision; + uint bin_size; + Field_new_decimal(uchar *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, In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg); + Field_new_decimal(uint32 len_arg, In_C_you_should_use_my_bool_instead() maybe_null_arg, + const char *field_name_arg, uint8 dec_arg, + In_C_you_should_use_my_bool_instead() unsigned_arg); + enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + Item_result result_type () const { return DECIMAL_RESULT; } + int reset(void); + In_C_you_should_use_my_bool_instead() store_value(const my_decimal *decimal_value); + void set_value_on_overflow(my_decimal *decimal_value, In_C_you_should_use_my_bool_instead() sign); + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int store_time(MYSQL_TIME *ltime, timestamp_type t_type); + int store_decimal(const my_decimal *); + double val_real(void); + longlong val_int(void); + my_decimal *val_decimal(my_decimal *); + String *val_str(String*, String *); + int cmp(const uchar *, const uchar *); + void sort_string(uchar *buff, uint length); + In_C_you_should_use_my_bool_instead() zero_pack() const { return 0; } + void sql_type(String &str) const; + uint32 max_display_length() { return field_length; } + uint size_of() const { return sizeof(*this); } + uint32 pack_length() const { return (uint32) bin_size; } + uint pack_length_from_metadata(uint field_metadata); + uint row_pack_length() { return pack_length(); } + int compatible_field_size(uint field_metadata); + uint is_equal(Create_field *new_field); + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first); +}; +class Field_tiny :public Field_num { +public: + Field_tiny(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + enum Item_result result_type () const { return INT_RESULT; } + enum_field_types type() const { return MYSQL_TYPE_TINY;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int reset(void) { ptr[0]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 1; } + void sql_type(String &str) const; + uint32 max_display_length() { return 4; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first) + { + *to= *from; + return to + 1; + } + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first) + { + *to= *from; + return from + 1; + } +}; +class Field_short :public Field_num { +public: + Field_short(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + Field_short(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + In_C_you_should_use_my_bool_instead() unsigned_arg) + :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, 0, 0, unsigned_arg) + {} + enum Item_result result_type () const { return INT_RESULT; } + enum_field_types type() const { return MYSQL_TYPE_SHORT;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;} + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int reset(void) { ptr[0]=ptr[1]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 2; } + void sql_type(String &str) const; + uint32 max_display_length() { return 6; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first) + { + int16 val; + do { val = (*((int16 *) (from))); } while(0); + *((uint16*) (to))= (uint16) (val); + return to + sizeof(val); + } + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first) + { + int16 val; + do { val = (*((int16 *) (from))); } while(0); + *((uint16*) (to))= (uint16) (val); + return from + sizeof(val); + } +}; +class Field_medium :public Field_num { +public: + Field_medium(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + enum Item_result result_type () const { return INT_RESULT; } + enum_field_types type() const { return MYSQL_TYPE_INT24;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 3; } + void sql_type(String &str) const; + uint32 max_display_length() { return 8; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first) + { + return Field::pack(to, from, max_length, low_byte_first); + } + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first) + { + return Field::unpack(to, from, param_data, low_byte_first); + } +}; +class Field_long :public Field_num { +public: + Field_long(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + Field_long(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + In_C_you_should_use_my_bool_instead() unsigned_arg) + :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg,0,0,unsigned_arg) + {} + enum Item_result result_type () const { return INT_RESULT; } + enum_field_types type() const { return MYSQL_TYPE_LONG;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } + double val_real(void); + longlong val_int(void); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + String *val_str(String*,String *); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 4; } + void sql_type(String &str) const; + uint32 max_display_length() { return 11; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first) + { + int32 val; + do { val = (*((long *) (from))); } while(0); + *((long *) (to))= (long) (val); + return to + sizeof(val); + } + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first) + { + int32 val; + do { val = (*((long *) (from))); } while(0); + *((long *) (to))= (long) (val); + return from + sizeof(val); + } +}; +class Field_longlong :public Field_num { +public: + Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + In_C_you_should_use_my_bool_instead() zero_arg, In_C_you_should_use_my_bool_instead() unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + Field_longlong(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, + const char *field_name_arg, + In_C_you_should_use_my_bool_instead() unsigned_arg) + :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg,0,0,unsigned_arg) + {} + enum Item_result result_type () const { return INT_RESULT; } + enum_field_types type() const { return MYSQL_TYPE_LONGLONG;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int reset(void) + { + ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; + return 0; + } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 8; } + void sql_type(String &str) const; + In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); } + uint32 max_display_length() { return 20; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first) + { + int64 val; + memcpy(((uchar*) &val),((uchar*) (from)),(sizeof(ulonglong))); + memcpy(((uchar*) (to)),((uchar*) &val),(sizeof(ulonglong))); + return to + sizeof(val); + } + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first) + { + int64 val; + memcpy(((uchar*) &val),((uchar*) (from)),(sizeof(ulonglong))); + memcpy(((uchar*) (to)),((uchar*) &val),(sizeof(ulonglong))); + return from + sizeof(val); + } +}; +class Field_float :public Field_real { +public: + Field_float(uchar *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,In_C_you_should_use_my_bool_instead() zero_arg,In_C_you_should_use_my_bool_instead() 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) + {} + Field_float(uint32 len_arg, In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + uint8 dec_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0) + {} + enum_field_types type() const { return MYSQL_TYPE_FLOAT;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int reset(void) { bzero(ptr,sizeof(float)); return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return sizeof(float); } + uint row_pack_length() { return pack_length(); } + void sql_type(String &str) const; +private: + int do_save_field_metadata(uchar *first_byte); +}; +class Field_double :public Field_real { +public: + Field_double(uchar *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,In_C_you_should_use_my_bool_instead() zero_arg,In_C_you_should_use_my_bool_instead() 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) + {} + Field_double(uint32 len_arg, In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + uint8 dec_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0) + {} + Field_double(uint32 len_arg, In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + uint8 dec_arg, my_bool not_fixed_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0) + {not_fixed= not_fixed_arg; } + enum_field_types type() const { return MYSQL_TYPE_DOUBLE;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int reset(void) { bzero(ptr,sizeof(double)); return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return sizeof(double); } + uint row_pack_length() { return pack_length(); } + void sql_type(String &str) const; +private: + int do_save_field_metadata(uchar *first_byte); +}; +class Field_null :public Field_str { + static uchar null[1]; +public: + Field_null(uchar *ptr_arg, uint32 len_arg, + enum utype unireg_check_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_str(ptr_arg, len_arg, null, 1, + unireg_check_arg, field_name_arg, cs) + {} + enum_field_types type() const { return MYSQL_TYPE_NULL;} + int store(const char *to, uint length, CHARSET_INFO *cs) + { null[0]=1; return 0; } + int store(double nr) { null[0]=1; return 0; } + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val) { null[0]=1; return 0; } + int store_decimal(const my_decimal *d) { null[0]=1; return 0; } + int reset(void) { return 0; } + double val_real(void) { return 0.0;} + longlong val_int(void) { return 0;} + my_decimal *val_decimal(my_decimal *) { return 0; } + String *val_str(String *value,String *value2) + { value2->length(0); return value2;} + int cmp(const uchar *a, const uchar *b) { return 0;} + void sort_string(uchar *buff, uint length) {} + uint32 pack_length() const { return 0; } + void sql_type(String &str) const; + uint size_of() const { return sizeof(*this); } + uint32 max_display_length() { return 4; } +}; +class Field_timestamp :public Field_str { +public: + Field_timestamp(uchar *ptr_arg, uint32 len_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + TABLE_SHARE *share, CHARSET_INFO *cs); + Field_timestamp(In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs); + enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } + enum Item_result cmp_type () const { return INT_RESULT; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 4; } + void sql_type(String &str) const; + In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); } + In_C_you_should_use_my_bool_instead() zero_pack() const { return 0; } + void set_time(); + virtual void set_default() + { + if (table->timestamp_field == this && + unireg_check != TIMESTAMP_UN_FIELD) + set_time(); + else + Field::set_default(); + } + inline long get_timestamp(my_bool *null_value) + { + if ((*null_value= is_null())) + return 0; + long tmp; + do { tmp = (*((long *) (ptr))); } while(0); + return tmp; + } + inline void store_timestamp(my_time_t timestamp) + { + *((long *) (ptr))= (long) ((uint32) timestamp); + } + In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate); + In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime); + timestamp_auto_set_type get_auto_set_type() const; +}; +class Field_year :public Field_tiny { +public: + Field_year(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg) + :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, 1, 1) + {} + enum_field_types type() const { return MYSQL_TYPE_YEAR;} + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + void sql_type(String &str) const; + In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); } +}; +class Field_date :public Field_str { +public: + Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, cs) + {} + Field_date(In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_str((uchar*) 0,10, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, cs) {} + enum_field_types type() const { return MYSQL_TYPE_DATE;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } + enum Item_result cmp_type () const { return INT_RESULT; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 4; } + void sql_type(String &str) const; + In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); } + In_C_you_should_use_my_bool_instead() zero_pack() const { return 1; } +}; +class Field_newdate :public Field_str { +public: + Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, cs) + {} + Field_newdate(In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_str((uchar*) 0,10, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, cs) {} + enum_field_types type() const { return MYSQL_TYPE_DATE;} + enum_field_types real_type() const { return MYSQL_TYPE_NEWDATE; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; } + enum Item_result cmp_type () const { return INT_RESULT; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int store_time(MYSQL_TIME *ltime, timestamp_type type); + int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 3; } + void sql_type(String &str) const; + In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); } + In_C_you_should_use_my_bool_instead() zero_pack() const { return 1; } + In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate); + In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime); +}; +class Field_time :public Field_str { +public: + Field_time(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_str(ptr_arg, 8, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, cs) + {} + Field_time(In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_str((uchar*) 0,8, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, cs) {} + enum_field_types type() const { return MYSQL_TYPE_TIME;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; } + enum Item_result cmp_type () const { return INT_RESULT; } + int store_time(MYSQL_TIME *ltime, timestamp_type type); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime, uint fuzzydate); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 3; } + void sql_type(String &str) const; + In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); } + In_C_you_should_use_my_bool_instead() zero_pack() const { return 1; } +}; +class Field_datetime :public Field_str { +public: + Field_datetime(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, cs) + {} + Field_datetime(In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_str((uchar*) 0,19, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, cs) {} + enum_field_types type() const { return MYSQL_TYPE_DATETIME;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; } + enum Item_result cmp_type () const { return INT_RESULT; } + uint decimals() const { return 6; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int store_time(MYSQL_TIME *ltime, timestamp_type type); + int reset(void) + { + ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; + return 0; + } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + In_C_you_should_use_my_bool_instead() send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 8; } + void sql_type(String &str) const; + In_C_you_should_use_my_bool_instead() can_be_compared_as_longlong() const { return (1); } + In_C_you_should_use_my_bool_instead() zero_pack() const { return 1; } + In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate); + In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime); +}; +class Field_string :public Field_longstr { +public: + In_C_you_should_use_my_bool_instead() can_alter_field_type; + Field_string(uchar *ptr_arg, uint32 len_arg,uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, cs), + can_alter_field_type(1) {}; + Field_string(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, cs), + can_alter_field_type(1) {}; + enum_field_types type() const + { + return ((can_alter_field_type && orig_table && + orig_table->s->db_create_options & 1 && + field_length >= 4) && + orig_table->s->frm_version < (6 +4) ? + MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING); + } + enum ha_base_keytype key_type() const + { return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; } + In_C_you_should_use_my_bool_instead() zero_pack() const { return 0; } + int reset(void) + { + charset()->cset->fill(charset(),(char*) ptr, field_length, + (has_charset() ? ' ' : 0)); + return 0; + } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int store(double nr) { return Field_str::store(nr); } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + my_decimal *val_decimal(my_decimal *); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + void sql_type(String &str) const; + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first); + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first); + uint pack_length_from_metadata(uint field_metadata) + { return (field_metadata & 0x00ff); } + uint row_pack_length() { return (field_length + 1); } + int pack_cmp(const uchar *a,const uchar *b,uint key_length, + my_bool insert_or_update); + int pack_cmp(const uchar *b,uint key_length,my_bool insert_or_update); + uint packed_col_length(const uchar *to, uint length); + uint max_packed_col_length(uint max_length); + uint size_of() const { return sizeof(*this); } + enum_field_types real_type() const { return MYSQL_TYPE_STRING; } + In_C_you_should_use_my_bool_instead() has_charset(void) const + { return charset() == &my_charset_bin ? (0) : (1); } + Field *new_field(MEM_ROOT *root, struct st_table *new_table, In_C_you_should_use_my_bool_instead() keep_type); + virtual uint get_key_image(uchar *buff,uint length, imagetype type); +private: + int do_save_field_metadata(uchar *first_byte); +}; +class Field_varstring :public Field_longstr { +public: + static const uint MAX_SIZE; + uint32 length_bytes; + Field_varstring(uchar *ptr_arg, + uint32 len_arg, uint length_bytes_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + TABLE_SHARE *share, CHARSET_INFO *cs) + :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, cs), + length_bytes(length_bytes_arg) + { + share->varchar_fields++; + } + Field_varstring(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, + const char *field_name_arg, + TABLE_SHARE *share, CHARSET_INFO *cs) + :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, cs), + length_bytes(len_arg < 256 ? 1 :2) + { + share->varchar_fields++; + } + enum_field_types type() const { return MYSQL_TYPE_VARCHAR; } + enum ha_base_keytype key_type() const; + uint row_pack_length() { return field_length; } + In_C_you_should_use_my_bool_instead() zero_pack() const { return 0; } + int reset(void) { bzero(ptr,field_length+length_bytes); return 0; } + uint32 pack_length() const { return (uint32) field_length+length_bytes; } + uint32 key_length() const { return (uint32) field_length; } + uint32 sort_length() const + { + return (uint32) field_length + (field_charset == &my_charset_bin ? + length_bytes : 0); + } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int store(double nr) { return Field_str::store(nr); } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + my_decimal *val_decimal(my_decimal *); + int cmp_max(const uchar *, const uchar *, uint max_length); + int cmp(const uchar *a,const uchar *b) + { + return cmp_max(a, b, ~0L); + } + void sort_string(uchar *buff,uint length); + uint get_key_image(uchar *buff,uint length, imagetype type); + void set_key_image(const uchar *buff,uint length); + void sql_type(String &str) const; + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first); + uchar *pack_key(uchar *to, const uchar *from, uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first); + uchar *pack_key_from_key_image(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first); + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first); + const uchar *unpack_key(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first); + int pack_cmp(const uchar *a, const uchar *b, uint key_length, + my_bool insert_or_update); + int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update); + int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0L); + int key_cmp(const uchar *,const uchar*); + int key_cmp(const uchar *str, uint length); + uint packed_col_length(const uchar *to, uint length); + uint max_packed_col_length(uint max_length); + uint32 data_length(); + uint size_of() const { return sizeof(*this); } + enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; } + In_C_you_should_use_my_bool_instead() has_charset(void) const + { return charset() == &my_charset_bin ? (0) : (1); } + Field *new_field(MEM_ROOT *root, struct st_table *new_table, In_C_you_should_use_my_bool_instead() keep_type); + Field *new_key_field(MEM_ROOT *root, struct st_table *new_table, + uchar *new_ptr, uchar *new_null_ptr, + uint new_null_bit); + uint is_equal(Create_field *new_field); + void hash(ulong *nr, ulong *nr2); +private: + int do_save_field_metadata(uchar *first_byte); +}; +class Field_blob :public Field_longstr { +protected: + uint packlength; + String value; +public: + Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + TABLE_SHARE *share, uint blob_pack_length, CHARSET_INFO *cs); + Field_blob(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, cs), + packlength(4) + { + flags|= 16; + } + Field_blob(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs, In_C_you_should_use_my_bool_instead() set_packlength) + :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, cs) + { + flags|= 16; + packlength= 4; + if (set_packlength) + { + 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; + } + } + Field_blob(uint32 packlength_arg) + :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, "temp", system_charset_info), + packlength(packlength_arg) {} + enum_field_types type() const { return MYSQL_TYPE_BLOB;} + enum ha_base_keytype key_type() const + { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + my_decimal *val_decimal(my_decimal *); + int cmp_max(const uchar *, const uchar *, uint max_length); + int cmp(const uchar *a,const uchar *b) + { return cmp_max(a, b, ~0L); } + int cmp(const uchar *a, uint32 a_length, const uchar *b, uint32 b_length); + int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0L); + int key_cmp(const uchar *,const uchar*); + int key_cmp(const uchar *str, uint length); + uint32 key_length() const { return 0; } + void sort_string(uchar *buff,uint length); + uint32 pack_length() const + { return (uint32) (packlength+table->s->blob_ptr_size); } + uint32 pack_length_no_ptr() const + { return (uint32) (packlength); } + uint row_pack_length() { return pack_length_no_ptr(); } + uint32 sort_length() const; + virtual uint32 max_data_length() const + { + return (uint32) (((ulonglong) 1 << (packlength*8)) -1); + } + int reset(void) { bzero(ptr, packlength+sizeof(uchar*)); return 0; } + void reset_fields() { bzero((uchar*) &value,sizeof(value)); } + static + void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number, In_C_you_should_use_my_bool_instead() low_byte_first); + void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number) + { + store_length(i_ptr, i_packlength, i_number, table->s->db_low_byte_first); + } + inline void store_length(uint32 number) + { + store_length(ptr, packlength, number); + } + uint32 get_packed_size(const uchar *ptr_arg, In_C_you_should_use_my_bool_instead() low_byte_first) + {return packlength + get_length(ptr_arg, packlength, low_byte_first);} + inline uint32 get_length(uint row_offset= 0) + { return get_length(ptr+row_offset, this->packlength, table->s->db_low_byte_first); } + uint32 get_length(const uchar *ptr, uint packlength, In_C_you_should_use_my_bool_instead() low_byte_first); + uint32 get_length(const uchar *ptr_arg) + { return get_length(ptr_arg, this->packlength, table->s->db_low_byte_first); } + void put_length(uchar *pos, uint32 length); + inline void get_ptr(uchar **str) + { + memcpy(((uchar*) str),(ptr+packlength),(sizeof(uchar*))); + } + inline void get_ptr(uchar **str, uint row_offset) + { + memcpy(((uchar*) str),(ptr+packlength+row_offset),(sizeof(char*))); + } + inline void set_ptr(uchar *length, uchar *data) + { + memcpy(ptr,length,packlength); + memcpy((ptr+packlength),(&data),(sizeof(char*))); + } + void set_ptr_offset(my_ptrdiff_t ptr_diff, uint32 length, uchar *data) + { + uchar *ptr_ofs= (uchar*) ((uchar*) (ptr)+ptr_diff); + store_length(ptr_ofs, packlength, length); + memcpy((ptr_ofs+packlength),(&data),(sizeof(char*))); + } + inline void set_ptr(uint32 length, uchar *data) + { + set_ptr_offset(0, length, data); + } + uint get_key_image(uchar *buff,uint length, imagetype type); + void set_key_image(const uchar *buff,uint length); + void sql_type(String &str) const; + inline In_C_you_should_use_my_bool_instead() copy() + { + uchar *tmp; + get_ptr(&tmp); + if (value.copy((char*) tmp, get_length(), charset())) + { + Field_blob::reset(); + return 1; + } + tmp=(uchar*) value.ptr(); + memcpy((ptr+packlength),(&tmp),(sizeof(char*))); + return 0; + } + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first); + uchar *pack_key(uchar *to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first); + uchar *pack_key_from_key_image(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first); + virtual const uchar *unpack(uchar *to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first); + const uchar *unpack_key(uchar* to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first); + int pack_cmp(const uchar *a, const uchar *b, uint key_length, + my_bool insert_or_update); + int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update); + uint packed_col_length(const uchar *col_ptr, uint length); + uint max_packed_col_length(uint max_length); + void free() { value.free(); } + inline void clear_temporary() { bzero((uchar*) &value,sizeof(value)); } + friend int field_conv(Field *to,Field *from); + uint size_of() const { return sizeof(*this); } + In_C_you_should_use_my_bool_instead() has_charset(void) const + { return charset() == &my_charset_bin ? (0) : (1); } + uint32 max_display_length(); + uint is_equal(Create_field *new_field); + inline In_C_you_should_use_my_bool_instead() in_read_set() { return bitmap_is_set(table->read_set, field_index); } + inline In_C_you_should_use_my_bool_instead() in_write_set() { return bitmap_is_set(table->write_set, field_index); } +private: + int do_save_field_metadata(uchar *first_byte); +}; +class Field_geom :public Field_blob { +public: + enum geometry_type geom_type; + Field_geom(uchar *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + TABLE_SHARE *share, uint blob_pack_length, + enum geometry_type geom_type_arg) + :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, share, blob_pack_length, &my_charset_bin) + { geom_type= geom_type_arg; } + Field_geom(uint32 len_arg,In_C_you_should_use_my_bool_instead() maybe_null_arg, const char *field_name_arg, + TABLE_SHARE *share, enum geometry_type geom_type_arg) + :Field_blob(len_arg, maybe_null_arg, field_name_arg, &my_charset_bin) + { geom_type= geom_type_arg; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; } + enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; } + void sql_type(String &str) const; + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int store_decimal(const my_decimal *); + uint size_of() const { return sizeof(*this); } + int reset(void) { return !maybe_null() || Field_blob::reset(); } + geometry_type get_geometry_type() { return geom_type; }; +}; +class Field_enum :public Field_str { +protected: + uint packlength; +public: + TYPELIB *typelib; + Field_enum(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint packlength_arg, + TYPELIB *typelib_arg, + CHARSET_INFO *charset_arg) + :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, charset_arg), + packlength(packlength_arg),typelib(typelib_arg) + { + flags|=256; + } + Field *new_field(MEM_ROOT *root, struct st_table *new_table, In_C_you_should_use_my_bool_instead() keep_type); + enum_field_types type() const { return MYSQL_TYPE_STRING; } + enum Item_result cmp_type () const { return INT_RESULT; } + enum Item_result cast_to_int_type () const { return INT_RESULT; } + enum ha_base_keytype key_type() const; + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return (uint32) packlength; } + void store_type(ulonglong value); + void sql_type(String &str) const; + uint size_of() const { return sizeof(*this); } + enum_field_types real_type() const { return MYSQL_TYPE_ENUM; } + uint pack_length_from_metadata(uint field_metadata) + { return (field_metadata & 0x00ff); } + uint row_pack_length() { return pack_length(); } + virtual In_C_you_should_use_my_bool_instead() zero_pack() const { return 0; } + In_C_you_should_use_my_bool_instead() optimize_range(uint idx, uint part) { return 0; } + In_C_you_should_use_my_bool_instead() eq_def(Field *field); + In_C_you_should_use_my_bool_instead() has_charset(void) const { return (1); } + CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } +private: + int do_save_field_metadata(uchar *first_byte); +}; +class Field_set :public Field_enum { +public: + Field_set(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint32 packlength_arg, + TYPELIB *typelib_arg, CHARSET_INFO *charset_arg) + :Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + packlength_arg, + typelib_arg,charset_arg) + { + flags=(flags & ~256) | 2048; + } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr) { return Field_set::store((longlong) nr, (0)); } + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + virtual In_C_you_should_use_my_bool_instead() zero_pack() const { return 1; } + String *val_str(String*,String *); + void sql_type(String &str) const; + enum_field_types real_type() const { return MYSQL_TYPE_SET; } + In_C_you_should_use_my_bool_instead() has_charset(void) const { return (1); } +}; +class Field_bit :public Field { +public: + uchar *bit_ptr; + uchar bit_ofs; + uint bit_len; + uint bytes_in_rec; + Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg, + enum utype unireg_check_arg, const char *field_name_arg); + 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_data_length() const { return (field_length + 7) / 8; } + 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; } + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val); + int store_decimal(const my_decimal *); + double val_real(void); + longlong val_int(void); + String *val_str(String*, String *); + virtual In_C_you_should_use_my_bool_instead() str_needs_quotes() { return (1); } + my_decimal *val_decimal(my_decimal *); + int cmp(const uchar *a, const uchar *b) + { + assert(ptr == a); + return Field_bit::key_cmp(b, bytes_in_rec+((bit_len) ? 1 : 0)); + } + int cmp_binary_offset(uint row_offset) + { return cmp_offset(row_offset); } + int cmp_max(const uchar *a, const uchar *b, uint max_length); + int key_cmp(const uchar *a, const uchar *b) + { return cmp_binary((uchar *) a, (uchar *) b); } + int key_cmp(const uchar *str, uint length); + int cmp_offset(uint row_offset); + void get_image(uchar *buff, uint length, CHARSET_INFO *cs) + { get_key_image(buff, length, itRAW); } + void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) + { Field_bit::store((char *) buff, length, cs); } + uint get_key_image(uchar *buff, uint length, imagetype type); + void set_key_image(const uchar *buff, uint length) + { Field_bit::store((char*) buff, length, &my_charset_bin); } + void sort_string(uchar *buff, uint length) + { get_key_image(buff, length, itRAW); } + uint32 pack_length() const { return (uint32) (field_length + 7) / 8; } + uint32 pack_length_in_rec() const { return bytes_in_rec; } + uint pack_length_from_metadata(uint field_metadata); + uint row_pack_length() + { return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); } + int compatible_field_size(uint field_metadata); + void sql_type(String &str) const; + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, In_C_you_should_use_my_bool_instead() low_byte_first); + virtual const uchar *unpack(uchar *to, const uchar *from, + uint param_data, In_C_you_should_use_my_bool_instead() low_byte_first); + virtual void set_default(); + Field *new_key_field(MEM_ROOT *root, struct st_table *new_table, + uchar *new_ptr, uchar *new_null_ptr, + uint new_null_bit); + void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg) + { + bit_ptr= bit_ptr_arg; + bit_ofs= bit_ofs_arg; + } + In_C_you_should_use_my_bool_instead() eq(Field *field) + { + return (Field::eq(field) && + field->type() == type() && + bit_ptr == ((Field_bit *)field)->bit_ptr && + bit_ofs == ((Field_bit *)field)->bit_ofs); + } + uint is_equal(Create_field *new_field); + void move_field_offset(my_ptrdiff_t ptr_diff) + { + Field::move_field_offset(ptr_diff); + bit_ptr= (uchar*) ((uchar*) (bit_ptr)+ptr_diff); + } + void hash(ulong *nr, ulong *nr2); +private: + virtual size_t do_last_null_byte() const; + int do_save_field_metadata(uchar *first_byte); +}; +class Field_bit_as_char: public Field_bit { +public: + Field_bit_as_char(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg); + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + uint size_of() const { return sizeof(*this); } + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr) { return Field_bit::store(nr); } + int store(longlong nr, In_C_you_should_use_my_bool_instead() unsigned_val) + { return Field_bit::store(nr, unsigned_val); } + void sql_type(String &str) const; +}; +class Create_field :public Sql_alloc +{ +public: + const char *field_name; + const char *change; + const char *after; + LEX_STRING comment; + Item *def; + enum enum_field_types sql_type; + ulong length; + uint32 char_length; + uint decimals, flags, pack_length, key_length; + Field::utype unireg_check; + TYPELIB *interval; + TYPELIB *save_interval; + List<String> interval_list; + CHARSET_INFO *charset; + Field::geometry_type geom_type; + Field *field; + uint8 row,col,sc_length,interval_id; + uint offset,pack_flag; + Create_field() :after(0) {} + Create_field(Field *field, Field *orig_field); + Create_field *clone(MEM_ROOT *mem_root) const + { return new (mem_root) Create_field(*this); } + void create_length_to_internal_length(void); + void init_for_tmp_table(enum_field_types sql_type_arg, + uint32 max_length, uint32 decimals, + In_C_you_should_use_my_bool_instead() maybe_null, In_C_you_should_use_my_bool_instead() is_unsigned); + In_C_you_should_use_my_bool_instead() init(THD *thd, char *field_name, enum_field_types type, char *length, + char *decimals, uint type_modifier, Item *default_value, + Item *on_update_value, LEX_STRING *comment, char *change, + List<String> *interval_list, CHARSET_INFO *cs, + uint uint_geom_type); +}; +class Send_field { + public: + const char *db_name; + const char *table_name,*org_table_name; + const char *col_name,*org_col_name; + ulong length; + uint charsetnr, flags, decimals; + enum_field_types type; + Send_field() {} +}; +class Copy_field :public Sql_alloc { + typedef void Copy_func(Copy_field*); + Copy_func *get_copy_func(Field *to, Field *from); +public: + uchar *from_ptr,*to_ptr; + uchar *from_null_ptr,*to_null_ptr; + my_bool *null_row; + uint from_bit,to_bit; + uint from_length,to_length; + Field *from_field,*to_field; + String tmp; + Copy_field() {} + ~Copy_field() {} + void set(Field *to,Field *from,In_C_you_should_use_my_bool_instead() save); + void set(uchar *to,Field *from); + void (*do_copy)(Copy_field *); + void (*do_copy2)(Copy_field *); +}; +Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length, + uchar *null_pos, uchar null_bit, + uint pack_flag, enum_field_types field_type, + CHARSET_INFO *cs, + Field::geometry_type geom_type, + Field::utype unireg_check, + TYPELIB *interval, const char *field_name); +uint pack_length_to_packflag(uint type); +enum_field_types get_blob_type_from_length(ulong length); +uint32 calc_pack_length(enum_field_types type,uint32 length); +int set_field_to_null(Field *field); +int set_field_to_null_with_conversions(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); +#include "protocol.h" +class i_string; +class THD; +typedef struct st_mysql_field MYSQL_FIELD; +typedef struct st_mysql_rows MYSQL_ROWS; +class Protocol +{ +protected: + THD *thd; + String *packet; + String *convert; + uint field_pos; + enum enum_field_types *field_types; + uint field_count; + In_C_you_should_use_my_bool_instead() net_store_data(const uchar *from, size_t length); + In_C_you_should_use_my_bool_instead() store_string_aux(const char *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); +public: + Protocol() {} + Protocol(THD *thd_arg) { init(thd_arg); } + virtual ~Protocol() {} + void init(THD* thd_arg); + enum { SEND_NUM_ROWS= 1, SEND_DEFAULTS= 2, SEND_EOF= 4 }; + virtual In_C_you_should_use_my_bool_instead() send_fields(List<Item> *list, uint flags); + In_C_you_should_use_my_bool_instead() store(I_List<i_string> *str_list); + In_C_you_should_use_my_bool_instead() store(const char *from, CHARSET_INFO *cs); + String *storage_packet() { return packet; } + inline void free() { packet->free(); } + virtual In_C_you_should_use_my_bool_instead() write(); + inline In_C_you_should_use_my_bool_instead() store(int from) + { return store_long((longlong) from); } + inline In_C_you_should_use_my_bool_instead() store(uint32 from) + { return store_long((longlong) from); } + inline In_C_you_should_use_my_bool_instead() store(longlong from) + { return store_longlong((longlong) from, 0); } + inline In_C_you_should_use_my_bool_instead() store(ulonglong from) + { return store_longlong((longlong) from, 1); } + inline In_C_you_should_use_my_bool_instead() store(String *str) + { return store((char*) str->ptr(), str->length(), str->charset()); } + virtual In_C_you_should_use_my_bool_instead() prepare_for_send(List<Item> *item_list) + { + field_count=item_list->elements; + return 0; + } + virtual In_C_you_should_use_my_bool_instead() flush(); + virtual void end_partial_result_set(THD *thd); + virtual void prepare_for_resend()=0; + virtual In_C_you_should_use_my_bool_instead() store_null()=0; + virtual In_C_you_should_use_my_bool_instead() store_tiny(longlong from)=0; + virtual In_C_you_should_use_my_bool_instead() store_short(longlong from)=0; + virtual In_C_you_should_use_my_bool_instead() store_long(longlong from)=0; + virtual In_C_you_should_use_my_bool_instead() store_longlong(longlong from, In_C_you_should_use_my_bool_instead() unsigned_flag)=0; + virtual In_C_you_should_use_my_bool_instead() store_decimal(const my_decimal *)=0; + virtual In_C_you_should_use_my_bool_instead() store(const char *from, size_t length, CHARSET_INFO *cs)=0; + virtual In_C_you_should_use_my_bool_instead() store(const char *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0; + virtual In_C_you_should_use_my_bool_instead() store(float from, uint32 decimals, String *buffer)=0; + virtual In_C_you_should_use_my_bool_instead() store(double from, uint32 decimals, String *buffer)=0; + virtual In_C_you_should_use_my_bool_instead() store(MYSQL_TIME *time)=0; + virtual In_C_you_should_use_my_bool_instead() store_date(MYSQL_TIME *time)=0; + virtual In_C_you_should_use_my_bool_instead() store_time(MYSQL_TIME *time)=0; + virtual In_C_you_should_use_my_bool_instead() store(Field *field)=0; + void remove_last_row() {} + enum enum_protocol_type + { + PROTOCOL_TEXT= 0, PROTOCOL_BINARY= 1 + }; + virtual enum enum_protocol_type type()= 0; +}; +class Protocol_text :public Protocol +{ +public: + Protocol_text() {} + Protocol_text(THD *thd_arg) :Protocol(thd_arg) {} + virtual void prepare_for_resend(); + virtual In_C_you_should_use_my_bool_instead() store_null(); + virtual In_C_you_should_use_my_bool_instead() store_tiny(longlong from); + virtual In_C_you_should_use_my_bool_instead() store_short(longlong from); + virtual In_C_you_should_use_my_bool_instead() store_long(longlong from); + virtual In_C_you_should_use_my_bool_instead() store_longlong(longlong from, In_C_you_should_use_my_bool_instead() unsigned_flag); + virtual In_C_you_should_use_my_bool_instead() store_decimal(const my_decimal *); + virtual In_C_you_should_use_my_bool_instead() store(const char *from, size_t length, CHARSET_INFO *cs); + virtual In_C_you_should_use_my_bool_instead() store(const char *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); + virtual In_C_you_should_use_my_bool_instead() store(MYSQL_TIME *time); + virtual In_C_you_should_use_my_bool_instead() store_date(MYSQL_TIME *time); + virtual In_C_you_should_use_my_bool_instead() store_time(MYSQL_TIME *time); + virtual In_C_you_should_use_my_bool_instead() store(float nr, uint32 decimals, String *buffer); + virtual In_C_you_should_use_my_bool_instead() store(double from, uint32 decimals, String *buffer); + virtual In_C_you_should_use_my_bool_instead() store(Field *field); + virtual enum enum_protocol_type type() { return PROTOCOL_TEXT; }; +}; +class Protocol_binary :public Protocol +{ +private: + uint bit_fields; +public: + Protocol_binary() {} + Protocol_binary(THD *thd_arg) :Protocol(thd_arg) {} + virtual In_C_you_should_use_my_bool_instead() prepare_for_send(List<Item> *item_list); + virtual void prepare_for_resend(); + virtual In_C_you_should_use_my_bool_instead() store_null(); + virtual In_C_you_should_use_my_bool_instead() store_tiny(longlong from); + virtual In_C_you_should_use_my_bool_instead() store_short(longlong from); + virtual In_C_you_should_use_my_bool_instead() store_long(longlong from); + virtual In_C_you_should_use_my_bool_instead() store_longlong(longlong from, In_C_you_should_use_my_bool_instead() unsigned_flag); + virtual In_C_you_should_use_my_bool_instead() store_decimal(const my_decimal *); + virtual In_C_you_should_use_my_bool_instead() store(const char *from, size_t length, CHARSET_INFO *cs); + virtual In_C_you_should_use_my_bool_instead() store(const char *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); + virtual In_C_you_should_use_my_bool_instead() store(MYSQL_TIME *time); + virtual In_C_you_should_use_my_bool_instead() store_date(MYSQL_TIME *time); + virtual In_C_you_should_use_my_bool_instead() store_time(MYSQL_TIME *time); + virtual In_C_you_should_use_my_bool_instead() store(float nr, uint32 decimals, String *buffer); + virtual In_C_you_should_use_my_bool_instead() store(double from, uint32 decimals, String *buffer); + virtual In_C_you_should_use_my_bool_instead() store(Field *field); + virtual enum enum_protocol_type type() { return PROTOCOL_BINARY; }; +}; +void send_warning(THD *thd, uint sql_errno, const char *err=0); +void net_send_error(THD *thd, uint sql_errno=0, const char *err=0); +void net_end_statement(THD *thd); +In_C_you_should_use_my_bool_instead() send_old_password_request(THD *thd); +uchar *net_store_data(uchar *to,const uchar *from, size_t length); +uchar *net_store_data(uchar *to,int32 from); +uchar *net_store_data(uchar *to,longlong from); +#include "sql_udf.h" +enum Item_udftype {UDFTYPE_FUNCTION=1,UDFTYPE_AGGREGATE}; +typedef void (*Udf_func_clear)(UDF_INIT *, uchar *, uchar *); +typedef void (*Udf_func_add)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *); +typedef void (*Udf_func_deinit)(UDF_INIT*); +typedef my_bool (*Udf_func_init)(UDF_INIT *, UDF_ARGS *, char *); +typedef void (*Udf_func_any)(); +typedef double (*Udf_func_double)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *); +typedef longlong (*Udf_func_longlong)(UDF_INIT *, UDF_ARGS *, uchar *, + uchar *); +typedef struct st_udf_func +{ + LEX_STRING name; + Item_result returns; + Item_udftype type; + char *dl; + void *dlhandle; + Udf_func_any func; + Udf_func_init func_init; + Udf_func_deinit func_deinit; + Udf_func_clear func_clear; + Udf_func_add func_add; + ulong usage_count; +} udf_func; +class Item_result_field; +class udf_handler :public Sql_alloc +{ + protected: + udf_func *u_d; + String *buffers; + UDF_ARGS f_args; + UDF_INIT initid; + char *num_buffer; + uchar error, is_null; + In_C_you_should_use_my_bool_instead() initialized; + Item **args; + public: + table_map used_tables_cache; + In_C_you_should_use_my_bool_instead() const_item_cache; + In_C_you_should_use_my_bool_instead() not_original; + udf_handler(udf_func *udf_arg) :u_d(udf_arg), buffers(0), error(0), + is_null(0), initialized(0), not_original(0) + {} + ~udf_handler(); + const char *name() const { return u_d ? u_d->name.str : "?"; } + Item_result result_type () const + { return u_d ? u_d->returns : STRING_RESULT;} + In_C_you_should_use_my_bool_instead() get_arguments(); + In_C_you_should_use_my_bool_instead() fix_fields(THD *thd, Item_result_field *item, + uint arg_count, Item **args); + void cleanup(); + double val(my_bool *null_value) + { + is_null= 0; + if (get_arguments()) + { + *null_value=1; + return 0.0; + } + Udf_func_double func= (Udf_func_double) u_d->func; + double tmp=func(&initid, &f_args, &is_null, &error); + if (is_null || error) + { + *null_value=1; + return 0.0; + } + *null_value=0; + return tmp; + } + longlong val_int(my_bool *null_value) + { + is_null= 0; + if (get_arguments()) + { + *null_value=1; + return 0LL; + } + Udf_func_longlong func= (Udf_func_longlong) u_d->func; + longlong tmp=func(&initid, &f_args, &is_null, &error); + if (is_null || error) + { + *null_value=1; + return 0LL; + } + *null_value=0; + return tmp; + } + my_decimal *val_decimal(my_bool *null_value, my_decimal *dec_buf); + void clear() + { + is_null= 0; + Udf_func_clear func= u_d->func_clear; + func(&initid, &is_null, &error); + } + void add(my_bool *null_value) + { + if (get_arguments()) + { + *null_value=1; + return; + } + Udf_func_add func= u_d->func_add; + func(&initid, &f_args, &is_null, &error); + *null_value= (my_bool) (is_null || error); + } + String *val_str(String *str,String *save_str); +}; +void udf_init(void),udf_free(void); +udf_func *find_udf(const char *name, uint len=0,In_C_you_should_use_my_bool_instead() mark_used=0); +void free_udf(udf_func *udf); +int mysql_create_function(THD *thd,udf_func *udf); +int mysql_drop_function(THD *thd,const LEX_STRING *name); +#include "sql_profile.h" +extern ST_FIELD_INFO query_profile_statistics_info[]; +int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond); +int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table); +#include "sql_partition.h" +#pragma interface +typedef struct { + longlong list_value; + uint32 partition_id; +} LIST_PART_ENTRY; +typedef struct { + uint32 start_part; + uint32 end_part; +} part_id_range; +struct st_partition_iter; +In_C_you_should_use_my_bool_instead() is_partition_in_list(char *part_name, List<char> list_part_names); +char *are_partitions_in_table(partition_info *new_part_info, + partition_info *old_part_info); +In_C_you_should_use_my_bool_instead() check_reorganise_list(partition_info *new_part_info, + partition_info *old_part_info, + List<char> list_part_names); +handler *get_ha_partition(partition_info *part_info); +int get_parts_for_update(const uchar *old_data, uchar *new_data, + const uchar *rec0, partition_info *part_info, + uint32 *old_part_id, uint32 *new_part_id, + longlong *func_value); +int get_part_for_delete(const uchar *buf, const uchar *rec0, + partition_info *part_info, uint32 *part_id); +void prune_partition_set(const TABLE *table, part_id_range *part_spec); +In_C_you_should_use_my_bool_instead() check_partition_info(partition_info *part_info,handlerton **eng_type, + TABLE *table, handler *file, HA_CREATE_INFO *info); +void set_linear_hash_mask(partition_info *part_info, uint no_parts); +In_C_you_should_use_my_bool_instead() fix_partition_func(THD *thd, TABLE *table, In_C_you_should_use_my_bool_instead() create_table_ind); +char *generate_partition_syntax(partition_info *part_info, + uint *buf_length, In_C_you_should_use_my_bool_instead() use_sql_alloc, + In_C_you_should_use_my_bool_instead() show_partition_options); +In_C_you_should_use_my_bool_instead() partition_key_modified(TABLE *table, const MY_BITMAP *fields); +void get_partition_set(const TABLE *table, uchar *buf, const uint index, + const key_range *key_spec, + part_id_range *part_spec); +void get_full_part_id_from_key(const TABLE *table, uchar *buf, + KEY *key_info, + const key_range *key_spec, + part_id_range *part_spec); +In_C_you_should_use_my_bool_instead() mysql_unpack_partition(THD *thd, const char *part_buf, + uint part_info_len, + const char *part_state, uint part_state_len, + TABLE *table, In_C_you_should_use_my_bool_instead() is_create_table_ind, + handlerton *default_db_type, + In_C_you_should_use_my_bool_instead() *work_part_info_used); +void make_used_partitions_str(partition_info *part_info, String *parts_str); +uint32 get_list_array_idx_for_endpoint(partition_info *part_info, + In_C_you_should_use_my_bool_instead() left_endpoint, + In_C_you_should_use_my_bool_instead() include_endpoint); +uint32 get_partition_id_range_for_endpoint(partition_info *part_info, + In_C_you_should_use_my_bool_instead() left_endpoint, + In_C_you_should_use_my_bool_instead() include_endpoint); +In_C_you_should_use_my_bool_instead() fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, + In_C_you_should_use_my_bool_instead() is_sub_part, In_C_you_should_use_my_bool_instead() is_field_to_be_setup); +In_C_you_should_use_my_bool_instead() check_part_func_fields(Field **ptr, In_C_you_should_use_my_bool_instead() ok_with_charsets); +In_C_you_should_use_my_bool_instead() field_is_partition_charset(Field *field); +typedef uint32 (*partition_iter_func)(st_partition_iter* part_iter); +typedef struct st_partition_iter +{ + partition_iter_func get_next; + In_C_you_should_use_my_bool_instead() ret_null_part, ret_null_part_orig; + struct st_part_num_range + { + uint32 start; + uint32 cur; + uint32 end; + }; + struct st_field_value_range + { + longlong start; + longlong cur; + longlong end; + }; + union + { + struct st_part_num_range part_nums; + struct st_field_value_range field_vals; + }; + partition_info *part_info; +} PARTITION_ITERATOR; +typedef int (*get_partitions_in_range_iter)(partition_info *part_info, + In_C_you_should_use_my_bool_instead() is_subpart, + uchar *min_val, uchar *max_val, + uint flags, + PARTITION_ITERATOR *part_iter); +#include "partition_info.h" +#include "partition_element.h" +enum partition_type { + NOT_A_PARTITION= 0, + RANGE_PARTITION, + HASH_PARTITION, + LIST_PARTITION +}; +enum partition_state { + PART_NORMAL= 0, + PART_IS_DROPPED= 1, + PART_TO_BE_DROPPED= 2, + PART_TO_BE_ADDED= 3, + PART_TO_BE_REORGED= 4, + PART_REORGED_DROPPED= 5, + PART_CHANGED= 6, + PART_IS_CHANGED= 7, + PART_IS_ADDED= 8 +}; +typedef struct p_elem_val +{ + longlong value; + In_C_you_should_use_my_bool_instead() null_value; + In_C_you_should_use_my_bool_instead() unsigned_flag; +} part_elem_value; +struct st_ddl_log_memory_entry; +class partition_element :public Sql_alloc { +public: + List<partition_element> subpartitions; + List<part_elem_value> list_val_list; + ha_rows part_max_rows; + ha_rows part_min_rows; + longlong range_value; + char *partition_name; + char *tablespace_name; + struct st_ddl_log_memory_entry *log_entry; + char* part_comment; + char* data_file_name; + char* index_file_name; + handlerton *engine_type; + enum partition_state part_state; + uint16 nodegroup_id; + In_C_you_should_use_my_bool_instead() has_null_value; + In_C_you_should_use_my_bool_instead() signed_flag; + In_C_you_should_use_my_bool_instead() max_value; + partition_element() + : part_max_rows(0), part_min_rows(0), range_value(0), + partition_name(NULL), tablespace_name(NULL), + log_entry(NULL), part_comment(NULL), + data_file_name(NULL), index_file_name(NULL), + engine_type(NULL), part_state(PART_NORMAL), + nodegroup_id(65535), has_null_value((0)), + signed_flag((0)), max_value((0)) + { + } + partition_element(partition_element *part_elem) + : part_max_rows(part_elem->part_max_rows), + part_min_rows(part_elem->part_min_rows), + range_value(0), partition_name(NULL), + tablespace_name(part_elem->tablespace_name), + part_comment(part_elem->part_comment), + data_file_name(part_elem->data_file_name), + index_file_name(part_elem->index_file_name), + engine_type(part_elem->engine_type), + part_state(part_elem->part_state), + nodegroup_id(part_elem->nodegroup_id), + has_null_value((0)) + { + } + ~partition_element() {} +}; +class partition_info; +typedef int (*get_part_id_func)(partition_info *part_info, + uint32 *part_id, + longlong *func_value); +typedef uint32 (*get_subpart_id_func)(partition_info *part_info); +struct st_ddl_log_memory_entry; +class partition_info : public Sql_alloc +{ +public: + List<partition_element> partitions; + List<partition_element> temp_partitions; + List<char> part_field_list; + List<char> subpart_field_list; + get_part_id_func get_partition_id; + get_part_id_func get_part_partition_id; + get_subpart_id_func get_subpartition_id; + get_part_id_func get_partition_id_charset; + get_part_id_func get_part_partition_id_charset; + get_subpart_id_func get_subpartition_id_charset; + Field **part_field_array; + Field **subpart_field_array; + Field **part_charset_field_array; + Field **subpart_charset_field_array; + Field **full_part_field_array; + Field **full_part_charset_field_array; + MY_BITMAP full_part_field_set; + uchar **part_field_buffers; + uchar **subpart_field_buffers; + uchar **full_part_field_buffers; + uchar **restore_part_field_ptrs; + uchar **restore_subpart_field_ptrs; + uchar **restore_full_part_field_ptrs; + Item *part_expr; + Item *subpart_expr; + Item *item_free_list; + struct st_ddl_log_memory_entry *first_log_entry; + struct st_ddl_log_memory_entry *exec_log_entry; + struct st_ddl_log_memory_entry *frm_log_entry; + MY_BITMAP used_partitions; + union { + longlong *range_int_array; + LIST_PART_ENTRY *list_array; + }; + get_partitions_in_range_iter get_part_iter_for_interval; + get_partitions_in_range_iter get_subpart_iter_for_interval; + longlong err_value; + char* part_info_string; + char *part_func_string; + char *subpart_func_string; + const char *part_state; + partition_element *curr_part_elem; + partition_element *current_partition; + key_map all_fields_in_PF, all_fields_in_PPF, all_fields_in_SPF; + key_map some_fields_in_PF; + handlerton *default_engine_type; + Item_result part_result_type; + partition_type part_type; + partition_type subpart_type; + uint part_info_len; + uint part_state_len; + uint part_func_len; + uint subpart_func_len; + uint no_parts; + uint no_subparts; + uint count_curr_subparts; + uint part_error_code; + uint no_list_values; + uint no_part_fields; + uint no_subpart_fields; + uint no_full_part_fields; + uint has_null_part_id; + uint16 linear_hash_mask; + In_C_you_should_use_my_bool_instead() use_default_partitions; + In_C_you_should_use_my_bool_instead() use_default_no_partitions; + In_C_you_should_use_my_bool_instead() use_default_subpartitions; + In_C_you_should_use_my_bool_instead() use_default_no_subpartitions; + In_C_you_should_use_my_bool_instead() default_partitions_setup; + In_C_you_should_use_my_bool_instead() defined_max_value; + In_C_you_should_use_my_bool_instead() list_of_part_fields; + In_C_you_should_use_my_bool_instead() list_of_subpart_fields; + In_C_you_should_use_my_bool_instead() linear_hash_ind; + In_C_you_should_use_my_bool_instead() fixed; + In_C_you_should_use_my_bool_instead() is_auto_partitioned; + In_C_you_should_use_my_bool_instead() from_openfrm; + In_C_you_should_use_my_bool_instead() has_null_value; + partition_info() + : get_partition_id(NULL), get_part_partition_id(NULL), + get_subpartition_id(NULL), + part_field_array(NULL), subpart_field_array(NULL), + part_charset_field_array(NULL), + subpart_charset_field_array(NULL), + full_part_field_array(NULL), + full_part_charset_field_array(NULL), + part_field_buffers(NULL), subpart_field_buffers(NULL), + full_part_field_buffers(NULL), + restore_part_field_ptrs(NULL), restore_subpart_field_ptrs(NULL), + restore_full_part_field_ptrs(NULL), + part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), + first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL), + list_array(NULL), err_value(0), + part_info_string(NULL), + part_func_string(NULL), subpart_func_string(NULL), + part_state(NULL), + curr_part_elem(NULL), current_partition(NULL), + default_engine_type(NULL), + part_result_type(INT_RESULT), + part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION), + part_info_len(0), part_state_len(0), + part_func_len(0), subpart_func_len(0), + no_parts(0), no_subparts(0), + count_curr_subparts(0), part_error_code(0), + no_list_values(0), no_part_fields(0), no_subpart_fields(0), + no_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0), + use_default_partitions((1)), use_default_no_partitions((1)), + use_default_subpartitions((1)), use_default_no_subpartitions((1)), + default_partitions_setup((0)), defined_max_value((0)), + list_of_part_fields((0)), list_of_subpart_fields((0)), + linear_hash_ind((0)), fixed((0)), + is_auto_partitioned((0)), from_openfrm((0)), + has_null_value((0)) + { + all_fields_in_PF.clear_all(); + all_fields_in_PPF.clear_all(); + all_fields_in_SPF.clear_all(); + some_fields_in_PF.clear_all(); + partitions.empty(); + temp_partitions.empty(); + part_field_list.empty(); + subpart_field_list.empty(); + } + ~partition_info() {} + partition_info *get_clone(); + In_C_you_should_use_my_bool_instead() is_sub_partitioned() + { + return (subpart_type == NOT_A_PARTITION ? (0) : (1)); + } + uint get_tot_partitions() + { + return no_parts * (is_sub_partitioned() ? no_subparts : 1); + } + In_C_you_should_use_my_bool_instead() set_up_defaults_for_partitioning(handler *file, HA_CREATE_INFO *info, + uint start_no); + char *has_unique_names(); + In_C_you_should_use_my_bool_instead() check_engine_mix(handlerton *engine_type, In_C_you_should_use_my_bool_instead() default_engine); + In_C_you_should_use_my_bool_instead() check_range_constants(); + In_C_you_should_use_my_bool_instead() check_list_constants(); + In_C_you_should_use_my_bool_instead() check_partition_info(THD *thd, handlerton **eng_type, + handler *file, HA_CREATE_INFO *info, + In_C_you_should_use_my_bool_instead() check_partition_function); + void print_no_partition_found(TABLE *table); + In_C_you_should_use_my_bool_instead() set_up_charset_field_preps(); +private: + static int list_part_cmp(const void* a, const void* b); + static int list_part_cmp_unsigned(const void* a, const void* b); + In_C_you_should_use_my_bool_instead() set_up_default_partitions(handler *file, HA_CREATE_INFO *info, + uint start_no); + In_C_you_should_use_my_bool_instead() set_up_default_subpartitions(handler *file, HA_CREATE_INFO *info); + char *create_default_partition_names(uint part_no, uint no_parts, + uint start_no); + char *create_subpartition_name(uint subpart_no, const char *part_name); + In_C_you_should_use_my_bool_instead() has_unique_name(partition_element *element); +}; +uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); +In_C_you_should_use_my_bool_instead() check_partition_dirs(partition_info *part_info); +static inline void init_single_partition_iterator(uint32 part_id, + PARTITION_ITERATOR *part_iter) +{ + part_iter->part_nums.start= part_iter->part_nums.cur= part_id; + part_iter->part_nums.end= part_id+1; + part_iter->get_next= get_next_partition_id_range; +} +static inline +void init_all_partitions_iterator(partition_info *part_info, + PARTITION_ITERATOR *part_iter) +{ + part_iter->part_nums.start= part_iter->part_nums.cur= 0; + part_iter->part_nums.end= part_info->no_parts; + part_iter->get_next= get_next_partition_id_range; +} +class user_var_entry; +class Security_context; +enum enum_var_type +{ + OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL +}; +class sys_var; +#include "item.h" +class Protocol; +struct TABLE_LIST; +void item_init(void); +class Item_field; +class DTCollation { +public: + CHARSET_INFO *collation; + enum Derivation derivation; + uint repertoire; + void set_repertoire_from_charset(CHARSET_INFO *cs) + { + repertoire= cs->state & 4096 ? + 1 : 3; + } + DTCollation() + { + collation= &my_charset_bin; + derivation= DERIVATION_NONE; + repertoire= 3; + } + DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg) + { + collation= collation_arg; + derivation= derivation_arg; + set_repertoire_from_charset(collation_arg); + } + void set(DTCollation &dt) + { + collation= dt.collation; + derivation= dt.derivation; + repertoire= dt.repertoire; + } + void set(CHARSET_INFO *collation_arg, Derivation derivation_arg) + { + collation= collation_arg; + derivation= derivation_arg; + set_repertoire_from_charset(collation_arg); + } + void set(CHARSET_INFO *collation_arg, + Derivation derivation_arg, + uint repertoire_arg) + { + collation= collation_arg; + derivation= derivation_arg; + repertoire= repertoire_arg; + } + void set(CHARSET_INFO *collation_arg) + { + collation= collation_arg; + set_repertoire_from_charset(collation_arg); + } + void set(Derivation derivation_arg) + { derivation= derivation_arg; } + In_C_you_should_use_my_bool_instead() aggregate(DTCollation &dt, uint flags= 0); + In_C_you_should_use_my_bool_instead() set(DTCollation &dt1, DTCollation &dt2, uint flags= 0) + { set(dt1); return aggregate(dt2, flags); } + const char *derivation_name() const + { + switch(derivation) + { + case DERIVATION_IGNORABLE: return "IGNORABLE"; + case DERIVATION_COERCIBLE: return "COERCIBLE"; + case DERIVATION_IMPLICIT: return "IMPLICIT"; + case DERIVATION_SYSCONST: return "SYSCONST"; + case DERIVATION_EXPLICIT: return "EXPLICIT"; + case DERIVATION_NONE: return "NONE"; + default: return "UNKNOWN"; + } + } +}; +struct Hybrid_type_traits; +struct Hybrid_type +{ + longlong integer; + double real; + my_decimal dec_buf[3]; + int used_dec_buf_no; + const Hybrid_type_traits *traits; + Hybrid_type() {} + Hybrid_type(const Hybrid_type &rhs) :traits(rhs.traits) {} +}; +struct Hybrid_type_traits +{ + virtual Item_result type() const { return REAL_RESULT; } + virtual void + fix_length_and_dec(Item *item, Item *arg) const; + virtual void set_zero(Hybrid_type *val) const { val->real= 0.0; } + virtual void add(Hybrid_type *val, Field *f) const + { val->real+= f->val_real(); } + virtual void div(Hybrid_type *val, ulonglong u) const + { val->real/= ((double) (ulonglong) (u)); } + virtual longlong val_int(Hybrid_type *val, In_C_you_should_use_my_bool_instead() unsigned_flag) const + { return (longlong) rint(val->real); } + virtual double val_real(Hybrid_type *val) const { return val->real; } + virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const; + virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const; + static const Hybrid_type_traits *instance(); + Hybrid_type_traits() {} + virtual ~Hybrid_type_traits() {} +}; +struct Hybrid_type_traits_decimal: public Hybrid_type_traits +{ + virtual Item_result type() const { return DECIMAL_RESULT; } + virtual void + fix_length_and_dec(Item *arg, Item *item) const; + virtual void set_zero(Hybrid_type *val) const; + virtual void add(Hybrid_type *val, Field *f) const; + virtual void div(Hybrid_type *val, ulonglong u) const; + virtual longlong val_int(Hybrid_type *val, In_C_you_should_use_my_bool_instead() unsigned_flag) const; + virtual double val_real(Hybrid_type *val) const; + virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const + { return &val->dec_buf[val->used_dec_buf_no]; } + virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const; + static const Hybrid_type_traits_decimal *instance(); + Hybrid_type_traits_decimal() {}; +}; +struct Hybrid_type_traits_integer: public Hybrid_type_traits +{ + virtual Item_result type() const { return INT_RESULT; } + virtual void + fix_length_and_dec(Item *arg, Item *item) const; + virtual void set_zero(Hybrid_type *val) const + { val->integer= 0; } + virtual void add(Hybrid_type *val, Field *f) const + { val->integer+= f->val_int(); } + virtual void div(Hybrid_type *val, ulonglong u) const + { val->integer/= (longlong) u; } + virtual longlong val_int(Hybrid_type *val, In_C_you_should_use_my_bool_instead() unsigned_flag) const + { return val->integer; } + virtual double val_real(Hybrid_type *val) const + { return (double) val->integer; } + virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const + { + int2my_decimal(30, val->integer, 0, &val->dec_buf[2]); + return &val->dec_buf[2]; + } + virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const + { buf->set(val->integer, &my_charset_bin); return buf;} + static const Hybrid_type_traits_integer *instance(); + Hybrid_type_traits_integer() {}; +}; +void dummy_error_processor(THD *thd, void *data); +void view_error_processor(THD *thd, void *data); +struct Name_resolution_context: Sql_alloc +{ + Name_resolution_context *outer_context; + TABLE_LIST *table_list; + TABLE_LIST *first_name_resolution_table; + TABLE_LIST *last_name_resolution_table; + st_select_lex *select_lex; + void (*error_processor)(THD *, void *); + void *error_processor_data; + In_C_you_should_use_my_bool_instead() resolve_in_select_list; + Security_context *security_ctx; + Name_resolution_context() + :outer_context(0), table_list(0), select_lex(0), + error_processor_data(0), + security_ctx(0) + {} + void init() + { + resolve_in_select_list= (0); + error_processor= &dummy_error_processor; + first_name_resolution_table= NULL; + last_name_resolution_table= NULL; + } + void resolve_in_table_list_only(TABLE_LIST *tables) + { + table_list= first_name_resolution_table= tables; + resolve_in_select_list= (0); + } + void process_error(THD *thd) + { + (*error_processor)(thd, error_processor_data); + } +}; +class Name_resolution_context_state +{ +private: + TABLE_LIST *save_table_list; + TABLE_LIST *save_first_name_resolution_table; + TABLE_LIST *save_next_name_resolution_table; + In_C_you_should_use_my_bool_instead() save_resolve_in_select_list; + TABLE_LIST *save_next_local; +public: + Name_resolution_context_state() {} +public: + void save_state(Name_resolution_context *context, TABLE_LIST *table_list) + { + save_table_list= context->table_list; + save_first_name_resolution_table= context->first_name_resolution_table; + save_resolve_in_select_list= context->resolve_in_select_list; + save_next_local= table_list->next_local; + save_next_name_resolution_table= table_list->next_name_resolution_table; + } + void restore_state(Name_resolution_context *context, TABLE_LIST *table_list) + { + table_list->next_local= save_next_local; + table_list->next_name_resolution_table= save_next_name_resolution_table; + context->table_list= save_table_list; + 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; + } +}; +typedef enum monotonicity_info +{ + NON_MONOTONIC, + MONOTONIC_INCREASING, + MONOTONIC_STRICT_INCREASING +} enum_monotonicity_info; +class sp_rcontext; +class Settable_routine_parameter +{ +public: + Settable_routine_parameter() {} + virtual ~Settable_routine_parameter() {} + virtual void set_required_privilege(In_C_you_should_use_my_bool_instead() rw) {}; + virtual In_C_you_should_use_my_bool_instead() set_value(THD *thd, sp_rcontext *ctx, Item **it)= 0; +}; +typedef In_C_you_should_use_my_bool_instead() (Item::*Item_processor) (uchar *arg); +typedef In_C_you_should_use_my_bool_instead() (Item::*Item_analyzer) (uchar **argp); +typedef Item* (Item::*Item_transformer) (uchar *arg); +typedef void (*Cond_traverser) (const Item *item, void *arg); +class Item { + Item(const Item &); + void operator=(Item &); +public: + static void *operator new(size_t size) + { return sql_alloc(size); } + static void *operator new(size_t size, MEM_ROOT *mem_root) + { return alloc_root(mem_root, size); } + static void operator delete(void *ptr,size_t size) { ; } + static void operator delete(void *ptr, MEM_ROOT *mem_root) {} + enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM, + INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM, + COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM, + PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, + FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, + SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, + PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM, + XPATH_NODESET, XPATH_NODESET_CMP, + VIEW_FIXER_ITEM}; + enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; + enum traverse_order { POSTFIX, PREFIX }; + uint rsize; + String str_value; + char * name; + char * orig_name; + Item *next; + uint32 max_length; + uint name_length; + int8 marker; + uint8 decimals; + my_bool maybe_null; + my_bool null_value; + my_bool unsigned_flag; + my_bool with_sum_func; + my_bool fixed; + my_bool is_autogenerated_name; + DTCollation collation; + my_bool with_subselect; + Item_result cmp_context; + Item(); + Item(THD *thd, Item *item); + virtual ~Item() + { + } + void set_name(const char *str, uint length, CHARSET_INFO *cs); + void rename(char *new_name); + void init_make_field(Send_field *tmp_field,enum enum_field_types type); + virtual void cleanup(); + virtual void make_field(Send_field *field); + Field *make_string_field(TABLE *table); + virtual In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **); + inline void quick_fix_field() { fixed= 1; } + int save_in_field_no_warnings(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); + virtual int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); + virtual void save_org_in_field(Field *field) + { (void) save_in_field(field, 1); } + virtual int save_safe_in_field(Field *field) + { return save_in_field(field, 1); } + virtual In_C_you_should_use_my_bool_instead() send(Protocol *protocol, String *str); + virtual In_C_you_should_use_my_bool_instead() eq(const Item *, In_C_you_should_use_my_bool_instead() binary_cmp) const; + virtual Item_result result_type() const { return REAL_RESULT; } + virtual Item_result cast_to_int_type() const { return result_type(); } + virtual enum_field_types string_field_type() const; + virtual enum_field_types field_type() const; + virtual enum Type type() const =0; + virtual enum_monotonicity_info get_monotonicity_info() const + { return NON_MONOTONIC; } + virtual longlong val_int_endpoint(In_C_you_should_use_my_bool_instead() left_endp, In_C_you_should_use_my_bool_instead() *incl_endp) + { assert(0); return 0; } + virtual double val_real()=0; + virtual longlong val_int()=0; + inline ulonglong val_uint() { return (ulonglong) val_int(); } + virtual String *val_str(String *str)=0; + virtual my_decimal *val_decimal(my_decimal *decimal_buffer)= 0; + virtual In_C_you_should_use_my_bool_instead() val_bool(); + virtual String *val_nodeset(String*) { return 0; } + String *val_string_from_real(String *str); + String *val_string_from_int(String *str); + String *val_string_from_decimal(String *str); + my_decimal *val_decimal_from_real(my_decimal *decimal_value); + my_decimal *val_decimal_from_int(my_decimal *decimal_value); + my_decimal *val_decimal_from_string(my_decimal *decimal_value); + my_decimal *val_decimal_from_date(my_decimal *decimal_value); + my_decimal *val_decimal_from_time(my_decimal *decimal_value); + longlong val_int_from_decimal(); + double val_real_from_decimal(); + int save_time_in_field(Field *field); + int save_date_in_field(Field *field); + int save_str_value_in_field(Field *field, String *result); + virtual Field *get_tmp_table_field() { return 0; } + virtual Field *tmp_table_field(TABLE *t_arg) { return 0; } + virtual const char *full_name() const { return name ? name : "???"; } + virtual double val_result() { return val_real(); } + virtual longlong val_int_result() { return val_int(); } + virtual String *str_result(String* tmp) { return val_str(tmp); } + virtual my_decimal *val_decimal_result(my_decimal *val) + { return val_decimal(val); } + virtual In_C_you_should_use_my_bool_instead() val_bool_result() { return val_bool(); } + virtual table_map used_tables() const { return (table_map) 0L; } + virtual table_map not_null_tables() const { return used_tables(); } + virtual In_C_you_should_use_my_bool_instead() basic_const_item() const { 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 != 31 ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} + virtual uint decimal_precision() const; + inline int decimal_int_part() const + { return my_decimal_int_part(decimal_precision(), decimals); } + virtual In_C_you_should_use_my_bool_instead() const_item() const { return used_tables() == 0; } + virtual In_C_you_should_use_my_bool_instead() const_during_execution() const + { return (used_tables() & ~(((table_map) 1) << (sizeof(table_map)*8-3))) == 0; } + virtual inline void print(String *str, enum_query_type query_type) + { + str->append(full_name()); + } + void print_item_w_name(String *, enum_query_type query_type); + virtual void update_used_tables() {} + virtual void split_sum_func(THD *thd, Item **ref_pointer_array, + List<Item> &fields) {} + void split_sum_func2(THD *thd, Item **ref_pointer_array, List<Item> &fields, + Item **ref, In_C_you_should_use_my_bool_instead() skip_registered); + virtual In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate); + virtual In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime); + virtual In_C_you_should_use_my_bool_instead() get_date_result(MYSQL_TIME *ltime,uint fuzzydate) + { return get_date(ltime,fuzzydate); } + virtual In_C_you_should_use_my_bool_instead() is_null() { return 0; } + virtual void update_null_value () { (void) val_int(); } + virtual void top_level_item() {} + virtual void set_result_field(Field *field) {} + virtual In_C_you_should_use_my_bool_instead() is_result_field() { return 0; } + virtual In_C_you_should_use_my_bool_instead() is_bool_func() { return 0; } + virtual void save_in_result_field(In_C_you_should_use_my_bool_instead() no_conversions) {} + virtual void no_rows_in_result() {} + virtual Item *copy_or_same(THD *thd) { return this; } + virtual Item *copy_andor_structure(THD *thd) { return this; } + virtual Item *real_item() { return this; } + virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } + static CHARSET_INFO *default_charset(); + virtual CHARSET_INFO *compare_collation() { return NULL; } + virtual In_C_you_should_use_my_bool_instead() walk(Item_processor processor, In_C_you_should_use_my_bool_instead() walk_subquery, uchar *arg) + { + return (this->*processor)(arg); + } + virtual Item* transform(Item_transformer transformer, uchar *arg); + virtual Item* compile(Item_analyzer analyzer, uchar **arg_p, + Item_transformer transformer, uchar *arg_t) + { + if ((this->*analyzer) (arg_p)) + return ((this->*transformer) (arg_t)); + return 0; + } + virtual void traverse_cond(Cond_traverser traverser, + void *arg, traverse_order order) + { + (*traverser)(this, arg); + } + virtual In_C_you_should_use_my_bool_instead() remove_dependence_processor(uchar * arg) { return 0; } + virtual In_C_you_should_use_my_bool_instead() remove_fixed(uchar * arg) { fixed= 0; return 0; } + virtual In_C_you_should_use_my_bool_instead() cleanup_processor(uchar *arg); + virtual In_C_you_should_use_my_bool_instead() collect_item_field_processor(uchar * arg) { return 0; } + virtual In_C_you_should_use_my_bool_instead() find_item_in_field_list_processor(uchar *arg) { return 0; } + virtual In_C_you_should_use_my_bool_instead() change_context_processor(uchar *context) { return 0; } + virtual In_C_you_should_use_my_bool_instead() reset_query_id_processor(uchar *query_id_arg) { return 0; } + virtual In_C_you_should_use_my_bool_instead() is_expensive_processor(uchar *arg) { return 0; } + virtual In_C_you_should_use_my_bool_instead() register_field_in_read_map(uchar *arg) { return 0; } + virtual In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *bool_arg) { return (1);} + virtual In_C_you_should_use_my_bool_instead() subst_argument_checker(uchar **arg) + { + if (*arg) + *arg= NULL; + return (1); + } + virtual Item *equal_fields_propagator(uchar * arg) { return this; } + virtual In_C_you_should_use_my_bool_instead() set_no_const_sub(uchar *arg) { return (0); } + virtual Item *replace_equal_field(uchar * arg) { return this; } + virtual Item *this_item() { return this; } + virtual const Item *this_item() const { return this; } + virtual Item **this_item_addr(THD *thd, Item **addr_arg) { return addr_arg; } + virtual uint cols() { return 1; } + virtual Item* element_index(uint i) { return this; } + virtual Item** addr(uint i) { return 0; } + virtual In_C_you_should_use_my_bool_instead() check_cols(uint c); + virtual In_C_you_should_use_my_bool_instead() null_inside() { return 0; } + virtual void bring_value() {} + Field *tmp_table_field_from_field_type(TABLE *table, In_C_you_should_use_my_bool_instead() fixed_length); + virtual Item_field *filed_for_view_update() { return 0; } + virtual Item *neg_transformer(THD *thd) { return NULL; } + virtual Item *update_value_transformer(uchar *select_arg) { return this; } + virtual Item *safe_charset_converter(CHARSET_INFO *tocs); + void delete_self() + { + cleanup(); + delete this; + } + virtual In_C_you_should_use_my_bool_instead() is_splocal() { return 0; } + virtual Settable_routine_parameter *get_settable_routine_parameter() + { + return 0; + } + virtual In_C_you_should_use_my_bool_instead() result_as_longlong() { return (0); } + In_C_you_should_use_my_bool_instead() is_datetime(); + virtual Field::geometry_type get_geometry_type() const + { return Field::GEOM_GEOMETRY; }; + String *check_well_formed_result(String *str, In_C_you_should_use_my_bool_instead() send_error= 0); + In_C_you_should_use_my_bool_instead() eq_by_collation(Item *item, In_C_you_should_use_my_bool_instead() binary_cmp, CHARSET_INFO *cs); +}; +class sp_head; +class Item_basic_constant :public Item +{ +public: + void cleanup() + { + if (orig_name) + name= orig_name; + } +}; +class Item_sp_variable :public Item +{ +protected: + THD *m_thd; +public: + LEX_STRING m_name; +public: + sp_head *m_sp; +public: + Item_sp_variable(char *sp_var_name_str, uint sp_var_name_length); +public: + In_C_you_should_use_my_bool_instead() fix_fields(THD *thd, Item **); + double val_real(); + longlong val_int(); + String *val_str(String *sp); + my_decimal *val_decimal(my_decimal *decimal_value); + In_C_you_should_use_my_bool_instead() is_null(); +public: + inline void make_field(Send_field *field); + inline In_C_you_should_use_my_bool_instead() const_item() const; + inline int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); + inline In_C_you_should_use_my_bool_instead() send(Protocol *protocol, String *str); +}; +inline void Item_sp_variable::make_field(Send_field *field) +{ + Item *it= this_item(); + if (name) + it->set_name(name, (uint) strlen(name), system_charset_info); + else + it->set_name(m_name.str, m_name.length, system_charset_info); + it->make_field(field); +} +inline In_C_you_should_use_my_bool_instead() Item_sp_variable::const_item() const +{ + return (1); +} +inline int Item_sp_variable::save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions) +{ + return this_item()->save_in_field(field, no_conversions); +} +inline In_C_you_should_use_my_bool_instead() Item_sp_variable::send(Protocol *protocol, String *str) +{ + return this_item()->send(protocol, str); +} +class Item_splocal :public Item_sp_variable, + private Settable_routine_parameter +{ + uint m_var_idx; + Type m_type; + Item_result m_result_type; + enum_field_types m_field_type; +public: + uint pos_in_query; + uint len_in_query; + Item_splocal(const LEX_STRING &sp_var_name, uint sp_var_idx, + enum_field_types sp_var_type, + uint pos_in_q= 0, uint len_in_q= 0); + In_C_you_should_use_my_bool_instead() is_splocal() { return 1; } + Item *this_item(); + const Item *this_item() const; + Item **this_item_addr(THD *thd, Item **); + virtual void print(String *str, enum_query_type query_type); +public: + inline const LEX_STRING *my_name() const; + inline uint get_var_idx() const; + inline enum Type type() const; + inline Item_result result_type() const; + inline enum_field_types field_type() const { return m_field_type; } +private: + In_C_you_should_use_my_bool_instead() set_value(THD *thd, sp_rcontext *ctx, Item **it); +public: + Settable_routine_parameter *get_settable_routine_parameter() + { + return this; + } +}; +inline const LEX_STRING *Item_splocal::my_name() const +{ + return &m_name; +} +inline uint Item_splocal::get_var_idx() const +{ + return m_var_idx; +} +inline enum Item::Type Item_splocal::type() const +{ + return m_type; +} +inline Item_result Item_splocal::result_type() const +{ + return m_result_type; +} +class Item_case_expr :public Item_sp_variable +{ +public: + Item_case_expr(uint case_expr_id); +public: + Item *this_item(); + const Item *this_item() const; + Item **this_item_addr(THD *thd, Item **); + inline enum Type type() const; + inline Item_result result_type() const; +public: + virtual void print(String *str, enum_query_type query_type); +private: + uint m_case_expr_id; +}; +inline enum Item::Type Item_case_expr::type() const +{ + return this_item()->type(); +} +inline Item_result Item_case_expr::result_type() const +{ + return this_item()->result_type(); +} +class Item_name_const : public Item +{ + Item *value_item; + Item *name_item; + In_C_you_should_use_my_bool_instead() valid_args; +public: + Item_name_const(Item *name_arg, Item *val); + In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **); + enum Type type() const; + double val_real(); + longlong val_int(); + String *val_str(String *sp); + my_decimal *val_decimal(my_decimal *); + In_C_you_should_use_my_bool_instead() is_null(); + virtual void print(String *str, enum_query_type query_type); + Item_result result_type() const + { + return value_item->result_type(); + } + In_C_you_should_use_my_bool_instead() const_item() const + { + return (1); + } + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions) + { + return value_item->save_in_field(field, no_conversions); + } + In_C_you_should_use_my_bool_instead() send(Protocol *protocol, String *str) + { + return value_item->send(protocol, str); + } +}; +In_C_you_should_use_my_bool_instead() agg_item_collations(DTCollation &c, const char *name, + Item **items, uint nitems, uint flags, int item_sep); +In_C_you_should_use_my_bool_instead() agg_item_collations_for_comparison(DTCollation &c, const char *name, + Item **items, uint nitems, uint flags); +In_C_you_should_use_my_bool_instead() agg_item_charsets(DTCollation &c, const char *name, + Item **items, uint nitems, uint flags, int item_sep); +class Item_num: public Item_basic_constant +{ +public: + Item_num() {} + virtual Item_num *neg()= 0; + Item *safe_charset_converter(CHARSET_INFO *tocs); + In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) { return (0);} +}; +class st_select_lex; +class Item_ident :public Item +{ +protected: + const char *orig_db_name; + const char *orig_table_name; + const char *orig_field_name; +public: + Name_resolution_context *context; + const char *db_name; + const char *table_name; + const char *field_name; + In_C_you_should_use_my_bool_instead() alias_name_used; + uint cached_field_index; + TABLE_LIST *cached_table; + st_select_lex *depended_from; + Item_ident(Name_resolution_context *context_arg, + const char *db_name_arg, const char *table_name_arg, + const char *field_name_arg); + Item_ident(THD *thd, Item_ident *item); + const char *full_name() const; + void cleanup(); + In_C_you_should_use_my_bool_instead() remove_dependence_processor(uchar * arg); + virtual void print(String *str, enum_query_type query_type); + virtual In_C_you_should_use_my_bool_instead() change_context_processor(uchar *cntx) + { context= (Name_resolution_context *)cntx; return (0); } + friend In_C_you_should_use_my_bool_instead() insert_fields(THD *thd, Name_resolution_context *context, + const char *db_name, + const char *table_name, List_iterator<Item> *it, + In_C_you_should_use_my_bool_instead() any_privileges); +}; +class Item_ident_for_show :public Item +{ +public: + Field *field; + const char *db_name; + const char *table_name; + Item_ident_for_show(Field *par_field, const char *db_arg, + const char *table_name_arg) + :field(par_field), db_name(db_arg), table_name(table_name_arg) + {} + enum Type type() const { return FIELD_ITEM; } + double val_real() { return field->val_real(); } + longlong val_int() { return field->val_int(); } + String *val_str(String *str) { return field->val_str(str); } + my_decimal *val_decimal(my_decimal *dec) { return field->val_decimal(dec); } + void make_field(Send_field *tmp_field); +}; +class Item_equal; +class COND_EQUAL; +class Item_field :public Item_ident +{ +protected: + void set_field(Field *field); +public: + Field *field,*result_field; + Item_equal *item_equal; + In_C_you_should_use_my_bool_instead() no_const_subst; + uint have_privileges; + In_C_you_should_use_my_bool_instead() any_privileges; + Item_field(Name_resolution_context *context_arg, + const char *db_arg,const char *table_name_arg, + const char *field_name_arg); + Item_field(THD *thd, Item_field *item); + Item_field(THD *thd, Name_resolution_context *context_arg, Field *field); + Item_field(Field *field); + enum Type type() const { return FIELD_ITEM; } + In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const; + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); + String *val_str(String*); + double val_result(); + longlong val_int_result(); + String *str_result(String* tmp); + my_decimal *val_decimal_result(my_decimal *); + In_C_you_should_use_my_bool_instead() val_bool_result(); + In_C_you_should_use_my_bool_instead() send(Protocol *protocol, String *str_arg); + void reset_field(Field *f); + In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **); + void make_field(Send_field *tmp_field); + int save_in_field(Field *field,In_C_you_should_use_my_bool_instead() no_conversions); + void save_org_in_field(Field *field); + table_map used_tables() const; + enum Item_result result_type () const + { + return field->result_type(); + } + Item_result cast_to_int_type() const + { + return field->cast_to_int_type(); + } + enum_field_types field_type() const + { + return field->type(); + } + enum_monotonicity_info get_monotonicity_info() const + { + return MONOTONIC_STRICT_INCREASING; + } + longlong val_int_endpoint(In_C_you_should_use_my_bool_instead() left_endp, In_C_you_should_use_my_bool_instead() *incl_endp); + Field *get_tmp_table_field() { return result_field; } + Field *tmp_table_field(TABLE *t_arg) { return result_field; } + In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate); + In_C_you_should_use_my_bool_instead() get_date_result(MYSQL_TIME *ltime,uint fuzzydate); + In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *ltime); + In_C_you_should_use_my_bool_instead() is_null() { return field->is_null(); } + void update_null_value(); + Item *get_tmp_table_item(THD *thd); + In_C_you_should_use_my_bool_instead() collect_item_field_processor(uchar * arg); + In_C_you_should_use_my_bool_instead() find_item_in_field_list_processor(uchar *arg); + In_C_you_should_use_my_bool_instead() register_field_in_read_map(uchar *arg); + In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) {return (0);} + void cleanup(); + In_C_you_should_use_my_bool_instead() result_as_longlong() + { + return field->can_be_compared_as_longlong(); + } + Item_equal *find_item_equal(COND_EQUAL *cond_equal); + In_C_you_should_use_my_bool_instead() subst_argument_checker(uchar **arg); + Item *equal_fields_propagator(uchar *arg); + In_C_you_should_use_my_bool_instead() set_no_const_sub(uchar *arg); + Item *replace_equal_field(uchar *arg); + 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(uchar *select_arg); + virtual void print(String *str, enum_query_type query_type); + Field::geometry_type get_geometry_type() const + { + assert(field_type() == MYSQL_TYPE_GEOMETRY); + return field->get_geometry_type(); + } + friend class Item_default_value; + friend class Item_insert_value; + friend class st_select_lex_unit; +}; +class Item_null :public Item_basic_constant +{ +public: + Item_null(char *name_par=0) + { + maybe_null= null_value= (1); + max_length= 0; + name= name_par ? name_par : (char*) "NULL"; + fixed= 1; + collation.set(&my_charset_bin, DERIVATION_IGNORABLE); + } + enum Type type() const { return NULL_ITEM; } + In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const; + double val_real(); + longlong val_int(); + String *val_str(String *str); + my_decimal *val_decimal(my_decimal *); + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); + int save_safe_in_field(Field *field); + In_C_you_should_use_my_bool_instead() send(Protocol *protocol, String *str); + enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_NULL; } + In_C_you_should_use_my_bool_instead() basic_const_item() const { return 1; } + Item *clone_item() { return new Item_null(name); } + In_C_you_should_use_my_bool_instead() is_null() { return 1; } + virtual inline void print(String *str, enum_query_type query_type) + { + str->append(("NULL"), ((size_t) (sizeof("NULL") - 1))); + } + Item *safe_charset_converter(CHARSET_INFO *tocs); + In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) {return (0);} +}; +class Item_null_result :public Item_null +{ +public: + Field *result_field; + Item_null_result() : Item_null(), result_field(0) {} + In_C_you_should_use_my_bool_instead() is_result_field() { return result_field != 0; } + void save_in_result_field(In_C_you_should_use_my_bool_instead() no_conversions) + { + save_in_field(result_field, no_conversions); + } + In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) {return (1);} +}; +class Item_param :public Item +{ + char cnvbuf[(255*3 +1)]; + String cnvstr; + Item *cnvitem; +public: + enum enum_item_param_state + { + NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE, + STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE, + DECIMAL_VALUE + } state; + String str_value_ptr; + my_decimal decimal_value; + union + { + longlong integer; + double real; + struct CONVERSION_INFO + { + CHARSET_INFO *character_set_client; + CHARSET_INFO *character_set_of_placeholder; + CHARSET_INFO *final_character_set_of_str_value; + } cs_info; + MYSQL_TIME time; + } value; + enum Item_result item_result_type; + enum Type item_type; + enum enum_field_types param_type; + uint pos_in_query; + Item_param(uint pos_in_query_arg); + enum Item_result result_type () const { return item_result_type; } + enum Type type() const { return item_type; } + enum_field_types field_type() const { return param_type; } + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal*); + String *val_str(String*); + In_C_you_should_use_my_bool_instead() get_time(MYSQL_TIME *tm); + In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *tm, uint fuzzydate); + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); + void set_null(); + void set_int(longlong i, uint32 max_length_arg); + void set_double(double i); + void set_decimal(const char *str, ulong length); + In_C_you_should_use_my_bool_instead() set_str(const char *str, ulong length); + In_C_you_should_use_my_bool_instead() set_longdata(const char *str, ulong length); + void set_time(MYSQL_TIME *tm, timestamp_type type, uint32 max_length_arg); + In_C_you_should_use_my_bool_instead() set_from_user_var(THD *thd, const user_var_entry *entry); + void reset(); + void (*set_param_func)(Item_param *param, uchar **pos, ulong len); + const String *query_val_str(String *str) const; + In_C_you_should_use_my_bool_instead() convert_str_value(THD *thd); + virtual table_map used_tables() const + { return state != NO_VALUE ? (table_map)0 : (((table_map) 1) << (sizeof(table_map)*8-3)); } + virtual void print(String *str, enum_query_type query_type); + In_C_you_should_use_my_bool_instead() is_null() + { assert(state != NO_VALUE); return state == NULL_VALUE; } + In_C_you_should_use_my_bool_instead() basic_const_item() const; + Item *safe_charset_converter(CHARSET_INFO *tocs); + Item *clone_item(); + In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const; + In_C_you_should_use_my_bool_instead() limit_clause_param; + void set_param_type_and_swap_value(Item_param *from); +}; +class Item_int :public Item_num +{ +public: + longlong value; + Item_int(int32 i,uint length= 11) + :value((longlong) i) + { max_length=length; fixed= 1; } + Item_int(longlong i,uint length= 21) + :value(i) + { max_length=length; fixed= 1; } + Item_int(ulonglong i, uint length= 21) + :value((longlong)i) + { max_length=length; fixed= 1; unsigned_flag= 1; } + Item_int(const char *str_arg,longlong i,uint length) :value(i) + { max_length=length; name=(char*) str_arg; fixed= 1; } + Item_int(const char *str_arg, uint length=64); + enum Type type() const { return INT_ITEM; } + enum Item_result result_type () const { return INT_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } + longlong val_int() { assert(fixed == 1); return value; } + double val_real() { assert(fixed == 1); return (double) value; } + my_decimal *val_decimal(my_decimal *); + String *val_str(String*); + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); + In_C_you_should_use_my_bool_instead() basic_const_item() const { return 1; } + Item *clone_item() { return new Item_int(name,value,max_length); } + virtual void print(String *str, enum_query_type query_type); + Item_num *neg() { value= -value; return this; } + uint decimal_precision() const + { return (uint)(max_length - ((value < 0) ? 1 : 0)); } + In_C_you_should_use_my_bool_instead() eq(const Item *, In_C_you_should_use_my_bool_instead() binary_cmp) const; + In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *bool_arg) { return (0);} +}; +class Item_uint :public Item_int +{ +public: + Item_uint(const char *str_arg, uint length); + Item_uint(ulonglong i) :Item_int((ulonglong) i, 10) {} + Item_uint(const char *str_arg, longlong i, uint length); + double val_real() + { assert(fixed == 1); return ((double) (ulonglong) ((ulonglong)value)); } + String *val_str(String*); + Item *clone_item() { return new Item_uint(name, value, max_length); } + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); + virtual void print(String *str, enum_query_type query_type); + Item_num *neg (); + uint decimal_precision() const { return max_length; } + In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *bool_arg) { return (0);} +}; +class Item_decimal :public Item_num +{ +protected: + my_decimal decimal_value; +public: + Item_decimal(const char *str_arg, uint length, CHARSET_INFO *charset); + Item_decimal(const char *str, const my_decimal *val_arg, + uint decimal_par, uint length); + Item_decimal(my_decimal *value_par); + Item_decimal(longlong val, In_C_you_should_use_my_bool_instead() unsig); + Item_decimal(double val, int precision, int scale); + Item_decimal(const uchar *bin, int precision, int scale); + enum Type type() const { return DECIMAL_ITEM; } + enum Item_result result_type () const { return DECIMAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } + longlong val_int(); + double val_real(); + String *val_str(String*); + my_decimal *val_decimal(my_decimal *val) { return &decimal_value; } + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); + In_C_you_should_use_my_bool_instead() basic_const_item() const { return 1; } + Item *clone_item() + { + return new Item_decimal(name, &decimal_value, decimals, max_length); + } + virtual void print(String *str, enum_query_type query_type); + Item_num *neg() + { + my_decimal_neg(&decimal_value); + unsigned_flag= !decimal_value.sign(); + return this; + } + uint decimal_precision() const { return decimal_value.precision(); } + In_C_you_should_use_my_bool_instead() eq(const Item *, In_C_you_should_use_my_bool_instead() binary_cmp) const; + void set_decimal_value(my_decimal *value_par); + In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *bool_arg) { return (0);} +}; +class Item_float :public Item_num +{ + char *presentation; +public: + double value; + Item_float(const char *str_arg, uint length); + Item_float(const char *str,double val_arg,uint decimal_par,uint length) + :value(val_arg) + { + presentation= name=(char*) str; + decimals=(uint8) decimal_par; + max_length=length; + fixed= 1; + } + Item_float(double value_par, uint decimal_par) :presentation(0), value(value_par) + { + decimals= (uint8) decimal_par; + fixed= 1; + } + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); + enum Type type() const { return REAL_ITEM; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + double val_real() { assert(fixed == 1); return value; } + longlong val_int() + { + assert(fixed == 1); + if (value <= (double) ((long long) 0x8000000000000000LL)) + { + return ((long long) 0x8000000000000000LL); + } + else if (value >= (double) (ulonglong) ((long long) 0x7FFFFFFFFFFFFFFFLL)) + { + return ((long long) 0x7FFFFFFFFFFFFFFFLL); + } + return (longlong) rint(value); + } + String *val_str(String*); + my_decimal *val_decimal(my_decimal *); + In_C_you_should_use_my_bool_instead() basic_const_item() const { return 1; } + Item *clone_item() + { return new Item_float(name, value, decimals, max_length); } + Item_num *neg() { value= -value; return this; } + virtual void print(String *str, enum_query_type query_type); + In_C_you_should_use_my_bool_instead() eq(const Item *, In_C_you_should_use_my_bool_instead() binary_cmp) const; +}; +class Item_static_float_func :public Item_float +{ + const char *func_name; +public: + Item_static_float_func(const char *str, double val_arg, uint decimal_par, + uint length) + :Item_float((char *) 0, val_arg, decimal_par, length), func_name(str) + {} + virtual inline void print(String *str, enum_query_type query_type) + { + str->append(func_name); + } + Item *safe_charset_converter(CHARSET_INFO *tocs); +}; +class Item_string :public Item_basic_constant +{ +public: + Item_string(const char *str,uint length, + CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE, + uint repertoire= 3) + : m_cs_specified((0)) + { + str_value.set_or_copy_aligned(str, length, cs); + collation.set(cs, dv, repertoire); + max_length= str_value.numchars()*cs->mbmaxlen; + set_name(str, length, cs); + decimals=31; + fixed= 1; + } + Item_string(CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) + : m_cs_specified((0)) + { + collation.set(cs, dv); + max_length= 0; + set_name(NULL, 0, cs); + decimals= 31; + fixed= 1; + } + Item_string(const char *name_par, const char *str, uint length, + CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE, + uint repertoire= 3) + : m_cs_specified((0)) + { + str_value.set_or_copy_aligned(str, length, cs); + collation.set(cs, dv, repertoire); + max_length= str_value.numchars()*cs->mbmaxlen; + set_name(name_par, 0, cs); + decimals=31; + fixed= 1; + } + void set_str_with_copy(const char *str_arg, uint length_arg) + { + str_value.copy(str_arg, length_arg, collation.collation); + max_length= str_value.numchars() * collation.collation->mbmaxlen; + } + void set_repertoire_from_value() + { + collation.repertoire= my_string_repertoire(str_value.charset(), + str_value.ptr(), + str_value.length()); + } + enum Type type() const { return STRING_ITEM; } + double val_real(); + longlong val_int(); + String *val_str(String*) + { + assert(fixed == 1); + return (String*) &str_value; + } + my_decimal *val_decimal(my_decimal *); + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); + enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } + In_C_you_should_use_my_bool_instead() basic_const_item() const { return 1; } + In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const; + Item *clone_item() + { + return new Item_string(name, str_value.ptr(), + str_value.length(), collation.collation); + } + Item *safe_charset_converter(CHARSET_INFO *tocs); + inline void append(char *str, uint length) + { + str_value.append(str, length); + max_length= str_value.numchars() * collation.collation->mbmaxlen; + } + virtual void print(String *str, enum_query_type query_type); + In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) {return (0);} + inline In_C_you_should_use_my_bool_instead() is_cs_specified() const + { + return m_cs_specified; + } + inline void set_cs_specified(In_C_you_should_use_my_bool_instead() cs_specified) + { + m_cs_specified= cs_specified; + } +private: + In_C_you_should_use_my_bool_instead() m_cs_specified; +}; +class Item_static_string_func :public Item_string +{ + const char *func_name; +public: + Item_static_string_func(const char *name_par, const char *str, uint length, + CHARSET_INFO *cs, + Derivation dv= DERIVATION_COERCIBLE) + :Item_string((char *) 0, str, length, cs, dv), func_name(name_par) + {} + Item *safe_charset_converter(CHARSET_INFO *tocs); + virtual inline void print(String *str, enum_query_type query_type) + { + str->append(func_name); + } + In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) {return (1);} +}; +class Item_partition_func_safe_string: public Item_string +{ +public: + Item_partition_func_safe_string(const char *name, uint length, + CHARSET_INFO *cs= NULL): + Item_string(name, length, cs) + {} +}; +class Item_return_date_time :public Item_partition_func_safe_string +{ + enum_field_types date_time_field_type; +public: + Item_return_date_time(const char *name_arg, enum_field_types field_type_arg) + :Item_partition_func_safe_string(name_arg, 0, &my_charset_bin), + date_time_field_type(field_type_arg) + { } + enum_field_types field_type() const { return date_time_field_type; } +}; +class Item_blob :public Item_partition_func_safe_string +{ +public: + Item_blob(const char *name, uint length) : + Item_partition_func_safe_string(name, length, &my_charset_bin) + { max_length= length; } + enum Type type() const { return TYPE_HOLDER; } + enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } +}; +class Item_empty_string :public Item_partition_func_safe_string +{ +public: + Item_empty_string(const char *header,uint length, CHARSET_INFO *cs= NULL) : + Item_partition_func_safe_string("",0, cs ? cs : &my_charset_utf8_general_ci) + { name=(char*) header; max_length= cs ? length * cs->mbmaxlen : length; } + void make_field(Send_field *field); +}; +class Item_return_int :public Item_int +{ + enum_field_types int_field_type; +public: + Item_return_int(const char *name_arg, uint length, + enum_field_types field_type_arg, longlong value= 0) + :Item_int(name_arg, value, length), int_field_type(field_type_arg) + { + unsigned_flag=1; + } + enum_field_types field_type() const { return int_field_type; } +}; +class Item_hex_string: public Item_basic_constant +{ +public: + Item_hex_string() {} + Item_hex_string(const char *str,uint str_length); + enum Type type() const { return VARBIN_ITEM; } + double val_real() + { + assert(fixed == 1); + return (double) (ulonglong) Item_hex_string::val_int(); + } + longlong val_int(); + In_C_you_should_use_my_bool_instead() basic_const_item() const { return 1; } + String *val_str(String*) { assert(fixed == 1); return &str_value; } + my_decimal *val_decimal(my_decimal *); + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); + enum Item_result result_type () const { return STRING_RESULT; } + enum Item_result cast_to_int_type() const { return INT_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } + virtual void print(String *str, enum_query_type query_type); + In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const; + virtual Item *safe_charset_converter(CHARSET_INFO *tocs); + In_C_you_should_use_my_bool_instead() check_partition_func_processor(uchar *int_arg) {return (0);} +}; +class Item_bin_string: public Item_hex_string +{ +public: + Item_bin_string(const char *str,uint str_length); +}; +class Item_result_field :public Item +{ +public: + Field *result_field; + Item_result_field() :result_field(0) {} + Item_result_field(THD *thd, Item_result_field *item): + Item(thd, item), result_field(item->result_field) + {} + ~Item_result_field() {} + Field *get_tmp_table_field() { return result_field; } + Field *tmp_table_field(TABLE *t_arg) { return result_field; } + table_map used_tables() const { return 1; } + virtual void fix_length_and_dec()=0; + void set_result_field(Field *field) { result_field= field; } + In_C_you_should_use_my_bool_instead() is_result_field() { return 1; } + void save_in_result_field(In_C_you_should_use_my_bool_instead() no_conversions) + { + save_in_field(result_field, no_conversions); + } + void cleanup(); +}; +class Item_ref :public Item_ident +{ +protected: + void set_properties(); +public: + enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF }; + Field *result_field; + Item **ref; + Item_ref(Name_resolution_context *context_arg, + const char *db_arg, const char *table_name_arg, + const char *field_name_arg) + :Item_ident(context_arg, db_arg, table_name_arg, field_name_arg), + result_field(0), ref(0) {} + Item_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, const char *field_name_arg, + In_C_you_should_use_my_bool_instead() alias_name_used_arg= (0)); + Item_ref(THD *thd, Item_ref *item) + :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {} + enum Type type() const { return REF_ITEM; } + In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const + { + Item *it= ((Item *) item)->real_item(); + return ref && (*ref)->eq(it, binary_cmp); + } + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); + In_C_you_should_use_my_bool_instead() val_bool(); + String *val_str(String* tmp); + In_C_you_should_use_my_bool_instead() is_null(); + In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate); + double val_result(); + longlong val_int_result(); + String *str_result(String* tmp); + my_decimal *val_decimal_result(my_decimal *); + In_C_you_should_use_my_bool_instead() val_bool_result(); + In_C_you_should_use_my_bool_instead() send(Protocol *prot, String *tmp); + void make_field(Send_field *field); + In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **); + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); + void save_org_in_field(Field *field); + enum Item_result result_type () const { return (*ref)->result_type(); } + enum_field_types field_type() const { return (*ref)->field_type(); } + Field *get_tmp_table_field() + { return result_field ? result_field : (*ref)->get_tmp_table_field(); } + Item *get_tmp_table_item(THD *thd); + table_map used_tables() const + { + return depended_from ? (((table_map) 1) << (sizeof(table_map)*8-2)) : (*ref)->used_tables(); + } + void update_used_tables() + { + if (!depended_from) + (*ref)->update_used_tables(); + } + table_map not_null_tables() const { return (*ref)->not_null_tables(); } + void set_result_field(Field *field) { result_field= field; } + In_C_you_should_use_my_bool_instead() is_result_field() { return 1; } + void save_in_result_field(In_C_you_should_use_my_bool_instead() no_conversions) + { + (*ref)->save_in_field(result_field, no_conversions); + } + Item *real_item() + { + return ref ? (*ref)->real_item() : this; + } + In_C_you_should_use_my_bool_instead() walk(Item_processor processor, In_C_you_should_use_my_bool_instead() walk_subquery, uchar *arg) + { return (*ref)->walk(processor, walk_subquery, arg); } + virtual void print(String *str, enum_query_type query_type); + In_C_you_should_use_my_bool_instead() result_as_longlong() + { + return (*ref)->result_as_longlong(); + } + void cleanup(); + Item_field *filed_for_view_update() + { return (*ref)->filed_for_view_update(); } + virtual Ref_Type ref_type() { return REF; } + uint cols() + { + return ref && result_type() == ROW_RESULT ? (*ref)->cols() : 1; + } + Item* element_index(uint i) + { + return ref && result_type() == ROW_RESULT ? (*ref)->element_index(i) : this; + } + Item** addr(uint i) + { + return ref && result_type() == ROW_RESULT ? (*ref)->addr(i) : 0; + } + In_C_you_should_use_my_bool_instead() check_cols(uint c) + { + return ref && result_type() == ROW_RESULT ? (*ref)->check_cols(c) + : Item::check_cols(c); + } + In_C_you_should_use_my_bool_instead() null_inside() + { + return ref && result_type() == ROW_RESULT ? (*ref)->null_inside() : 0; + } + void bring_value() + { + if (ref && result_type() == ROW_RESULT) + (*ref)->bring_value(); + } +}; +class Item_direct_ref :public Item_ref +{ +public: + Item_direct_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, + const char *field_name_arg, + In_C_you_should_use_my_bool_instead() alias_name_used_arg= (0)) + :Item_ref(context_arg, item, table_name_arg, + field_name_arg, alias_name_used_arg) + {} + Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {} + double val_real(); + longlong val_int(); + String *val_str(String* tmp); + my_decimal *val_decimal(my_decimal *); + In_C_you_should_use_my_bool_instead() val_bool(); + In_C_you_should_use_my_bool_instead() is_null(); + In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime,uint fuzzydate); + virtual Ref_Type ref_type() { return DIRECT_REF; } +}; +class Item_direct_view_ref :public Item_direct_ref +{ +public: + Item_direct_view_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, + const char *field_name_arg) + :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg) {} + Item_direct_view_ref(THD *thd, Item_direct_ref *item) + :Item_direct_ref(thd, item) {} + In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **); + In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const; + Item *get_tmp_table_item(THD *thd) + { + Item *item= Item_ref::get_tmp_table_item(thd); + item->name= name; + return item; + } + virtual Ref_Type ref_type() { return VIEW_REF; } +}; +class Item_sum; +class Item_outer_ref :public Item_direct_ref +{ +public: + Item *outer_ref; + Item_sum *in_sum_func; + In_C_you_should_use_my_bool_instead() found_in_select_list; + 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_ref(outer_field_arg), in_sum_func(0), + found_in_select_list(0) + { + ref= &outer_ref; + set_properties(); + fixed= 0; + } + Item_outer_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, const char *field_name_arg, + In_C_you_should_use_my_bool_instead() alias_name_used_arg) + :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg, + alias_name_used_arg), + outer_ref(0), in_sum_func(0), found_in_select_list(1) + {} + void save_in_result_field(In_C_you_should_use_my_bool_instead() no_conversions) + { + outer_ref->save_org_in_field(result_field); + } + In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **); + table_map used_tables() const + { + return (*ref)->const_item() ? 0 : (((table_map) 1) << (sizeof(table_map)*8-2)); + } + virtual Ref_Type ref_type() { return OUTER_REF; } +}; +class Item_in_subselect; +class Item_ref_null_helper: public Item_ref +{ +protected: + Item_in_subselect* owner; +public: + Item_ref_null_helper(Name_resolution_context *context_arg, + Item_in_subselect* master, Item **item, + const char *table_name_arg, const char *field_name_arg) + :Item_ref(context_arg, item, table_name_arg, field_name_arg), + owner(master) {} + double val_real(); + longlong val_int(); + String* val_str(String* s); + my_decimal *val_decimal(my_decimal *); + In_C_you_should_use_my_bool_instead() val_bool(); + In_C_you_should_use_my_bool_instead() get_date(MYSQL_TIME *ltime, uint fuzzydate); + virtual void print(String *str, enum_query_type query_type); + table_map used_tables() const + { + return (depended_from ? + (((table_map) 1) << (sizeof(table_map)*8-2)) : + (*ref)->used_tables() | (((table_map) 1) << (sizeof(table_map)*8-1))); + } +}; +class Item_int_with_ref :public Item_int +{ + Item *ref; +public: + Item_int_with_ref(longlong i, Item *ref_arg, my_bool unsigned_arg) : + Item_int(i), ref(ref_arg) + { + unsigned_flag= unsigned_arg; + } + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions) + { + return ref->save_in_field(field, no_conversions); + } + Item *clone_item(); + virtual Item *real_item() { return ref; } +}; +class Item_copy_string :public Item +{ + enum enum_field_types cached_field_type; +public: + Item *item; + Item_copy_string(Item *i) :item(i) + { + null_value=maybe_null=item->maybe_null; + decimals=item->decimals; + max_length=item->max_length; + name=item->name; + cached_field_type= item->field_type(); + } + enum Type type() const { return COPY_STR_ITEM; } + enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return cached_field_type; } + double val_real() + { + int err_not_used; + char *end_not_used; + return (null_value ? 0.0 : + ((str_value.charset())->cset->strntod((str_value.charset()),((char*) str_value.ptr()),(str_value.length()),(&end_not_used),(&err_not_used)))); + } + longlong val_int() + { + int err; + return null_value ? 0LL : ((str_value.charset())->cset->strntoll((str_value.charset()),(str_value.ptr()),(str_value.length()),(10),((char**) 0),(&err))); + } + String *val_str(String*); + my_decimal *val_decimal(my_decimal *); + void make_field(Send_field *field) { item->make_field(field); } + void copy(); + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions) + { + return save_str_value_in_field(field, &str_value); + } + table_map used_tables() const { return (table_map) 1L; } + In_C_you_should_use_my_bool_instead() const_item() const { return 0; } + In_C_you_should_use_my_bool_instead() is_null() { return null_value; } +}; +class Cached_item :public Sql_alloc +{ +public: + my_bool null_value; + Cached_item() :null_value(0) {} + virtual In_C_you_should_use_my_bool_instead() cmp(void)=0; + virtual ~Cached_item(); +}; +class Cached_item_str :public Cached_item +{ + Item *item; + String value,tmp_value; +public: + Cached_item_str(THD *thd, Item *arg); + In_C_you_should_use_my_bool_instead() cmp(void); + ~Cached_item_str(); +}; +class Cached_item_real :public Cached_item +{ + Item *item; + double value; +public: + Cached_item_real(Item *item_par) :item(item_par),value(0.0) {} + In_C_you_should_use_my_bool_instead() cmp(void); +}; +class Cached_item_int :public Cached_item +{ + Item *item; + longlong value; +public: + Cached_item_int(Item *item_par) :item(item_par),value(0) {} + In_C_you_should_use_my_bool_instead() cmp(void); +}; +class Cached_item_decimal :public Cached_item +{ + Item *item; + my_decimal value; +public: + Cached_item_decimal(Item *item_par); + In_C_you_should_use_my_bool_instead() cmp(void); +}; +class Cached_item_field :public Cached_item +{ + uchar *buff; + Field *field; + uint length; +public: + Cached_item_field(Item_field *item) + { + field= item->field; + buff= (uchar*) sql_calloc(length=field->pack_length()); + } + In_C_you_should_use_my_bool_instead() cmp(void); +}; +class Item_default_value : public Item_field +{ +public: + Item *arg; + Item_default_value(Name_resolution_context *context_arg) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(NULL) {} + Item_default_value(Name_resolution_context *context_arg, Item *a) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(a) {} + enum Type type() const { return DEFAULT_VALUE_ITEM; } + In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const; + In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **); + virtual void print(String *str, enum_query_type query_type); + int save_in_field(Field *field_arg, In_C_you_should_use_my_bool_instead() no_conversions); + table_map used_tables() const { return (table_map)0L; } + In_C_you_should_use_my_bool_instead() walk(Item_processor processor, In_C_you_should_use_my_bool_instead() walk_subquery, uchar *args) + { + return arg->walk(processor, walk_subquery, args) || + (this->*processor)(args); + } + Item *transform(Item_transformer transformer, uchar *args); +}; +class Item_insert_value : public Item_field +{ +public: + Item *arg; + Item_insert_value(Name_resolution_context *context_arg, Item *a) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(a) {} + In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const; + In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **); + virtual void print(String *str, enum_query_type query_type); + int save_in_field(Field *field_arg, In_C_you_should_use_my_bool_instead() no_conversions) + { + return Item_field::save_in_field(field_arg, no_conversions); + } + table_map used_tables() const { return (((table_map) 1) << (sizeof(table_map)*8-1)); } + In_C_you_should_use_my_bool_instead() walk(Item_processor processor, In_C_you_should_use_my_bool_instead() walk_subquery, uchar *args) + { + return arg->walk(processor, walk_subquery, args) || + (this->*processor)(args); + } +}; +enum trg_action_time_type +{ + TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX +}; +class Table_triggers_list; +class Item_trigger_field : public Item_field, + private Settable_routine_parameter +{ +public: + enum row_version_type {OLD_ROW, NEW_ROW}; + row_version_type row_version; + Item_trigger_field *next_trg_field; + uint field_idx; + Table_triggers_list *triggers; + Item_trigger_field(Name_resolution_context *context_arg, + row_version_type row_ver_arg, + const char *field_name_arg, + ulong priv, const In_C_you_should_use_my_bool_instead() ro) + :Item_field(context_arg, + (const char *)NULL, (const char *)NULL, field_name_arg), + row_version(row_ver_arg), field_idx((uint)-1), original_privilege(priv), + want_privilege(priv), table_grants(NULL), read_only (ro) + {} + void setup_field(THD *thd, TABLE *table, GRANT_INFO *table_grant_info); + enum Type type() const { return TRIGGER_FIELD_ITEM; } + In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const; + In_C_you_should_use_my_bool_instead() fix_fields(THD *, Item **); + virtual void print(String *str, enum_query_type query_type); + 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: + void set_required_privilege(In_C_you_should_use_my_bool_instead() rw); + In_C_you_should_use_my_bool_instead() set_value(THD *thd, sp_rcontext *ctx, Item **it); +public: + Settable_routine_parameter *get_settable_routine_parameter() + { + return (read_only ? 0 : this); + } + In_C_you_should_use_my_bool_instead() set_value(THD *thd, Item **it) + { + return set_value(thd, NULL, it); + } +private: + ulong original_privilege; + ulong want_privilege; + GRANT_INFO *table_grants; + In_C_you_should_use_my_bool_instead() read_only; +}; +class Item_cache: public Item_basic_constant +{ +protected: + Item *example; + table_map used_table_map; + Field *cached_field; + enum enum_field_types cached_field_type; +public: + Item_cache(): + example(0), used_table_map(0), cached_field(0), cached_field_type(MYSQL_TYPE_STRING) + { + fixed= 1; + null_value= 1; + } + Item_cache(enum_field_types field_type_arg): + example(0), used_table_map(0), cached_field(0), cached_field_type(field_type_arg) + { + fixed= 1; + null_value= 1; + } + void set_used_tables(table_map map) { used_table_map= map; } + virtual In_C_you_should_use_my_bool_instead() allocate(uint i) { return 0; } + virtual In_C_you_should_use_my_bool_instead() setup(Item *item) + { + example= item; + max_length= item->max_length; + decimals= item->decimals; + collation.set(item->collation); + unsigned_flag= item->unsigned_flag; + if (item->type() == FIELD_ITEM) + cached_field= ((Item_field *)item)->field; + return 0; + }; + virtual void store(Item *)= 0; + enum Type type() const { return CACHE_ITEM; } + enum_field_types field_type() const { return cached_field_type; } + static Item_cache* get_cache(const Item *item); + table_map used_tables() const { return used_table_map; } + virtual void keep_array() {} + virtual void print(String *str, enum_query_type query_type); + In_C_you_should_use_my_bool_instead() eq_def(Field *field) + { + return cached_field ? cached_field->eq_def (field) : (0); + } + In_C_you_should_use_my_bool_instead() eq(const Item *item, In_C_you_should_use_my_bool_instead() binary_cmp) const + { + return this == item; + } +}; +class Item_cache_int: public Item_cache +{ +protected: + longlong value; +public: + Item_cache_int(): Item_cache(), value(0) {} + Item_cache_int(enum_field_types field_type_arg): + Item_cache(field_type_arg), value(0) {} + void store(Item *item); + void store(Item *item, longlong val_arg); + double val_real() { assert(fixed == 1); return (double) value; } + longlong val_int() { assert(fixed == 1); return value; } + String* val_str(String *str); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type() const { return INT_RESULT; } + In_C_you_should_use_my_bool_instead() result_as_longlong() { return (1); } +}; +class Item_cache_real: public Item_cache +{ + double value; +public: + Item_cache_real(): Item_cache(), value(0) {} + void store(Item *item); + double val_real() { assert(fixed == 1); return value; } + longlong val_int(); + String* val_str(String *str); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type() const { return REAL_RESULT; } +}; +class Item_cache_decimal: public Item_cache +{ +protected: + my_decimal decimal_value; +public: + Item_cache_decimal(): Item_cache() {} + void store(Item *item); + double val_real(); + longlong val_int(); + String* val_str(String *str); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type() const { return DECIMAL_RESULT; } +}; +class Item_cache_str: public Item_cache +{ + char buffer[80]; + String *value, value_buff; + In_C_you_should_use_my_bool_instead() is_varbinary; +public: + Item_cache_str(const Item *item) : + Item_cache(), value(0), + is_varbinary(item->type() == FIELD_ITEM && + ((const Item_field *) item)->field->type() == + MYSQL_TYPE_VARCHAR && + !((const Item_field *) item)->field->has_charset()) + {} + void store(Item *item); + double val_real(); + longlong val_int(); + String* val_str(String *) { assert(fixed == 1); return value; } + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type() const { return STRING_RESULT; } + CHARSET_INFO *charset() const { return value->charset(); }; + int save_in_field(Field *field, In_C_you_should_use_my_bool_instead() no_conversions); +}; +class Item_cache_row: public Item_cache +{ + Item_cache **values; + uint item_count; + In_C_you_should_use_my_bool_instead() save_array; +public: + Item_cache_row() + :Item_cache(), values(0), item_count(2), save_array(0) {} + In_C_you_should_use_my_bool_instead() allocate(uint num); + In_C_you_should_use_my_bool_instead() setup(Item *item); + void store(Item *item); + void illegal_method_call(const char *); + void make_field(Send_field *) + { + illegal_method_call((const char*)"make_field"); + }; + double val_real() + { + illegal_method_call((const char*)"val"); + return 0; + }; + longlong val_int() + { + illegal_method_call((const char*)"val_int"); + return 0; + }; + String *val_str(String *) + { + illegal_method_call((const char*)"val_str"); + return 0; + }; + my_decimal *val_decimal(my_decimal *val) + { + illegal_method_call((const char*)"val_decimal"); + return 0; + }; + enum Item_result result_type() const { return ROW_RESULT; } + uint cols() { return item_count; } + Item *element_index(uint i) { return values[i]; } + Item **addr(uint i) { return (Item **) (values + i); } + In_C_you_should_use_my_bool_instead() check_cols(uint c); + In_C_you_should_use_my_bool_instead() null_inside(); + void bring_value(); + void keep_array() { save_array= 1; } + void cleanup() + { + const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("Item_cache_row::cleanup","./sql/item.h",2898,&_db_func_,&_db_file_,&_db_level_, &_db_framep_); + Item_cache::cleanup(); + if (save_array) + bzero(values, item_count*sizeof(Item**)); + else + values= 0; + do {_db_return_ (2904, &_db_func_, &_db_file_, &_db_level_); return;} while(0); + } +}; +class Item_type_holder: public Item +{ +protected: + TYPELIB *enum_set_typelib; + enum_field_types fld_type; + Field::geometry_type geometry_type; + void get_full_info(Item *item); + int prev_decimal_int_part; +public: + Item_type_holder(THD*, Item*); + Item_result result_type() const; + enum_field_types field_type() const { return fld_type; }; + enum Type type() const { return TYPE_HOLDER; } + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); + String *val_str(String*); + In_C_you_should_use_my_bool_instead() join_types(THD *thd, Item *); + Field *make_field_by_type(TABLE *table); + static uint32 display_length(Item *item); + static enum_field_types get_real_type(Item *); + Field::geometry_type get_geometry_type() const { return geometry_type; }; +}; +class st_select_lex; +void mark_select_range_as_dependent(THD *thd, + st_select_lex *last_select, + st_select_lex *current_sel, + Field *found_field, Item *found_item, + Item_ident *resolved_item); +extern Cached_item *new_Cached_item(THD *thd, Item *item); +extern Item_result item_cmp_type(Item_result a,Item_result b); +extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item); +extern In_C_you_should_use_my_bool_instead() field_is_equal_to_item(Field *field,Item *item); +extern my_decimal decimal_zero; +void free_items(Item *item); +void cleanup_items(Item *item); +class THD; +void close_thread_tables(THD *thd); +In_C_you_should_use_my_bool_instead() check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables); +In_C_you_should_use_my_bool_instead() check_single_table_access(THD *thd, ulong privilege, + TABLE_LIST *tables, In_C_you_should_use_my_bool_instead() no_errors); +In_C_you_should_use_my_bool_instead() check_routine_access(THD *thd,ulong want_access,char *db,char *name, + In_C_you_should_use_my_bool_instead() is_proc, In_C_you_should_use_my_bool_instead() no_errors); +In_C_you_should_use_my_bool_instead() check_some_access(THD *thd, ulong want_access, TABLE_LIST *table); +In_C_you_should_use_my_bool_instead() check_some_routine_access(THD *thd, const char *db, const char *name, In_C_you_should_use_my_bool_instead() is_proc); +In_C_you_should_use_my_bool_instead() multi_update_precheck(THD *thd, TABLE_LIST *tables); +In_C_you_should_use_my_bool_instead() multi_delete_precheck(THD *thd, TABLE_LIST *tables); +int mysql_multi_update_prepare(THD *thd); +int mysql_multi_delete_prepare(THD *thd); +In_C_you_should_use_my_bool_instead() mysql_insert_select_prepare(THD *thd); +In_C_you_should_use_my_bool_instead() update_precheck(THD *thd, TABLE_LIST *tables); +In_C_you_should_use_my_bool_instead() delete_precheck(THD *thd, TABLE_LIST *tables); +In_C_you_should_use_my_bool_instead() insert_precheck(THD *thd, TABLE_LIST *tables); +In_C_you_should_use_my_bool_instead() create_table_precheck(THD *thd, TABLE_LIST *tables, + TABLE_LIST *create_table); +int append_query_string(CHARSET_INFO *csinfo, + String const *from, String *to); +void get_default_definer(THD *thd, LEX_USER *definer); +LEX_USER *create_default_definer(THD *thd); +LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name); +LEX_USER *get_current_user(THD *thd, LEX_USER *user); +In_C_you_should_use_my_bool_instead() check_string_byte_length(LEX_STRING *str, const char *err_msg, + uint max_byte_length); +In_C_you_should_use_my_bool_instead() check_string_char_length(LEX_STRING *str, const char *err_msg, + uint max_char_length, CHARSET_INFO *cs, + In_C_you_should_use_my_bool_instead() no_error); +In_C_you_should_use_my_bool_instead() test_if_data_home_dir(const char *dir); +In_C_you_should_use_my_bool_instead() parse_sql(THD *thd, + class Lex_input_stream *lip, + class Object_creation_ctx *creation_ctx); +enum enum_mysql_completiontype { + ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7, + COMMIT_RELEASE=-1, COMMIT=0, COMMIT_AND_CHAIN=6 +}; +In_C_you_should_use_my_bool_instead() begin_trans(THD *thd); +In_C_you_should_use_my_bool_instead() end_active_trans(THD *thd); +int end_trans(THD *thd, enum enum_mysql_completiontype completion); +Item *negate_expression(THD *thd, Item *expr); +int vprint_msg_to_log(enum loglevel level, const char *format, va_list args); +void sql_print_error(const char *format, ...) __attribute__((format(printf, 1, 2))); +void sql_print_warning(const char *format, ...) __attribute__((format(printf, 1, 2))); +void sql_print_information(const char *format, ...) + __attribute__((format(printf, 1, 2))); +typedef void (*sql_print_message_func)(const char *format, ...) + __attribute__((format(printf, 1, 2))); +extern sql_print_message_func sql_print_message_handlers[]; +int error_log_print(enum loglevel level, const char *format, + va_list args); +In_C_you_should_use_my_bool_instead() slow_log_print(THD *thd, const char *query, uint query_length, + ulonglong current_utime); +In_C_you_should_use_my_bool_instead() general_log_print(THD *thd, enum enum_server_command command, + const char *format,...); +In_C_you_should_use_my_bool_instead() general_log_write(THD *thd, enum enum_server_command command, + const char *query, uint query_length); +#include "sql_class.h" +#include "log.h" +class Relay_log_info; +class Format_description_log_event; +class TC_LOG +{ + public: + int using_heuristic_recover(); + TC_LOG() {} + virtual ~TC_LOG() {} + virtual int open(const char *opt_name)=0; + virtual void close()=0; + virtual int log_xid(THD *thd, my_xid xid)=0; + virtual void unlog(ulong cookie, my_xid xid)=0; +}; +class TC_LOG_DUMMY: public TC_LOG +{ +public: + TC_LOG_DUMMY() {} + int open(const char *opt_name) { return 0; } + void close() { } + int log_xid(THD *thd, my_xid xid) { return 1; } + void unlog(ulong cookie, my_xid xid) { } +}; +class TC_LOG_MMAP: public TC_LOG +{ + public: + typedef enum { + POOL, + ERROR, + DIRTY + } PAGE_STATE; + private: + typedef struct st_page { + struct st_page *next; + my_xid *start, *end; + my_xid *ptr; + int size, free; + int waiters; + PAGE_STATE state; + pthread_mutex_t lock; + pthread_cond_t cond; + } PAGE; + char logname[512]; + File fd; + my_off_t file_length; + uint npages, inited; + uchar *data; + struct st_page *pages, *syncing, *active, *pool, *pool_last; + pthread_mutex_t LOCK_active, LOCK_pool, LOCK_sync; + pthread_cond_t COND_pool, COND_active; + public: + TC_LOG_MMAP(): inited(0) {} + int open(const char *opt_name); + void close(); + int log_xid(THD *thd, my_xid xid); + void unlog(ulong cookie, my_xid xid); + int recover(); + private: + void get_active_from_pool(); + int sync(); + int overflow(); +}; +extern TC_LOG *tc_log; +extern TC_LOG_MMAP tc_log_mmap; +extern TC_LOG_DUMMY tc_log_dummy; +class Relay_log_info; +typedef struct st_log_info +{ + char log_file_name[512]; + my_off_t index_file_offset, index_file_start_offset; + my_off_t pos; + In_C_you_should_use_my_bool_instead() fatal; + pthread_mutex_t lock; + st_log_info() + : index_file_offset(0), index_file_start_offset(0), + pos(0), fatal(0) + { + log_file_name[0] = '\0'; + pthread_mutex_init(&lock, NULL); + } + ~st_log_info() { pthread_mutex_destroy(&lock);} +} LOG_INFO; +class Log_event; +class Rows_log_event; +enum enum_log_type { LOG_UNKNOWN, LOG_NORMAL, LOG_BIN }; +enum enum_log_state { LOG_OPENED, LOG_CLOSED, LOG_TO_BE_OPENED }; +class MYSQL_LOG +{ +public: + MYSQL_LOG(); + void init_pthread_objects(); + void cleanup(); + In_C_you_should_use_my_bool_instead() open(const char *log_name, + enum_log_type log_type, + const char *new_name, + enum cache_type io_cache_type_arg); + void init(enum_log_type log_type_arg, + enum cache_type io_cache_type_arg); + void close(uint exiting); + inline In_C_you_should_use_my_bool_instead() is_open() { return log_state != LOG_CLOSED; } + const char *generate_name(const char *log_name, const char *suffix, + In_C_you_should_use_my_bool_instead() strip_ext, char *buff); + int generate_new_name(char *new_name, const char *log_name); + protected: + pthread_mutex_t LOCK_log; + char *name; + char log_file_name[512]; + char time_buff[20], db[(64*3) + 1]; + In_C_you_should_use_my_bool_instead() write_error, inited; + IO_CACHE log_file; + enum_log_type log_type; + volatile enum_log_state log_state; + enum cache_type io_cache_type; + friend class Log_event; +}; +class MYSQL_QUERY_LOG: public MYSQL_LOG +{ +public: + MYSQL_QUERY_LOG() : last_time(0) {} + void reopen_file(); + In_C_you_should_use_my_bool_instead() write(time_t event_time, const char *user_host, + uint user_host_len, int thread_id, + const char *command_type, uint command_type_len, + const char *sql_text, uint sql_text_len); + In_C_you_should_use_my_bool_instead() write(THD *thd, time_t current_time, time_t query_start_arg, + const char *user_host, uint user_host_len, + ulonglong query_utime, ulonglong lock_utime, In_C_you_should_use_my_bool_instead() is_command, + const char *sql_text, uint sql_text_len); + In_C_you_should_use_my_bool_instead() open_slow_log(const char *log_name) + { + char buf[512]; + return open(generate_name(log_name, "-slow.log", 0, buf), LOG_NORMAL, 0, + WRITE_CACHE); + } + In_C_you_should_use_my_bool_instead() open_query_log(const char *log_name) + { + char buf[512]; + return open(generate_name(log_name, ".log", 0, buf), LOG_NORMAL, 0, + WRITE_CACHE); + } +private: + time_t last_time; +}; +class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG +{ + private: + pthread_mutex_t LOCK_index; + pthread_mutex_t LOCK_prep_xids; + pthread_cond_t COND_prep_xids; + pthread_cond_t update_cond; + ulonglong bytes_written; + IO_CACHE index_file; + char index_file_name[512]; + ulong max_size; + long prepared_xids; + uint file_id; + uint open_count; + int readers_count; + In_C_you_should_use_my_bool_instead() need_start_event; + In_C_you_should_use_my_bool_instead() no_auto_events; + ulonglong m_table_map_version; + int write_to_file(IO_CACHE *cache); + void new_file_without_locking(); + void new_file_impl(In_C_you_should_use_my_bool_instead() need_lock); +public: + MYSQL_LOG::generate_name; + MYSQL_LOG::is_open; + Format_description_log_event *description_event_for_exec, + *description_event_for_queue; + MYSQL_BIN_LOG(); + int open(const char *opt_name); + void close(); + 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); + In_C_you_should_use_my_bool_instead() is_table_mapped(TABLE *table) const + { + return table->s->table_map_version == table_map_version(); + } + ulonglong table_map_version() const { return m_table_map_version; } + void update_table_map_version() { ++m_table_map_version; } + int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event); + void reset_bytes_written() + { + bytes_written = 0; + } + void harvest_bytes_written(ulonglong* counter) + { + char buf1[22],buf2[22]; + const char *_db_func_, *_db_file_; uint _db_level_; char **_db_framep_; _db_enter_ ("harvest_bytes_written","./sql/log.h",321,&_db_func_,&_db_file_,&_db_level_, &_db_framep_); + (*counter)+=bytes_written; + do {_db_pargs_(324,"info"); _db_doprnt_ ("counter: %s bytes_written: %s", llstr(*counter,buf1), llstr(bytes_written,buf2));} while(0); + bytes_written=0; + do {_db_return_ (326, &_db_func_, &_db_file_, &_db_level_); return;} while(0); + } + void set_max_size(ulong max_size_arg); + void signal_update(); + void wait_for_update(THD* thd, In_C_you_should_use_my_bool_instead() master_or_slave); + void set_need_start_event() { need_start_event = 1; } + void init(In_C_you_should_use_my_bool_instead() no_auto_events_arg, ulong max_size); + void init_pthread_objects(); + void cleanup(); + In_C_you_should_use_my_bool_instead() open(const char *log_name, + enum_log_type log_type, + const char *new_name, + enum cache_type io_cache_type_arg, + In_C_you_should_use_my_bool_instead() no_auto_events_arg, ulong max_size, + In_C_you_should_use_my_bool_instead() null_created); + In_C_you_should_use_my_bool_instead() open_index_file(const char *index_file_name_arg, + const char *log_name); + void new_file(); + In_C_you_should_use_my_bool_instead() write(Log_event* event_info); + In_C_you_should_use_my_bool_instead() write(THD *thd, IO_CACHE *cache, Log_event *commit_event); + int write_cache(IO_CACHE *cache, In_C_you_should_use_my_bool_instead() lock_log, In_C_you_should_use_my_bool_instead() flush_and_sync); + void start_union_events(THD *thd, query_id_t query_id_param); + void stop_union_events(THD *thd); + In_C_you_should_use_my_bool_instead() is_query_in_union(THD *thd, query_id_t query_id_param); + In_C_you_should_use_my_bool_instead() appendv(const char* buf,uint len,...); + In_C_you_should_use_my_bool_instead() append(Log_event* ev); + void make_log_name(char* buf, const char* log_ident); + In_C_you_should_use_my_bool_instead() is_active(const char* log_file_name); + int update_log_index(LOG_INFO* linfo, In_C_you_should_use_my_bool_instead() need_update_threads); + void rotate_and_purge(uint flags); + In_C_you_should_use_my_bool_instead() flush_and_sync(); + int purge_logs(const char *to_log, In_C_you_should_use_my_bool_instead() included, + In_C_you_should_use_my_bool_instead() need_mutex, In_C_you_should_use_my_bool_instead() need_update_threads, + ulonglong *decrease_log_space); + int purge_logs_before_date(time_t purge_time); + int purge_first_log(Relay_log_info* rli, In_C_you_should_use_my_bool_instead() included); + In_C_you_should_use_my_bool_instead() reset_logs(THD* thd); + void close(uint exiting); + int find_log_pos(LOG_INFO* linfo, const char* log_name, + In_C_you_should_use_my_bool_instead() need_mutex); + int find_next_log(LOG_INFO* linfo, In_C_you_should_use_my_bool_instead() need_mutex); + int get_current_log(LOG_INFO* linfo); + int raw_get_current_log(LOG_INFO* linfo); + uint next_file_id(); + inline char* get_index_fname() { return index_file_name;} + inline char* get_log_fname() { return log_file_name; } + inline char* get_name() { return name; } + inline pthread_mutex_t* get_log_lock() { return &LOCK_log; } + inline IO_CACHE* get_log_file() { return &log_file; } + inline void lock_index() { pthread_mutex_lock(&LOCK_index);} + inline void unlock_index() { pthread_mutex_unlock(&LOCK_index);} + inline IO_CACHE *get_index_file() { return &index_file;} + inline uint32 get_open_count() { return open_count; } +}; +class Log_event_handler +{ +public: + Log_event_handler() {} + virtual In_C_you_should_use_my_bool_instead() init()= 0; + virtual void cleanup()= 0; + virtual In_C_you_should_use_my_bool_instead() log_slow(THD *thd, time_t current_time, + time_t query_start_arg, const char *user_host, + uint user_host_len, ulonglong query_utime, + ulonglong lock_utime, In_C_you_should_use_my_bool_instead() is_command, + const char *sql_text, uint sql_text_len)= 0; + virtual In_C_you_should_use_my_bool_instead() log_error(enum loglevel level, const char *format, + va_list args)= 0; + virtual In_C_you_should_use_my_bool_instead() log_general(THD *thd, time_t event_time, const char *user_host, + uint user_host_len, int thread_id, + const char *command_type, uint command_type_len, + const char *sql_text, uint sql_text_len, + CHARSET_INFO *client_cs)= 0; + virtual ~Log_event_handler() {} +}; +int check_if_log_table(uint db_len, const char *db, uint table_name_len, + const char *table_name, uint check_if_opened); +class Log_to_csv_event_handler: public Log_event_handler +{ + friend class LOGGER; +public: + Log_to_csv_event_handler(); + ~Log_to_csv_event_handler(); + virtual In_C_you_should_use_my_bool_instead() init(); + virtual void cleanup(); + virtual In_C_you_should_use_my_bool_instead() log_slow(THD *thd, time_t current_time, + time_t query_start_arg, const char *user_host, + uint user_host_len, ulonglong query_utime, + ulonglong lock_utime, In_C_you_should_use_my_bool_instead() is_command, + const char *sql_text, uint sql_text_len); + virtual In_C_you_should_use_my_bool_instead() log_error(enum loglevel level, const char *format, + va_list args); + virtual In_C_you_should_use_my_bool_instead() log_general(THD *thd, time_t event_time, const char *user_host, + uint user_host_len, int thread_id, + const char *command_type, uint command_type_len, + const char *sql_text, uint sql_text_len, + CHARSET_INFO *client_cs); + int activate_log(THD *thd, uint log_type); +}; +class Log_to_file_event_handler: public Log_event_handler +{ + MYSQL_QUERY_LOG mysql_log; + MYSQL_QUERY_LOG mysql_slow_log; + In_C_you_should_use_my_bool_instead() is_initialized; +public: + Log_to_file_event_handler(): is_initialized((0)) + {} + virtual In_C_you_should_use_my_bool_instead() init(); + virtual void cleanup(); + virtual In_C_you_should_use_my_bool_instead() log_slow(THD *thd, time_t current_time, + time_t query_start_arg, const char *user_host, + uint user_host_len, ulonglong query_utime, + ulonglong lock_utime, In_C_you_should_use_my_bool_instead() is_command, + const char *sql_text, uint sql_text_len); + virtual In_C_you_should_use_my_bool_instead() log_error(enum loglevel level, const char *format, + va_list args); + virtual In_C_you_should_use_my_bool_instead() log_general(THD *thd, time_t event_time, const char *user_host, + uint user_host_len, int thread_id, + const char *command_type, uint command_type_len, + const char *sql_text, uint sql_text_len, + CHARSET_INFO *client_cs); + void flush(); + void init_pthread_objects(); + MYSQL_QUERY_LOG *get_mysql_slow_log() { return &mysql_slow_log; } + MYSQL_QUERY_LOG *get_mysql_log() { return &mysql_log; } +}; +class LOGGER +{ + pthread_rwlock_t LOCK_logger; + uint inited; + Log_to_csv_event_handler *table_log_handler; + Log_to_file_event_handler *file_log_handler; + Log_event_handler *error_log_handler_list[3 + 1]; + Log_event_handler *slow_log_handler_list[3 + 1]; + Log_event_handler *general_log_handler_list[3 + 1]; +public: + In_C_you_should_use_my_bool_instead() is_log_tables_initialized; + LOGGER() : inited(0), table_log_handler(NULL), + file_log_handler(NULL), is_log_tables_initialized((0)) + {} + void lock_shared() { pthread_rwlock_rdlock(&LOCK_logger); } + void lock_exclusive() { pthread_rwlock_wrlock(&LOCK_logger); } + void unlock() { pthread_rwlock_unlock(&LOCK_logger); } + In_C_you_should_use_my_bool_instead() is_log_table_enabled(uint log_table_type); + In_C_you_should_use_my_bool_instead() log_command(THD *thd, enum enum_server_command command); + void init_base(); + void init_log_tables(); + In_C_you_should_use_my_bool_instead() flush_logs(THD *thd); + void cleanup_base(); + void cleanup_end(); + In_C_you_should_use_my_bool_instead() error_log_print(enum loglevel level, const char *format, + va_list args); + In_C_you_should_use_my_bool_instead() slow_log_print(THD *thd, const char *query, uint query_length, + ulonglong current_utime); + In_C_you_should_use_my_bool_instead() general_log_print(THD *thd,enum enum_server_command command, + const char *format, va_list args); + In_C_you_should_use_my_bool_instead() general_log_write(THD *thd, enum enum_server_command command, + const char *query, uint query_length); + int set_handlers(uint error_log_printer, + uint slow_log_printer, + uint general_log_printer); + void init_error_log(uint error_log_printer); + void init_slow_log(uint slow_log_printer); + void init_general_log(uint general_log_printer); + void deactivate_log_handler(THD* thd, uint log_type); + In_C_you_should_use_my_bool_instead() activate_log_handler(THD* thd, uint log_type); + MYSQL_QUERY_LOG *get_slow_log_file_handler() + { + if (file_log_handler) + return file_log_handler->get_mysql_slow_log(); + return NULL; + } + MYSQL_QUERY_LOG *get_log_file_handler() + { + if (file_log_handler) + return file_log_handler->get_mysql_log(); + return NULL; + } +}; +enum enum_binlog_format { + BINLOG_FORMAT_MIXED= 0, + BINLOG_FORMAT_STMT= 1, + BINLOG_FORMAT_ROW= 2, + BINLOG_FORMAT_UNSPEC= 3 +}; +extern TYPELIB binlog_format_typelib; +#include "rpl_tblmap.h" +struct st_table; +typedef st_table TABLE; +class table_mapping { +private: + MEM_ROOT m_mem_root; +public: + enum enum_error { + ERR_NO_ERROR = 0, + ERR_LIMIT_EXCEEDED, + ERR_MEMORY_ALLOCATION + }; + table_mapping(); + ~table_mapping(); + TABLE* get_table(ulong table_id); + int set_table(ulong table_id, TABLE* table); + int remove_table(ulong table_id); + void clear_tables(); + ulong count() const { return m_table_ids.records; } +private: + struct entry { + ulong table_id; + union { + TABLE *table; + entry *next; + }; + }; + entry *find_entry(ulong table_id) + { + return (entry *)hash_search(&m_table_ids, + (uchar*)&table_id, + sizeof(table_id)); + } + int expand(); + entry *m_free; + HASH m_table_ids; +}; +class Reprepare_observer +{ +public: + In_C_you_should_use_my_bool_instead() report_error(THD *thd); + In_C_you_should_use_my_bool_instead() is_invalidated() const { return m_invalidated; } + void reset_reprepare_observer() { m_invalidated= (0); } +private: + In_C_you_should_use_my_bool_instead() m_invalidated; +}; +class Relay_log_info; +class Query_log_event; +class Load_log_event; +class Slave_log_event; +class sp_rcontext; +class sp_cache; +class Lex_input_stream; +class Rows_log_event; +enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; +enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME }; +enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_UPDATE }; +enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON, + DELAY_KEY_WRITE_ALL }; +enum enum_slave_exec_mode { SLAVE_EXEC_MODE_STRICT, + SLAVE_EXEC_MODE_IDEMPOTENT, + SLAVE_EXEC_MODE_LAST_BIT}; +enum enum_mark_columns +{ MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE}; +extern char internal_table_name[2]; +extern char empty_c_string[1]; +extern const char **errmesg; +extern uint tc_heuristic_recover; +typedef struct st_user_var_events +{ + user_var_entry *user_var_event; + char *value; + ulong length; + Item_result type; + uint charset_number; +} BINLOG_USER_VAR_EVENT; +typedef struct st_copy_info { + ha_rows records; + ha_rows deleted; + ha_rows updated; + ha_rows copied; + ha_rows error_count; + ha_rows touched; + enum enum_duplicates handle_duplicates; + int escape_char, last_errno; + In_C_you_should_use_my_bool_instead() ignore; + List<Item> *update_fields; + List<Item> *update_values; + TABLE_LIST *view; +} COPY_INFO; +class Key_part_spec :public Sql_alloc { +public: + const char *field_name; + uint length; + Key_part_spec(const char *name,uint len=0) :field_name(name), length(len) {} + In_C_you_should_use_my_bool_instead() operator==(const Key_part_spec& other) const; + Key_part_spec *clone(MEM_ROOT *mem_root) const + { return new (mem_root) Key_part_spec(*this); } +}; +class Alter_drop :public Sql_alloc { +public: + enum drop_type {KEY, COLUMN }; + const char *name; + enum drop_type type; + Alter_drop(enum drop_type par_type,const char *par_name) + :name(par_name), type(par_type) {} + Alter_drop *clone(MEM_ROOT *mem_root) const + { return new (mem_root) Alter_drop(*this); } +}; +class Alter_column :public Sql_alloc { +public: + const char *name; + Item *def; + Alter_column(const char *par_name,Item *literal) + :name(par_name), def(literal) {} + Alter_column *clone(MEM_ROOT *mem_root) const + { return new (mem_root) Alter_column(*this); } +}; +class Key :public Sql_alloc { +public: + enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL, FOREIGN_KEY}; + enum Keytype type; + KEY_CREATE_INFO key_create_info; + List<Key_part_spec> columns; + const char *name; + In_C_you_should_use_my_bool_instead() generated; + Key(enum Keytype type_par, const char *name_arg, + KEY_CREATE_INFO *key_info_arg, + In_C_you_should_use_my_bool_instead() generated_arg, List<Key_part_spec> &cols) + :type(type_par), key_create_info(*key_info_arg), columns(cols), + name(name_arg), generated(generated_arg) + {} + Key(const Key &rhs, MEM_ROOT *mem_root); + virtual ~Key() {} + friend In_C_you_should_use_my_bool_instead() foreign_key_prefix(Key *a, Key *b); + virtual Key *clone(MEM_ROOT *mem_root) const + { return new (mem_root) Key(*this, mem_root); } +}; +class Table_ident; +class Foreign_key: public Key { +public: + enum fk_match_opt { FK_MATCH_UNDEF, FK_MATCH_FULL, + FK_MATCH_PARTIAL, FK_MATCH_SIMPLE}; + enum fk_option { FK_OPTION_UNDEF, FK_OPTION_RESTRICT, FK_OPTION_CASCADE, + FK_OPTION_SET_NULL, FK_OPTION_NO_ACTION, FK_OPTION_DEFAULT}; + Table_ident *ref_table; + List<Key_part_spec> ref_columns; + uint delete_opt, update_opt, match_opt; + Foreign_key(const char *name_arg, List<Key_part_spec> &cols, + Table_ident *table, List<Key_part_spec> &ref_cols, + uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg) + :Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols), + ref_table(table), ref_columns(ref_cols), + delete_opt(delete_opt_arg), update_opt(update_opt_arg), + match_opt(match_opt_arg) + {} + Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root); + virtual Key *clone(MEM_ROOT *mem_root) const + { return new (mem_root) Foreign_key(*this, mem_root); } +}; +typedef struct st_mysql_lock +{ + TABLE **table; + uint table_count,lock_count; + THR_LOCK_DATA **locks; +} MYSQL_LOCK; +class LEX_COLUMN : public Sql_alloc +{ +public: + String column; + uint rights; + LEX_COLUMN (const String& x,const uint& y ): column (x),rights (y) {} +}; +#include "sql_lex.h" +class Table_ident; +class sql_exchange; +class LEX_COLUMN; +class sp_head; +class sp_name; +class sp_instr; +class sp_pcontext; +class st_alter_tablespace; +class partition_info; +class Event_parse_data; +enum enum_sql_command { + SQLCOM_SELECT, SQLCOM_CREATE_TABLE, SQLCOM_CREATE_INDEX, SQLCOM_ALTER_TABLE, + SQLCOM_UPDATE, SQLCOM_INSERT, SQLCOM_INSERT_SELECT, + SQLCOM_DELETE, SQLCOM_TRUNCATE, SQLCOM_DROP_TABLE, SQLCOM_DROP_INDEX, + SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS, + SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_STATUS, + SQLCOM_SHOW_ENGINE_LOGS, SQLCOM_SHOW_ENGINE_STATUS, SQLCOM_SHOW_ENGINE_MUTEX, + SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, + SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS, + SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS, + SQLCOM_SHOW_TRIGGERS, + SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES, + SQLCOM_GRANT, + SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB, + SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT, + SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION, + SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, + SQLCOM_ASSIGN_TO_KEYCACHE, SQLCOM_PRELOAD_KEYS, + SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, + SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT, + SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_RELEASE_SAVEPOINT, + SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, + SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER, + SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE, + SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_PURGE_BEFORE, SQLCOM_SHOW_BINLOGS, + SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA, + SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ, + SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_UPDATE_MULTI, + SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO, + SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS, + SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES, + SQLCOM_HELP, SQLCOM_CREATE_USER, SQLCOM_DROP_USER, SQLCOM_RENAME_USER, + SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM, + SQLCOM_CREATE_PROCEDURE, SQLCOM_CREATE_SPFUNCTION, SQLCOM_CALL, + SQLCOM_DROP_PROCEDURE, SQLCOM_ALTER_PROCEDURE,SQLCOM_ALTER_FUNCTION, + SQLCOM_SHOW_CREATE_PROC, SQLCOM_SHOW_CREATE_FUNC, + SQLCOM_SHOW_STATUS_PROC, SQLCOM_SHOW_STATUS_FUNC, + SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE, + SQLCOM_CREATE_VIEW, SQLCOM_DROP_VIEW, + SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER, + SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE, + SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER, + SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE, + SQLCOM_ALTER_TABLESPACE, + SQLCOM_INSTALL_PLUGIN, SQLCOM_UNINSTALL_PLUGIN, + SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT, + SQLCOM_SHOW_PLUGINS, + SQLCOM_SHOW_CONTRIBUTORS, + SQLCOM_CREATE_SERVER, SQLCOM_DROP_SERVER, SQLCOM_ALTER_SERVER, + SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT, + SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS, + SQLCOM_SHOW_CREATE_TRIGGER, + SQLCOM_ALTER_DB_UPGRADE, + SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, + SQLCOM_END +}; +class Delayed_insert; +class select_result; +class Time_zone; +struct system_variables +{ + ulong dynamic_variables_version; + char* dynamic_variables_ptr; + uint dynamic_variables_head; + uint dynamic_variables_size; + ulonglong myisam_max_extra_sort_file_size; + ulonglong myisam_max_sort_file_size; + ulonglong max_heap_table_size; + ulonglong tmp_table_size; + ulonglong long_query_time; + ha_rows select_limit; + ha_rows max_join_size; + ulong auto_increment_increment, auto_increment_offset; + ulong bulk_insert_buff_size; + ulong join_buff_size; + ulong max_allowed_packet; + ulong max_error_count; + ulong max_length_for_sort_data; + ulong max_sort_length; + ulong max_tmp_tables; + ulong max_insert_delayed_threads; + ulong min_examined_row_limit; + ulong multi_range_count; + ulong myisam_repair_threads; + ulong myisam_sort_buff_size; + ulong myisam_stats_method; + ulong net_buffer_length; + ulong net_interactive_timeout; + ulong net_read_timeout; + ulong net_retry_count; + ulong net_wait_timeout; + ulong net_write_timeout; + ulong optimizer_prune_level; + ulong optimizer_search_depth; + ulong preload_buff_size; + ulong profiling_history_size; + ulong query_cache_type; + ulong read_buff_size; + ulong read_rnd_buff_size; + ulong div_precincrement; + ulong sortbuff_size; + ulong thread_handling; + ulong tx_isolation; + ulong completion_type; + ulong sql_mode; + ulong max_sp_recursion_depth; + ulong updatable_views_with_limit; + ulong default_week_format; + ulong max_seeks_for_key; + ulong range_alloc_block_size; + ulong query_alloc_block_size; + ulong query_prealloc_size; + ulong trans_alloc_block_size; + 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; + my_thread_id pseudo_thread_id; + my_bool low_priority_updates; + my_bool new_mode; + my_bool old_mode; + my_bool query_cache_wlock_invalidate; + my_bool engine_condition_pushdown; + my_bool keep_files_on_create; + my_bool ndb_force_send; + my_bool ndb_use_copying_alter_table; + my_bool ndb_use_exact_count; + my_bool ndb_use_transactions; + my_bool ndb_index_stat_enable; + my_bool old_alter_table; + my_bool old_passwords; + plugin_ref table_plugin; + CHARSET_INFO *character_set_filesystem; + CHARSET_INFO *character_set_client; + CHARSET_INFO *character_set_results; + CHARSET_INFO *collation_server; + CHARSET_INFO *collation_database; + CHARSET_INFO *collation_connection; + MY_LOCALE *lc_time_names; + Time_zone *time_zone; + DATE_TIME_FORMAT *date_format; + DATE_TIME_FORMAT *datetime_format; + DATE_TIME_FORMAT *time_format; + my_bool sysdate_is_now; +}; +typedef struct system_status_var +{ + ulonglong bytes_received; + ulonglong bytes_sent; + ulong com_other; + ulong com_stat[(uint) SQLCOM_END]; + ulong created_tmp_disk_tables; + ulong created_tmp_tables; + ulong ha_commit_count; + ulong ha_delete_count; + ulong ha_read_first_count; + ulong ha_read_last_count; + ulong ha_read_key_count; + ulong ha_read_next_count; + ulong ha_read_prev_count; + ulong ha_read_rnd_count; + ulong ha_read_rnd_next_count; + ulong ha_rollback_count; + ulong ha_update_count; + ulong ha_write_count; + ulong ha_prepare_count; + ulong ha_discover_count; + ulong ha_savepoint_count; + ulong ha_savepoint_rollback_count; + ulong key_blocks_changed; + ulong key_blocks_used; + ulong key_cache_r_requests; + ulong key_cache_read; + ulong key_cache_w_requests; + ulong key_cache_write; + ulong net_big_packet_count; + ulong opened_tables; + ulong opened_shares; + ulong select_full_join_count; + ulong select_full_range_join_count; + ulong select_range_count; + ulong select_range_check_count; + ulong select_scan_count; + ulong long_query_count; + ulong filesort_merge_passes; + ulong filesort_range_count; + ulong filesort_rows; + ulong filesort_scan_count; + ulong com_stmt_prepare; + ulong com_stmt_reprepare; + ulong com_stmt_execute; + ulong com_stmt_send_long_data; + ulong com_stmt_fetch; + ulong com_stmt_reset; + ulong com_stmt_close; + double last_query_cost; +} STATUS_VAR; +void mark_transaction_to_rollback(THD *thd, In_C_you_should_use_my_bool_instead() all); +#include "sql_acl.h" +#include "slave.h" +#include "log.h" +#include "my_list.h" +#include "rpl_filter.h" +#include "mysql.h" +#include "mysql_version.h" +#include "mysql_com.h" +#include "mysql_time.h" +#include "my_list.h" +extern unsigned int mysql_port; +extern char *mysql_unix_port; +typedef struct st_mysql_field { + char *name; + char *org_name; + char *table; + char *org_table; + char *db; + char *catalog; + char *def; + unsigned long length; + unsigned long max_length; + unsigned int name_length; + unsigned int org_name_length; + unsigned int table_length; + unsigned int org_table_length; + unsigned int db_length; + unsigned int catalog_length; + unsigned int def_length; + unsigned int flags; + unsigned int decimals; + unsigned int charsetnr; + enum enum_field_types type; + void *extension; +} MYSQL_FIELD; +typedef char **MYSQL_ROW; +typedef unsigned int MYSQL_FIELD_OFFSET; +#include "typelib.h" +typedef struct st_mysql_rows { + struct st_mysql_rows *next; + MYSQL_ROW data; + unsigned long length; +} MYSQL_ROWS; +typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; +#include "my_alloc.h" +typedef struct embedded_query_result EMBEDDED_QUERY_RESULT; +typedef struct st_mysql_data { + MYSQL_ROWS *data; + struct embedded_query_result *embedded_info; + MEM_ROOT alloc; + my_ulonglong rows; + unsigned int fields; + void *extension; +} MYSQL_DATA; +enum mysql_option +{ + MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, MYSQL_OPT_NAMED_PIPE, + MYSQL_INIT_COMMAND, MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, + MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_LOCAL_INFILE, + MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT, + MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT, + MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, + MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, + MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, + MYSQL_OPT_SSL_VERIFY_SERVER_CERT +}; +struct st_mysql_options { + unsigned int connect_timeout, read_timeout, write_timeout; + unsigned int port, protocol; + unsigned long client_flag; + char *host,*user,*password,*unix_socket,*db; + struct st_dynamic_array *init_commands; + char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name; + char *ssl_key; + char *ssl_cert; + char *ssl_ca; + char *ssl_capath; + char *ssl_cipher; + char *shared_memory_base_name; + unsigned long max_allowed_packet; + my_bool use_ssl; + my_bool compress,named_pipe; + my_bool rpl_probe; + my_bool rpl_parse; + my_bool no_master_reads; + my_bool separate_thread; + enum mysql_option methods_to_use; + char *client_ip; + my_bool secure_auth; + my_bool report_data_truncation; + int (*local_infile_init)(void **, const char *, void *); + int (*local_infile_read)(void *, char *, unsigned int); + void (*local_infile_end)(void *); + int (*local_infile_error)(void *, char *, unsigned int); + void *local_infile_userdata; + void *extension; +}; +enum mysql_status +{ + MYSQL_STATUS_READY,MYSQL_STATUS_GET_RESULT,MYSQL_STATUS_USE_RESULT +}; +enum mysql_protocol_type +{ + MYSQL_PROTOCOL_DEFAULT, MYSQL_PROTOCOL_TCP, MYSQL_PROTOCOL_SOCKET, + MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY +}; +enum mysql_rpl_type +{ + MYSQL_RPL_MASTER, MYSQL_RPL_SLAVE, MYSQL_RPL_ADMIN +}; +typedef struct character_set +{ + unsigned int number; + unsigned int state; + const char *csname; + const char *name; + const char *comment; + const char *dir; + unsigned int mbminlen; + unsigned int mbmaxlen; +} MY_CHARSET_INFO; +struct st_mysql_methods; +struct st_mysql_stmt; +typedef struct st_mysql +{ + NET net; + unsigned char *connector_fd; + char *host,*user,*passwd,*unix_socket,*server_version,*host_info; + char *info, *db; + struct charset_info_st *charset; + MYSQL_FIELD *fields; + MEM_ROOT field_alloc; + my_ulonglong affected_rows; + my_ulonglong insert_id; + my_ulonglong extra_info; + unsigned long thread_id; + unsigned long packet_length; + unsigned int port; + unsigned long client_flag,server_capabilities; + unsigned int protocol_version; + unsigned int field_count; + unsigned int server_status; + unsigned int server_language; + unsigned int warning_count; + struct st_mysql_options options; + enum mysql_status status; + my_bool free_me; + my_bool reconnect; + char scramble[20 +1]; + my_bool rpl_pivot; + struct st_mysql* master, *next_slave; + struct st_mysql* last_used_slave; + struct st_mysql* last_used_con; + LIST *stmts; + const struct st_mysql_methods *methods; + void *thd; + my_bool *unbuffered_fetch_owner; + char *info_buffer; + void *extension; +} MYSQL; +typedef struct st_mysql_res { + my_ulonglong row_count; + MYSQL_FIELD *fields; + MYSQL_DATA *data; + MYSQL_ROWS *data_cursor; + unsigned long *lengths; + MYSQL *handle; + const struct st_mysql_methods *methods; + MYSQL_ROW row; + MYSQL_ROW current_row; + MEM_ROOT field_alloc; + unsigned int field_count, current_field; + my_bool eof; + my_bool unbuffered_fetch_cancelled; + void *extension; +} MYSQL_RES; +typedef struct st_mysql_manager +{ + NET net; + char *host, *user, *passwd; + char *net_buf, *net_buf_pos, *net_data_end; + unsigned int port; + int cmd_status; + int last_errno; + int net_buf_size; + my_bool free_me; + my_bool eof; + char last_error[256]; + void *extension; +} MYSQL_MANAGER; +typedef struct st_mysql_parameters +{ + unsigned long *p_max_allowed_packet; + unsigned long *p_net_buffer_length; + void *extension; +} MYSQL_PARAMETERS; +int mysql_server_init(int argc, char **argv, char **groups); +void mysql_server_end(void); +MYSQL_PARAMETERS * mysql_get_parameters(void); +my_bool mysql_thread_init(void); +void mysql_thread_end(void); +my_ulonglong mysql_num_rows(MYSQL_RES *res); +unsigned int mysql_num_fields(MYSQL_RES *res); +my_bool mysql_eof(MYSQL_RES *res); +MYSQL_FIELD * mysql_fetch_field_direct(MYSQL_RES *res, + unsigned int fieldnr); +MYSQL_FIELD * mysql_fetch_fields(MYSQL_RES *res); +MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *res); +MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES *res); +unsigned int mysql_field_count(MYSQL *mysql); +my_ulonglong mysql_affected_rows(MYSQL *mysql); +my_ulonglong mysql_insert_id(MYSQL *mysql); +unsigned int mysql_errno(MYSQL *mysql); +const char * mysql_error(MYSQL *mysql); +const char * mysql_sqlstate(MYSQL *mysql); +unsigned int mysql_warning_count(MYSQL *mysql); +const char * mysql_info(MYSQL *mysql); +unsigned long mysql_thread_id(MYSQL *mysql); +const char * mysql_character_set_name(MYSQL *mysql); +int mysql_set_character_set(MYSQL *mysql, const char *csname); +MYSQL * mysql_init(MYSQL *mysql); +my_bool mysql_ssl_set(MYSQL *mysql, const char *key, + const char *cert, const char *ca, + const char *capath, const char *cipher); +const char * mysql_get_ssl_cipher(MYSQL *mysql); +my_bool mysql_change_user(MYSQL *mysql, const char *user, + const char *passwd, const char *db); +MYSQL * mysql_real_connect(MYSQL *mysql, const char *host, + const char *user, + const char *passwd, + const char *db, + unsigned int port, + const char *unix_socket, + unsigned long clientflag); +int mysql_select_db(MYSQL *mysql, const char *db); +int mysql_query(MYSQL *mysql, const char *q); +int mysql_send_query(MYSQL *mysql, const char *q, + unsigned long length); +int mysql_real_query(MYSQL *mysql, const char *q, + unsigned long length); +MYSQL_RES * mysql_store_result(MYSQL *mysql); +MYSQL_RES * mysql_use_result(MYSQL *mysql); +my_bool mysql_master_query(MYSQL *mysql, const char *q, + unsigned long length); +my_bool mysql_master_send_query(MYSQL *mysql, const char *q, + unsigned long length); +my_bool mysql_slave_query(MYSQL *mysql, const char *q, + unsigned long length); +my_bool mysql_slave_send_query(MYSQL *mysql, const char *q, + unsigned long length); +void mysql_get_character_set_info(MYSQL *mysql, + MY_CHARSET_INFO *charset); +void +mysql_set_local_infile_handler(MYSQL *mysql, + int (*local_infile_init)(void **, const char *, + void *), + int (*local_infile_read)(void *, char *, + unsigned int), + void (*local_infile_end)(void *), + int (*local_infile_error)(void *, char*, + unsigned int), + void *); +void +mysql_set_local_infile_default(MYSQL *mysql); +void mysql_enable_rpl_parse(MYSQL* mysql); +void mysql_disable_rpl_parse(MYSQL* mysql); +int mysql_rpl_parse_enabled(MYSQL* mysql); +void mysql_enable_reads_from_master(MYSQL* mysql); +void mysql_disable_reads_from_master(MYSQL* mysql); +my_bool mysql_reads_from_master_enabled(MYSQL* mysql); +enum mysql_rpl_type mysql_rpl_query_type(const char* q, int len); +my_bool mysql_rpl_probe(MYSQL* mysql); +int mysql_set_master(MYSQL* mysql, const char* host, + unsigned int port, + const char* user, + const char* passwd); +int mysql_add_slave(MYSQL* mysql, const char* host, + unsigned int port, + const char* user, + const char* passwd); +int mysql_shutdown(MYSQL *mysql, + enum mysql_enum_shutdown_level + shutdown_level); +int mysql_dump_debug_info(MYSQL *mysql); +int mysql_refresh(MYSQL *mysql, + unsigned int refresh_options); +int mysql_kill(MYSQL *mysql,unsigned long pid); +int mysql_set_server_option(MYSQL *mysql, + enum enum_mysql_set_option + option); +int mysql_ping(MYSQL *mysql); +const char * mysql_stat(MYSQL *mysql); +const char * mysql_get_server_info(MYSQL *mysql); +const char * mysql_get_client_info(void); +unsigned long mysql_get_client_version(void); +const char * mysql_get_host_info(MYSQL *mysql); +unsigned long mysql_get_server_version(MYSQL *mysql); +unsigned int mysql_get_proto_info(MYSQL *mysql); +MYSQL_RES * mysql_list_dbs(MYSQL *mysql,const char *wild); +MYSQL_RES * mysql_list_tables(MYSQL *mysql,const char *wild); +MYSQL_RES * mysql_list_processes(MYSQL *mysql); +int mysql_options(MYSQL *mysql,enum mysql_option option, + const void *arg); +void mysql_free_result(MYSQL_RES *result); +void mysql_data_seek(MYSQL_RES *result, + my_ulonglong offset); +MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result, + MYSQL_ROW_OFFSET offset); +MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, + MYSQL_FIELD_OFFSET offset); +MYSQL_ROW mysql_fetch_row(MYSQL_RES *result); +unsigned long * mysql_fetch_lengths(MYSQL_RES *result); +MYSQL_FIELD * mysql_fetch_field(MYSQL_RES *result); +MYSQL_RES * mysql_list_fields(MYSQL *mysql, const char *table, + const char *wild); +unsigned long mysql_escape_string(char *to,const char *from, + unsigned long from_length); +unsigned long mysql_hex_string(char *to,const char *from, + unsigned long from_length); +unsigned long mysql_real_escape_string(MYSQL *mysql, + char *to,const char *from, + unsigned long length); +void mysql_debug(const char *debug); +void myodbc_remove_escape(MYSQL *mysql,char *name); +unsigned int mysql_thread_safe(void); +my_bool mysql_embedded(void); +MYSQL_MANAGER* mysql_manager_init(MYSQL_MANAGER* con); +MYSQL_MANAGER* mysql_manager_connect(MYSQL_MANAGER* con, + const char* host, + const char* user, + const char* passwd, + unsigned int port); +void mysql_manager_close(MYSQL_MANAGER* con); +int mysql_manager_command(MYSQL_MANAGER* con, + const char* cmd, int cmd_len); +int mysql_manager_fetch_line(MYSQL_MANAGER* con, + char* res_buf, + int res_buf_size); +my_bool mysql_read_query_result(MYSQL *mysql); +enum enum_mysql_stmt_state +{ + MYSQL_STMT_INIT_DONE= 1, MYSQL_STMT_PREPARE_DONE, MYSQL_STMT_EXECUTE_DONE, + MYSQL_STMT_FETCH_DONE +}; +typedef struct st_mysql_bind +{ + unsigned long *length; + my_bool *is_null; + void *buffer; + my_bool *error; + unsigned char *row_ptr; + void (*store_param_func)(NET *net, struct st_mysql_bind *param); + void (*fetch_result)(struct st_mysql_bind *, MYSQL_FIELD *, + unsigned char **row); + void (*skip_result)(struct st_mysql_bind *, MYSQL_FIELD *, + unsigned char **row); + unsigned long buffer_length; + unsigned long offset; + unsigned long length_value; + unsigned int param_number; + unsigned int pack_length; + enum enum_field_types buffer_type; + my_bool error_value; + my_bool is_unsigned; + my_bool long_data_used; + my_bool is_null_value; + void *extension; +} MYSQL_BIND; +typedef struct st_mysql_stmt +{ + MEM_ROOT mem_root; + LIST list; + MYSQL *mysql; + MYSQL_BIND *params; + MYSQL_BIND *bind; + MYSQL_FIELD *fields; + MYSQL_DATA result; + MYSQL_ROWS *data_cursor; + int (*read_row_func)(struct st_mysql_stmt *stmt, + unsigned char **row); + my_ulonglong affected_rows; + my_ulonglong insert_id; + unsigned long stmt_id; + unsigned long flags; + unsigned long prefetch_rows; + unsigned int server_status; + unsigned int last_errno; + unsigned int param_count; + unsigned int field_count; + enum enum_mysql_stmt_state state; + char last_error[512]; + char sqlstate[5 +1]; + my_bool send_types_to_server; + my_bool bind_param_done; + unsigned char bind_result_done; + my_bool unbuffered_fetch_cancelled; + my_bool update_max_length; + void *extension; +} MYSQL_STMT; +enum enum_stmt_attr_type +{ + STMT_ATTR_UPDATE_MAX_LENGTH, + STMT_ATTR_CURSOR_TYPE, + STMT_ATTR_PREFETCH_ROWS +}; +typedef struct st_mysql_methods +{ + my_bool (*read_query_result)(MYSQL *mysql); + my_bool (*advanced_command)(MYSQL *mysql, + enum enum_server_command command, + const unsigned char *header, + unsigned long header_length, + const unsigned char *arg, + unsigned long arg_length, + my_bool skip_check, + MYSQL_STMT *stmt); + MYSQL_DATA *(*read_rows)(MYSQL *mysql,MYSQL_FIELD *mysql_fields, + unsigned int fields); + MYSQL_RES * (*use_result)(MYSQL *mysql); + void (*fetch_lengths)(unsigned long *to, + MYSQL_ROW column, unsigned int field_count); + void (*flush_use_result)(MYSQL *mysql); + MYSQL_FIELD * (*list_fields)(MYSQL *mysql); + my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt); + int (*stmt_execute)(MYSQL_STMT *stmt); + int (*read_binary_rows)(MYSQL_STMT *stmt); + int (*unbuffered_fetch)(MYSQL *mysql, char **row); + void (*free_embedded_thd)(MYSQL *mysql); + const char *(*read_statistics)(MYSQL *mysql); + my_bool (*next_result)(MYSQL *mysql); + int (*read_change_user_result)(MYSQL *mysql, char *buff, const char *passwd); + int (*read_rows_from_cursor)(MYSQL_STMT *stmt); +} MYSQL_METHODS; +MYSQL_STMT * mysql_stmt_init(MYSQL *mysql); +int mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, + unsigned long length); +int mysql_stmt_execute(MYSQL_STMT *stmt); +int mysql_stmt_fetch(MYSQL_STMT *stmt); +int mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind_arg, + unsigned int column, + unsigned long offset); +int mysql_stmt_store_result(MYSQL_STMT *stmt); +unsigned long mysql_stmt_param_count(MYSQL_STMT * stmt); +my_bool mysql_stmt_attr_set(MYSQL_STMT *stmt, + enum enum_stmt_attr_type attr_type, + const void *attr); +my_bool mysql_stmt_attr_get(MYSQL_STMT *stmt, + enum enum_stmt_attr_type attr_type, + void *attr); +my_bool mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +my_bool mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +my_bool mysql_stmt_close(MYSQL_STMT * stmt); +my_bool mysql_stmt_reset(MYSQL_STMT * stmt); +my_bool mysql_stmt_free_result(MYSQL_STMT *stmt); +my_bool mysql_stmt_send_long_data(MYSQL_STMT *stmt, + unsigned int param_number, + const char *data, + unsigned long length); +MYSQL_RES * mysql_stmt_result_metadata(MYSQL_STMT *stmt); +MYSQL_RES * mysql_stmt_param_metadata(MYSQL_STMT *stmt); +unsigned int mysql_stmt_errno(MYSQL_STMT * stmt); +const char * mysql_stmt_error(MYSQL_STMT * stmt); +const char * mysql_stmt_sqlstate(MYSQL_STMT * stmt); +MYSQL_ROW_OFFSET mysql_stmt_row_seek(MYSQL_STMT *stmt, + MYSQL_ROW_OFFSET offset); +MYSQL_ROW_OFFSET mysql_stmt_row_tell(MYSQL_STMT *stmt); +void mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong offset); +my_ulonglong mysql_stmt_num_rows(MYSQL_STMT *stmt); +my_ulonglong mysql_stmt_affected_rows(MYSQL_STMT *stmt); +my_ulonglong mysql_stmt_insert_id(MYSQL_STMT *stmt); +unsigned int mysql_stmt_field_count(MYSQL_STMT *stmt); +my_bool mysql_commit(MYSQL * mysql); +my_bool mysql_rollback(MYSQL * mysql); +my_bool mysql_autocommit(MYSQL * mysql, my_bool auto_mode); +my_bool mysql_more_results(MYSQL *mysql); +int mysql_next_result(MYSQL *mysql); +void mysql_close(MYSQL *sock); +typedef struct st_table_rule_ent +{ + char* db; + char* tbl_name; + uint key_len; +} TABLE_RULE_ENT; +class Rpl_filter +{ +public: + Rpl_filter(); + ~Rpl_filter(); + Rpl_filter(Rpl_filter const&); + Rpl_filter& operator=(Rpl_filter const&); + In_C_you_should_use_my_bool_instead() tables_ok(const char* db, TABLE_LIST* tables); + In_C_you_should_use_my_bool_instead() db_ok(const char* db); + In_C_you_should_use_my_bool_instead() db_ok_with_wild_table(const char *db); + In_C_you_should_use_my_bool_instead() is_on(); + int add_do_table(const char* table_spec); + int add_ignore_table(const char* table_spec); + int add_wild_do_table(const char* table_spec); + int add_wild_ignore_table(const char* table_spec); + void add_do_db(const char* db_spec); + void add_ignore_db(const char* db_spec); + void add_db_rewrite(const char* from_db, const char* to_db); + void get_do_table(String* str); + void get_ignore_table(String* str); + void get_wild_do_table(String* str); + void get_wild_ignore_table(String* str); + const char* get_rewrite_db(const char* db, size_t *new_len); + I_List<i_string>* get_do_db(); + I_List<i_string>* get_ignore_db(); +private: + In_C_you_should_use_my_bool_instead() table_rules_on; + void init_table_rule_hash(HASH* h, In_C_you_should_use_my_bool_instead()* h_inited); + void init_table_rule_array(DYNAMIC_ARRAY* a, In_C_you_should_use_my_bool_instead()* a_inited); + int add_table_rule(HASH* h, const char* table_spec); + int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec); + void free_string_array(DYNAMIC_ARRAY *a); + void table_rule_ent_hash_to_str(String* s, HASH* h, In_C_you_should_use_my_bool_instead() inited); + void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a, + In_C_you_should_use_my_bool_instead() inited); + TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len); + HASH do_table; + HASH ignore_table; + DYNAMIC_ARRAY wild_do_table; + DYNAMIC_ARRAY wild_ignore_table; + In_C_you_should_use_my_bool_instead() do_table_inited; + In_C_you_should_use_my_bool_instead() ignore_table_inited; + In_C_you_should_use_my_bool_instead() wild_do_table_inited; + In_C_you_should_use_my_bool_instead() wild_ignore_table_inited; + I_List<i_string> do_db; + I_List<i_string> ignore_db; + I_List<i_string_pair> rewrite_db; +}; +extern Rpl_filter *rpl_filter; +extern Rpl_filter *binlog_filter; +#include "rpl_tblmap.h" +class Relay_log_info; +class Master_info; +extern ulong master_retry_count; +extern MY_BITMAP slave_error_mask; +extern In_C_you_should_use_my_bool_instead() use_slave_mask; +extern char *slave_load_tmpdir; +extern char *master_info_file, *relay_log_info_file; +extern char *opt_relay_logname, *opt_relaylog_index_name; +extern my_bool opt_skip_slave_start, opt_reckless_slave; +extern my_bool opt_log_slave_updates; +extern ulonglong relay_log_space_limit; +int init_slave(); +void init_slave_skip_errors(const char* arg); +In_C_you_should_use_my_bool_instead() flush_relay_log_info(Relay_log_info* rli); +int register_slave_on_master(MYSQL* mysql); +int terminate_slave_threads(Master_info* mi, int thread_mask, + In_C_you_should_use_my_bool_instead() skip_lock = 0); +int start_slave_threads(In_C_you_should_use_my_bool_instead() need_slave_mutex, In_C_you_should_use_my_bool_instead() wait_for_start, + Master_info* mi, const char* master_info_fname, + const char* slave_info_fname, int thread_mask); +int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock, + pthread_mutex_t *cond_lock, + pthread_cond_t* start_cond, + volatile uint *slave_running, + volatile ulong *slave_run_id, + Master_info* mi, + In_C_you_should_use_my_bool_instead() high_priority); +int mysql_table_dump(THD* thd, const char* db, + const char* tbl_name, int fd = -1); +int fetch_master_table(THD* thd, const char* db_name, const char* table_name, + Master_info* mi, MYSQL* mysql, In_C_you_should_use_my_bool_instead() overwrite); +In_C_you_should_use_my_bool_instead() show_master_info(THD* thd, Master_info* mi); +In_C_you_should_use_my_bool_instead() show_binlog_info(THD* thd); +In_C_you_should_use_my_bool_instead() rpl_master_has_bug(Relay_log_info *rli, uint bug_id, In_C_you_should_use_my_bool_instead() report=(1)); +In_C_you_should_use_my_bool_instead() rpl_master_erroneous_autoinc(THD* thd); +const char *print_slave_db_safe(const char *db); +int check_expected_error(THD* thd, Relay_log_info const *rli, int error_code); +void skip_load_data_infile(NET* net); +void end_slave(); +void clear_until_condition(Relay_log_info* rli); +void clear_slave_error(Relay_log_info* rli); +void end_relay_log_info(Relay_log_info* rli); +void lock_slave_threads(Master_info* mi); +void unlock_slave_threads(Master_info* mi); +void init_thread_mask(int* mask,Master_info* mi,In_C_you_should_use_my_bool_instead() inverse); +int init_relay_log_pos(Relay_log_info* rli,const char* log,ulonglong pos, + In_C_you_should_use_my_bool_instead() need_data_lock, const char** errmsg, + In_C_you_should_use_my_bool_instead() look_for_description_event); +int purge_relay_logs(Relay_log_info* rli, THD *thd, In_C_you_should_use_my_bool_instead() just_reset, + const char** errmsg); +void set_slave_thread_options(THD* thd); +void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli); +void rotate_relay_log(Master_info* mi); +int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, + In_C_you_should_use_my_bool_instead() skip); + void * handle_slave_io(void *arg); + void * handle_slave_sql(void *arg); +extern In_C_you_should_use_my_bool_instead() volatile abort_loop; +extern Master_info main_mi, *active_mi; +extern LIST master_list; +extern my_bool replicate_same_server_id; +extern int disconnect_slave_event_count, abort_slave_event_count ; +extern uint master_port, master_connect_retry, report_port; +extern char * master_user, *master_password, *master_host; +extern char *master_info_file, *relay_log_info_file, *report_user; +extern char *report_host, *report_password; +extern my_bool master_ssl; +extern char *master_ssl_ca, *master_ssl_capath, *master_ssl_cert; +extern char *master_ssl_cipher, *master_ssl_key; +extern I_List<THD> threads; +enum mysql_db_table_field +{ + MYSQL_DB_FIELD_HOST = 0, + MYSQL_DB_FIELD_DB, + MYSQL_DB_FIELD_USER, + MYSQL_DB_FIELD_SELECT_PRIV, + MYSQL_DB_FIELD_INSERT_PRIV, + MYSQL_DB_FIELD_UPDATE_PRIV, + MYSQL_DB_FIELD_DELETE_PRIV, + MYSQL_DB_FIELD_CREATE_PRIV, + MYSQL_DB_FIELD_DROP_PRIV, + MYSQL_DB_FIELD_GRANT_PRIV, + MYSQL_DB_FIELD_REFERENCES_PRIV, + MYSQL_DB_FIELD_INDEX_PRIV, + MYSQL_DB_FIELD_ALTER_PRIV, + MYSQL_DB_FIELD_CREATE_TMP_TABLE_PRIV, + MYSQL_DB_FIELD_LOCK_TABLES_PRIV, + MYSQL_DB_FIELD_CREATE_VIEW_PRIV, + MYSQL_DB_FIELD_SHOW_VIEW_PRIV, + MYSQL_DB_FIELD_CREATE_ROUTINE_PRIV, + MYSQL_DB_FIELD_ALTER_ROUTINE_PRIV, + MYSQL_DB_FIELD_EXECUTE_PRIV, + MYSQL_DB_FIELD_EVENT_PRIV, + MYSQL_DB_FIELD_TRIGGER_PRIV, + MYSQL_DB_FIELD_COUNT +}; +extern TABLE_FIELD_W_TYPE mysql_db_table_fields[]; +extern time_t mysql_db_table_last_check; +struct acl_host_and_ip +{ + char *hostname; + long ip,ip_mask; +}; +class ACL_ACCESS { +public: + ulong sort; + ulong access; +}; +class ACL_HOST :public ACL_ACCESS +{ +public: + acl_host_and_ip host; + char *db; +}; +class ACL_USER :public ACL_ACCESS +{ +public: + acl_host_and_ip host; + uint hostname_length; + USER_RESOURCES user_resource; + char *user; + uint8 salt[20 +1]; + uint8 salt_len; + enum SSL_type ssl_type; + const char *ssl_cipher, *x509_issuer, *x509_subject; +}; +class ACL_DB :public ACL_ACCESS +{ +public: + acl_host_and_ip host; + char *user,*db; +}; +In_C_you_should_use_my_bool_instead() hostname_requires_resolving(const char *hostname); +my_bool acl_init(In_C_you_should_use_my_bool_instead() dont_read_acl_tables); +my_bool acl_reload(THD *thd); +void acl_free(In_C_you_should_use_my_bool_instead() end=0); +ulong acl_get(const char *host, const char *ip, + const char *user, const char *db, my_bool db_is_pattern); +int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd, + uint passwd_len); +In_C_you_should_use_my_bool_instead() acl_getroot_no_password(Security_context *sctx, char *user, char *host, + char *ip, char *db); +In_C_you_should_use_my_bool_instead() acl_check_host(const char *host, const char *ip); +int check_change_password(THD *thd, const char *host, const char *user, + char *password, uint password_len); +In_C_you_should_use_my_bool_instead() change_password(THD *thd, const char *host, const char *user, + char *password); +In_C_you_should_use_my_bool_instead() mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list, + ulong rights, In_C_you_should_use_my_bool_instead() revoke); +int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list, + List <LEX_COLUMN> &column_list, ulong rights, + In_C_you_should_use_my_bool_instead() revoke); +In_C_you_should_use_my_bool_instead() mysql_routine_grant(THD *thd, TABLE_LIST *table, In_C_you_should_use_my_bool_instead() is_proc, + List <LEX_USER> &user_list, ulong rights, + In_C_you_should_use_my_bool_instead() revoke, In_C_you_should_use_my_bool_instead() no_error); +my_bool grant_init(); +void grant_free(void); +my_bool grant_reload(THD *thd); +In_C_you_should_use_my_bool_instead() check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, + uint show_command, uint number, In_C_you_should_use_my_bool_instead() dont_print_error); +In_C_you_should_use_my_bool_instead() check_grant_column (THD *thd, GRANT_INFO *grant, + const char *db_name, const char *table_name, + const char *name, uint length, Security_context *sctx); +In_C_you_should_use_my_bool_instead() check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref, + const char *name, uint length); +In_C_you_should_use_my_bool_instead() check_grant_all_columns(THD *thd, ulong want_access, + Field_iterator_table_ref *fields); +In_C_you_should_use_my_bool_instead() check_grant_routine(THD *thd, ulong want_access, + TABLE_LIST *procs, In_C_you_should_use_my_bool_instead() is_proc, In_C_you_should_use_my_bool_instead() no_error); +In_C_you_should_use_my_bool_instead() check_grant_db(THD *thd,const char *db); +ulong get_table_grant(THD *thd, TABLE_LIST *table); +ulong get_column_grant(THD *thd, GRANT_INFO *grant, + const char *db_name, const char *table_name, + const char *field_name); +In_C_you_should_use_my_bool_instead() mysql_show_grants(THD *thd, LEX_USER *user); +void get_privilege_desc(char *to, uint max_length, ulong access); +void get_mqh(const char *user, const char *host, USER_CONN *uc); +In_C_you_should_use_my_bool_instead() mysql_create_user(THD *thd, List <LEX_USER> &list); +In_C_you_should_use_my_bool_instead() mysql_drop_user(THD *thd, List <LEX_USER> &list); +In_C_you_should_use_my_bool_instead() mysql_rename_user(THD *thd, List <LEX_USER> &list); +In_C_you_should_use_my_bool_instead() mysql_revoke_all(THD *thd, List <LEX_USER> &list); +void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, + const char *db, const char *table); +In_C_you_should_use_my_bool_instead() sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, + In_C_you_should_use_my_bool_instead() is_proc); +int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, + In_C_you_should_use_my_bool_instead() is_proc); +In_C_you_should_use_my_bool_instead() check_routine_level_acl(THD *thd, const char *db, const char *name, + In_C_you_should_use_my_bool_instead() is_proc); +In_C_you_should_use_my_bool_instead() is_acl_user(const char *host, const char *user); +#include "tztime.h" +class Time_zone: public Sql_alloc +{ +public: + Time_zone() {} + virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t, + my_bool *in_dst_time_gap) const = 0; + virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const = 0; + virtual const String * get_name() const = 0; + virtual ~Time_zone() {}; +}; +extern Time_zone * my_tz_UTC; +extern Time_zone * my_tz_SYSTEM; +extern Time_zone * my_tz_OFFSET0; +extern Time_zone * my_tz_find(THD *thd, const String *name); +extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap); +extern void my_tz_free(); +extern my_time_t sec_since_epoch_TIME(MYSQL_TIME *t); +static const int MY_TZ_TABLES_COUNT= 4; +In_C_you_should_use_my_bool_instead() check_global_access(THD *thd, ulong want_access); +int get_quote_char_for_identifier(THD *thd, const char *name, uint length); +void sql_perror(const char *message); +In_C_you_should_use_my_bool_instead() fn_format_relative_to_data_home(char * to, const char *name, + const char *dir, const char *extension); +extern uint mysql_data_home_len; +extern char *mysql_data_home,server_version[60], + mysql_real_data_home[], mysql_unpacked_real_data_home[]; +extern CHARSET_INFO *character_set_filesystem; +extern char reg_ext[20]; +extern uint reg_ext_length; +extern ulong specialflag; +extern uint lower_case_table_names; +extern In_C_you_should_use_my_bool_instead() mysqld_embedded; +extern my_bool opt_large_pages; +extern uint opt_large_page_size; +extern struct system_variables global_system_variables; +uint strconvert(CHARSET_INFO *from_cs, const char *from, + CHARSET_INFO *to_cs, char *to, uint to_length, uint *errors); +uint filename_to_tablename(const char *from, char *to, uint to_length); +uint tablename_to_filename(const char *from, char *to, uint to_length); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d2fc752ca11..43c9c2ee899 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -22,7 +22,7 @@ #include "sql_repl.h" #include "rpl_filter.h" #include "repl_failsafe.h" -#include "stacktrace.h" +#include <my_stacktrace.h> #include "mysqld_suffix.h" #include "mysys_err.h" #include "events.h" @@ -522,6 +522,7 @@ char mysql_real_data_home[FN_REFLEN], *opt_init_file, *opt_tc_log_file, def_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; char mysql_unpacked_real_data_home[FN_REFLEN]; +int mysql_unpacked_real_data_home_len; uint reg_ext_length; const key_map key_map_empty(0); key_map key_map_full(0); // Will be initialized later @@ -1952,6 +1953,7 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused))) static BOOL WINAPI console_event_handler( DWORD type ) { DBUG_ENTER("console_event_handler"); +#ifndef EMBEDDED_LIBRARY if(type == CTRL_C_EVENT) { /* @@ -1960,12 +1962,15 @@ static BOOL WINAPI console_event_handler( DWORD type ) between main thread doing initialization and CTRL-C thread doing cleanup, which can result into crash. */ +#ifndef EMBEDDED_LIBRARY if(hEventShutdown) kill_mysql(); else +#endif sql_print_warning("CTRL-C ignored during startup"); DBUG_RETURN(TRUE); } +#endif DBUG_RETURN(FALSE); } @@ -2049,7 +2054,7 @@ LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers) #endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */ __try { - set_exception_pointers(ex_pointers); + my_set_exception_pointers(ex_pointers); handle_segfault(ex_pointers->ExceptionRecord->ExceptionCode); } __except(EXCEPTION_EXECUTE_HANDLER) @@ -2432,8 +2437,8 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n", Attempting backtrace. You can use the following information to find out\n\ where mysqld died. If you see no messages after this, something went\n\ terribly wrong...\n"); - print_stacktrace(thd ? (uchar*) thd->thread_stack : (uchar*) 0, - my_thread_stack_size); + my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL, + my_thread_stack_size); } if (thd) { @@ -2457,7 +2462,7 @@ terribly wrong...\n"); } fprintf(stderr, "Trying to get some variables.\n\ Some pointers may be invalid and cause the dump to abort...\n"); - safe_print_str("thd->query", thd->query, 1024); + my_safe_print_str("thd->query", thd->query, 1024); fprintf(stderr, "thd->thread_id=%lu\n", (ulong) thd->thread_id); fprintf(stderr, "thd->killed=%s\n", kreason); } @@ -2504,7 +2509,7 @@ bugs.\n"); { fprintf(stderr, "Writing a core file\n"); fflush(stderr); - write_core(sig); + my_write_core(sig); } #endif @@ -2538,7 +2543,9 @@ static void init_signals(void) sigemptyset(&sa.sa_mask); sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL); - init_stacktrace(); +#ifdef HAVE_STACKTRACE + my_init_stacktrace(); +#endif #if defined(__amiga__) sa.sa_handler=(void(*)())handle_segfault; #else @@ -2870,6 +2877,7 @@ int my_message_sql(uint error, const char *str, myf MyFlags) by the stored procedures code. */ if (thd->spcont && + ! (MyFlags & ME_NO_SP_HANDLER) && thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd)) { /* @@ -2879,7 +2887,8 @@ int my_message_sql(uint error, const char *str, myf MyFlags) DBUG_RETURN(0); } - if (!thd->no_warnings_for_error) + if (!thd->no_warnings_for_error && + !(MyFlags & ME_NO_WARNING_FOR_ERROR)) { /* Suppress infinite recursion if there a memory allocation error @@ -3120,6 +3129,7 @@ SHOW_VAR com_status_vars[]= { {"stmt_execute", (char*) offsetof(STATUS_VAR, com_stmt_execute), SHOW_LONG_STATUS}, {"stmt_fetch", (char*) offsetof(STATUS_VAR, com_stmt_fetch), SHOW_LONG_STATUS}, {"stmt_prepare", (char*) offsetof(STATUS_VAR, com_stmt_prepare), SHOW_LONG_STATUS}, + {"stmt_reprepare", (char*) offsetof(STATUS_VAR, com_stmt_reprepare), SHOW_LONG_STATUS}, {"stmt_reset", (char*) offsetof(STATUS_VAR, com_stmt_reset), SHOW_LONG_STATUS}, {"stmt_send_long_data", (char*) offsetof(STATUS_VAR, com_stmt_send_long_data), SHOW_LONG_STATUS}, {"truncate", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_TRUNCATE]), SHOW_LONG_STATUS}, @@ -3208,7 +3218,7 @@ static int init_common_variables(const char *conf_file_name, int argc, We have few debug-only commands in com_status_vars, only visible in debug builds. for simplicity we enable the assert only in debug builds - There are 7 Com_ variables which don't have corresponding SQLCOM_ values: + There are 8 Com_ variables which don't have corresponding SQLCOM_ values: (TODO strictly speaking they shouldn't be here, should not have Com_ prefix that is. Perhaps Stmt_ ? Comstmt_ ? Prepstmt_ ?) @@ -3217,6 +3227,7 @@ static int init_common_variables(const char *conf_file_name, int argc, Com_stmt_execute => com_stmt_execute Com_stmt_fetch => com_stmt_fetch Com_stmt_prepare => com_stmt_prepare + Com_stmt_reprepare => com_stmt_reprepare Com_stmt_reset => com_stmt_reset Com_stmt_send_long_data => com_stmt_send_long_data @@ -3225,7 +3236,7 @@ static int init_common_variables(const char *conf_file_name, int argc, of SQLCOM_ constants. */ compile_time_assert(sizeof(com_status_vars)/sizeof(com_status_vars[0]) - 1 == - SQLCOM_END + 7); + SQLCOM_END + 8); #endif load_defaults(conf_file_name, groups, &argc, &argv); @@ -3526,7 +3537,9 @@ static int init_thread_environment() (void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST); (void) pthread_cond_init(&COND_server_started,NULL); sp_cache_init(); +#ifdef HAVE_EVENT_SCHEDULER Events::init_mutexes(); +#endif /* Parameter for threads created for connections */ (void) pthread_attr_init(&connection_attrib); (void) pthread_attr_setdetachstate(&connection_attrib, @@ -6838,7 +6851,8 @@ The minimum value for this variable is 4096.", {"table_definition_cache", OPT_TABLE_DEF_CACHE, "The number of cached table definitions.", (uchar**) &table_def_size, (uchar**) &table_def_size, - 0, GET_ULONG, REQUIRED_ARG, 128, 1, 512*1024L, 0, 1, 0}, + 0, GET_ULONG, REQUIRED_ARG, TABLE_DEF_CACHE_DEFAULT, TABLE_DEF_CACHE_MIN, + 512*1024L, 0, 1, 0}, {"table_open_cache", OPT_TABLE_OPEN_CACHE, "The number of cached open tables.", (uchar**) &table_cache_size, (uchar**) &table_cache_size, 0, GET_ULONG, @@ -7473,6 +7487,7 @@ static void mysql_init_variables(void) /* Things reset to zero */ opt_skip_slave_start= opt_reckless_slave = 0; mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0; + myisam_test_invalid_symlink= test_if_data_home_dir; opt_log= opt_slow_log= 0; opt_update_log= 0; log_output_options= find_bit_type(log_output_str, &log_output_typelib); @@ -7918,8 +7933,12 @@ mysqld_get_one_option(int optid, } #endif case OPT_EVENT_SCHEDULER: +#ifndef HAVE_EVENT_SCHEDULER + sql_perror("Event scheduler is not supported in embedded build."); +#else if (Events::set_opt_event_scheduler(argument)) exit(1); +#endif break; case (int) OPT_SKIP_NEW: opt_specialflag|= SPECIAL_NO_NEW_FUNC; @@ -8433,9 +8452,12 @@ static void fix_paths(void) pos[1]= 0; } convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); - (void) fn_format(buff, mysql_real_data_home, "", "", - (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS)); - (void) unpack_dirname(mysql_unpacked_real_data_home, buff); + my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0)); + mysql_unpacked_real_data_home_len= strlen(mysql_unpacked_real_data_home); + if (mysql_unpacked_real_data_home[mysql_unpacked_real_data_home_len-1] == FN_LIBCHAR) + --mysql_unpacked_real_data_home_len; + + convert_dirname(language,language,NullS); (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index e5709f418f7..28ee8af0699 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2314,9 +2314,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, table deletes. */ if ((thd->lex->sql_command != SQLCOM_DELETE)) -#ifdef NOT_USED - if ((thd->lex->sql_command != SQLCOM_UPDATE)) -#endif { /* Get best non-covering ROR-intersection plan and prepare data for @@ -7939,6 +7936,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() handler *file= head->file; DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::read_keys_and_merge"); + /* We're going to just read rowids. */ file->extra(HA_EXTRA_KEYREAD); head->prepare_for_position(); @@ -7997,15 +7995,17 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() } - DBUG_PRINT("info", ("ok")); - /* ok, all row ids are in Unique */ + /* + Ok all rowids are in the Unique now. The next call will initialize + head->sort structure so it can be used to iterate through the rowids + sequence. + */ result= unique->get(head); delete unique; doing_pk_scan= FALSE; /* index_merge currently doesn't support "using index" at all */ file->extra(HA_EXTRA_NO_KEYREAD); - /* start table scan */ - init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1, 1); + init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1 , 1, TRUE); DBUG_RETURN(result); } @@ -8031,6 +8031,7 @@ int QUICK_INDEX_MERGE_SELECT::get_next() { result= HA_ERR_END_OF_FILE; end_read_record(&read_record); + free_io_cache(head); /* All rows from Unique have been retrieved, do a clustered PK scan */ if (pk_quick_select) { @@ -8559,9 +8560,17 @@ bool QUICK_RANGE_SELECT::row_in_ranges() QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q, uint used_key_parts_arg) - :QUICK_RANGE_SELECT(*q), rev_it(rev_ranges) + :QUICK_RANGE_SELECT(*q), rev_it(rev_ranges), + used_key_parts (used_key_parts_arg) { QUICK_RANGE *r; + /* + Use default MRR implementation for reverse scans. No table engine + currently can do an MRR scan with output in reverse index order. + */ + multi_range_length= 0; + multi_range= NULL; + multi_range_buff= NULL; QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer; QUICK_RANGE **end_range= pr + ranges.elements; @@ -8601,10 +8610,11 @@ int QUICK_SELECT_DESC::get_next() int result; if (last_range) { // Already read through key - result = ((last_range->flag & EQ_RANGE) - ? file->index_next_same(record, last_range->min_key, - last_range->min_length) : - file->index_prev(record)); + result = ((last_range->flag & EQ_RANGE && + used_key_parts <= head->key_info[index].key_parts) ? + file->index_next_same(record, last_range->min_key, + last_range->min_length) : + file->index_prev(record)); if (!result) { if (cmp_prev(*rev_it.ref()) == 0) @@ -8628,7 +8638,9 @@ int QUICK_SELECT_DESC::get_next() continue; } - if (last_range->flag & EQ_RANGE) + if (last_range->flag & EQ_RANGE && + used_key_parts <= head->key_info[index].key_parts) + { result = file->index_read_map(record, last_range->max_key, last_range->max_keypart_map, @@ -8637,6 +8649,8 @@ int QUICK_SELECT_DESC::get_next() else { DBUG_ASSERT(last_range->flag & NEAR_MAX || + (last_range->flag & EQ_RANGE && + used_key_parts > head->key_info[index].key_parts) || range_reads_after_key(last_range)); result=file->index_read_map(record, last_range->max_key, last_range->max_keypart_map, @@ -8734,54 +8748,6 @@ bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range_arg) } -/* TRUE if we are reading over a key that may have a NULL value */ - -#ifdef NOT_USED -bool QUICK_SELECT_DESC::test_if_null_range(QUICK_RANGE *range_arg, - uint used_key_parts) -{ - uint offset, end; - KEY_PART *key_part = key_parts, - *key_part_end= key_part+used_key_parts; - - for (offset= 0, end = min(range_arg->min_length, range_arg->max_length) ; - offset < end && key_part != key_part_end ; - offset+= key_part++->store_length) - { - if (!memcmp((char*) range_arg->min_key+offset, - (char*) range_arg->max_key+offset, - key_part->store_length)) - continue; - - if (key_part->null_bit && range_arg->min_key[offset]) - return 1; // min_key is null and max_key isn't - // Range doesn't cover NULL. This is ok if there is no more null parts - break; - } - /* - If the next min_range is > NULL, then we can use this, even if - it's a NULL key - Example: SELECT * FROM t1 WHERE a = 2 AND b >0 ORDER BY a DESC,b DESC; - - */ - if (key_part != key_part_end && key_part->null_bit) - { - if (offset >= range_arg->min_length || range_arg->min_key[offset]) - return 1; // Could be null - key_part++; - } - /* - If any of the key parts used in the ORDER BY could be NULL, we can't - use the key to sort the data. - */ - for (; key_part != key_part_end ; key_part++) - if (key_part->null_bit) - return 1; // Covers null part - return 0; -} -#endif - - void QUICK_RANGE_SELECT::add_info_string(String *str) { KEY *key_info= head->key_info + index; diff --git a/sql/opt_range.h b/sql/opt_range.h index 4f5cce28bf2..8d2ba1bb0a6 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -345,14 +345,7 @@ public: void dbug_dump(int indent, bool verbose); #endif private: - /* Used only by QUICK_SELECT_DESC */ - QUICK_RANGE_SELECT(const QUICK_RANGE_SELECT& org) : QUICK_SELECT_I() - { - bcopy(&org, this, sizeof(*this)); - multi_range_length= 0; - multi_range= NULL; - multi_range_buff= NULL; - } + /* Default copy ctor used by QUICK_SELECT_DESC */ }; @@ -686,12 +679,10 @@ public: int get_type() { return QS_TYPE_RANGE_DESC; } private: bool range_reads_after_key(QUICK_RANGE *range); -#ifdef NOT_USED - bool test_if_null_range(QUICK_RANGE *range, uint used_key_parts); -#endif int reset(void) { rev_it.rewind(); return QUICK_RANGE_SELECT::reset(); } List<QUICK_RANGE> rev_ranges; List_iterator<QUICK_RANGE> rev_it; + uint used_key_parts; }; diff --git a/sql/protocol.cc b/sql/protocol.cc index c98ad72fffe..3eccc6632ce 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -790,6 +790,9 @@ bool Protocol_text::store(const char *from, size_t length, { CHARSET_INFO *tocs= this->thd->variables.character_set_results; #ifndef DBUG_OFF + DBUG_PRINT("info", ("Protocol_text::store field %u (%u): %s", field_pos, + field_count, from)); + DBUG_ASSERT(field_pos < field_count); DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || field_types[field_pos] == MYSQL_TYPE_BIT || diff --git a/sql/records.cc b/sql/records.cc index cfcaf9df8e6..9e040de3fda 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -86,6 +86,23 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, The temporary file is normally used when the references doesn't fit into a properly sized memory buffer. For most small queries the references are stored in the memory buffer. + SYNOPSIS + init_read_record() + info OUT read structure + thd Thread handle + table Table the data [originally] comes from. + select SQL_SELECT structure. We may select->quick or + select->file as data source + use_record_cache Call file->extra_opt(HA_EXTRA_CACHE,...) + if we're going to do sequential read and some + additional conditions are satisfied. + print_error Copy this to info->print_error + disable_rr_cache Don't use rr_from_cache (used by sort-union + index-merge which produces rowid sequences that + are already ordered) + + DESCRIPTION + This function sets up reading data via one of the methods: The temporary file is also used when performing an update where a key is modified. @@ -140,7 +157,8 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, */ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, SQL_SELECT *select, - int use_record_cache, bool print_error) + int use_record_cache, bool print_error, + bool disable_rr_cache) { IO_CACHE *tempfile; DBUG_ENTER("init_read_record"); @@ -191,7 +209,8 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, it doesn't make sense to use cache - we don't read from the table and table->sort.io_cache is read sequentially */ - if (!table->sort.addon_field && + if (!disable_rr_cache && + !table->sort.addon_field && ! (specialflag & SPECIAL_SAFE_MODE) && thd->variables.read_rnd_buff_size && !(table->file->ha_table_flags() & HA_FAST_KEY_READ) && diff --git a/sql/rpl_tblmap.cc b/sql/rpl_tblmap.cc index 6c8b494dfa9..a004c354263 100644 --- a/sql/rpl_tblmap.cc +++ b/sql/rpl_tblmap.cc @@ -19,7 +19,11 @@ #include "rpl_tblmap.h" +#ifdef MYSQL_CLIENT +#define MAYBE_TABLE_NAME(T) ("") +#else #define MAYBE_TABLE_NAME(T) ((T) ? (T)->s->table_name.str : "<>") +#endif #define TABLE_ID_HASH_SIZE 32 #define TABLE_ID_CHUNK 256 @@ -42,11 +46,14 @@ table_mapping::table_mapping() table_mapping::~table_mapping() { +#ifdef MYSQL_CLIENT + clear_tables(); +#endif hash_free(&m_table_ids); free_root(&m_mem_root, MYF(0)); } -st_table* table_mapping::get_table(ulong table_id) +TABLE* table_mapping::get_table(ulong table_id) { DBUG_ENTER("table_mapping::get_table(ulong)"); DBUG_PRINT("enter", ("table_id: %lu", table_id)); @@ -104,8 +111,12 @@ int table_mapping::set_table(ulong table_id, TABLE* table) m_free= m_free->next; } else + { +#ifdef MYSQL_CLIENT + free_table_map_log_event(e->table); +#endif hash_delete(&m_table_ids,(uchar *)e); - + } e->table_id= table_id; e->table= table; my_hash_insert(&m_table_ids,(uchar *)e); @@ -140,6 +151,9 @@ void table_mapping::clear_tables() for (uint i= 0; i < m_table_ids.records; i++) { entry *e= (entry *)hash_element(&m_table_ids, i); +#ifdef MYSQL_CLIENT + free_table_map_log_event(e->table); +#endif e->next= m_free; m_free= e; } diff --git a/sql/rpl_tblmap.h b/sql/rpl_tblmap.h index 446833d5ed6..3b5b10be580 100644 --- a/sql/rpl_tblmap.h +++ b/sql/rpl_tblmap.h @@ -17,8 +17,15 @@ #define TABLE_MAPPING_H /* Forward declarations */ +#ifndef MYSQL_CLIENT struct st_table; typedef st_table TABLE; +#else +class Table_map_log_event; +typedef Table_map_log_event TABLE; +void free_table_map_log_event(TABLE *table); +#endif + /* CLASS table_mapping diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 4f4083d9b8f..e34f8561051 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -188,7 +188,8 @@ table_def::compatible_with(Relay_log_info const *rli_arg, TABLE *table) for (uint col= 0 ; col < cols_to_check ; ++col) { - if (table->field[col]->type() != type(col)) + Field *const field= table->field[col]; + if (field->type() != type(col)) { DBUG_ASSERT(col < size() && col < tsh->fields); DBUG_ASSERT(tsh->db.str && tsh->table_name.str); @@ -197,15 +198,15 @@ table_def::compatible_with(Relay_log_info const *rli_arg, TABLE *table) my_snprintf(buf, sizeof(buf), "Column %d type mismatch - " "received type %d, %s.%s has type %d", col, type(col), tsh->db.str, tsh->table_name.str, - table->field[col]->type()); + field->type()); rli->report(ERROR_LEVEL, ER_BINLOG_ROW_WRONG_TABLE_DEF, ER(ER_BINLOG_ROW_WRONG_TABLE_DEF), buf); } /* Check the slave's field size against that of the master. */ - if (!error && - !table->field[col]->compatible_field_size(field_metadata(col))) + if (!error && + !field->compatible_field_size(field_metadata(col), rli_arg)) { error= 1; char buf[256]; @@ -213,10 +214,9 @@ table_def::compatible_with(Relay_log_info const *rli_arg, TABLE *table) "master has size %d, %s.%s on slave has size %d." " Master's column size should be <= the slave's " "column size.", col, - table->field[col]->pack_length_from_metadata( - m_field_metadata[col]), - tsh->db.str, tsh->table_name.str, - table->field[col]->row_pack_length()); + field->pack_length_from_metadata(m_field_metadata[col]), + tsh->db.str, tsh->table_name.str, + field->row_pack_length()); rli->report(ERROR_LEVEL, ER_BINLOG_ROW_WRONG_TABLE_DEF, ER(ER_BINLOG_ROW_WRONG_TABLE_DEF), buf); } diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 375715c7858..8e2f4a7374f 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -236,7 +236,9 @@ public: @retval 1 if the table definition is not compatible with @c table @retval 0 if the table definition is compatible with @c table */ +#ifndef MYSQL_CLIENT int compatible_with(Relay_log_info const *rli, TABLE *table) const; +#endif private: ulong m_size; // Number of elements in the types array @@ -247,6 +249,8 @@ private: uchar *m_memory; }; + +#ifndef MYSQL_CLIENT /** Extend the normal table list with a few new fields needed by the slave thread, but nowhere else. @@ -288,6 +292,7 @@ namespace { }; } +#endif #define DBUG_PRINT_BITSET(N,FRM,BS) \ do { \ diff --git a/sql/set_var.cc b/sql/set_var.cc index cd8713f34a8..df1badebc50 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -254,7 +254,10 @@ static sys_var_long_ptr sys_delayed_insert_timeout(&vars, "delayed_insert_timeou static sys_var_long_ptr sys_delayed_queue_size(&vars, "delayed_queue_size", &delayed_queue_size); +#ifdef HAVE_EVENT_SCHEDULER static sys_var_event_scheduler sys_event_scheduler(&vars, "event_scheduler"); +#endif + static sys_var_long_ptr sys_expire_logs_days(&vars, "expire_logs_days", &expire_logs_days); static sys_var_bool_ptr sys_flush(&vars, "flush", &myisam_flush); @@ -726,7 +729,7 @@ static uchar *slave_get_report_port(THD *thd) return (uchar*) &thd->sys_var_tmp.long_value; } -static sys_var_readonly sys_repl_report_port(&vars, "report_port", OPT_GLOBAL, SHOW_INT, slave_get_report_port); +static sys_var_readonly sys_repl_report_port(&vars, "report_port", OPT_GLOBAL, SHOW_LONG, slave_get_report_port); #endif @@ -1173,6 +1176,21 @@ void fix_slave_exec_mode(enum_var_type type) DBUG_VOID_RETURN; } + +bool sys_var_thd_binlog_format::check(THD *thd, set_var *var) { + /* + All variables that affect writing to binary log (either format or + turning logging on and off) use the same checking. We call the + superclass ::check function to assign the variable correctly, and + then check the value. + */ + bool result= sys_var_thd_enum::check(thd, var); + if (!result) + result= check_log_update(thd, var); + return result; +} + + bool sys_var_thd_binlog_format::is_readonly() const { /* @@ -1677,6 +1695,14 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) strmov(buff, "NULL"); goto err; } + + if (!m_allow_empty_value && + res->length() == 0) + { + buff[0]= 0; + goto err; + } + var->save_result.ulong_value= ((ulong) find_set(enum_names, res->c_ptr(), res->length(), @@ -1692,10 +1718,19 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) else { ulonglong tmp= var->value->val_int(); - /* - For when the enum is made to contain 64 elements, as 1ULL<<64 is - undefined, we guard with a "count<64" test. - */ + + if (!m_allow_empty_value && + tmp == 0) + { + buff[0]= '0'; + buff[1]= 0; + goto err; + } + + /* + For when the enum is made to contain 64 elements, as 1ULL<<64 is + undefined, we guard with a "count<64" test. + */ if (unlikely((tmp >= ((ULL(1)) << enum_names->count)) && (enum_names->count < 64))) { @@ -2394,32 +2429,51 @@ static int sys_check_log_path(THD *thd, set_var *var) MY_STAT f_stat; String str(buff, sizeof(buff), system_charset_info), *res; const char *log_file_str; - + size_t path_length; + if (!(res= var->value->val_str(&str))) goto err; log_file_str= res->c_ptr(); bzero(&f_stat, sizeof(MY_STAT)); - (void) unpack_filename(path, log_file_str); - if (my_stat(path, &f_stat, MYF(0))) + path_length= unpack_filename(path, log_file_str); + + if (!path_length) { - /* Check if argument is a file and we have 'write' permission */ - if (!MY_S_ISREG(f_stat.st_mode) || - !(f_stat.st_mode & MY_S_IWRITE)) - goto err; + /* File name is empty. */ + + goto err; } - else + + if (my_stat(path, &f_stat, MYF(0))) { - size_t path_length; /* - Check if directory exists and - we have permission to create file & write to file + A file system object exists. Check if argument is a file and we have + 'write' permission. */ - (void) dirname_part(path, log_file_str, &path_length); - if (my_access(path, (F_OK|W_OK))) + + if (!MY_S_ISREG(f_stat.st_mode) || + !(f_stat.st_mode & MY_S_IWRITE)) goto err; + + return 0; } + + /* Get dirname of the file path. */ + (void) dirname_part(path, log_file_str, &path_length); + + /* Dirname is empty if file path is relative. */ + if (!path_length) + return 0; + + /* + Check if directory exists and we have permission to create file and + write to file. + */ + if (my_access(path, (F_OK|W_OK))) + goto err; + return 0; err: @@ -4038,13 +4092,12 @@ uchar *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b) return (uchar*) thd->strdup(buf); } - +#ifdef HAVE_EVENT_SCHEDULER bool sys_var_event_scheduler::check(THD *thd, set_var *var) { return check_enum(thd, var, &Events::var_typelib); } - /* The update method of the global variable event_scheduler. If event_scheduler is switched from 0 to 1 then the scheduler main @@ -4083,7 +4136,7 @@ uchar *sys_var_event_scheduler::value_ptr(THD *thd, enum_var_type type, { return (uchar *) Events::get_opt_event_scheduler_str(); } - +#endif /**************************************************************************** Used templates diff --git a/sql/set_var.h b/sql/set_var.h index b33a3a968bb..8ae97c6502d 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -74,7 +74,8 @@ public: sys_var(const char *name_arg, sys_after_update_func func= NULL, Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) :name(name_arg), after_update(func), no_support_one_shot(1), - binlog_status(binlog_status_arg) + binlog_status(binlog_status_arg), + m_allow_empty_value(TRUE) {} virtual ~sys_var() {} void chain_sys_var(sys_var_chain *chain_arg) @@ -109,8 +110,16 @@ public: virtual bool is_readonly() const { return 0; } virtual sys_var_pluginvar *cast_pluginvar() { return 0; } +protected: + void set_allow_empty_value(bool allow_empty_value) + { + m_allow_empty_value= allow_empty_value; + } + private: const Binlog_status_enum binlog_status; + + bool m_allow_empty_value; }; @@ -878,8 +887,11 @@ public: sys_var_log_output(sys_var_chain *chain, const char *name_arg, ulong *value_arg, TYPELIB *typelib, sys_after_update_func func) :sys_var(name_arg,func), value(value_arg), enum_names(typelib) - { chain_sys_var(chain); } - bool check(THD *thd, set_var *var) + { + chain_sys_var(chain); + set_allow_empty_value(FALSE); + } + virtual bool check(THD *thd, set_var *var) { return check_set(thd, var, enum_names); } @@ -1085,7 +1097,7 @@ public: virtual void set_default(THD *thd, enum_var_type type); }; - +#ifdef HAVE_EVENT_SCHEDULER class sys_var_event_scheduler :public sys_var_long_ptr { /* We need a derived class only to have a warn_deprecated() */ @@ -1101,6 +1113,7 @@ public: return type != STRING_RESULT && type != INT_RESULT; } }; +#endif extern void fix_binlog_format_after_update(THD *thd, enum_var_type type); @@ -1113,6 +1126,7 @@ public: &binlog_format_typelib, fix_binlog_format_after_update) {}; + bool check(THD *thd, set_var *var); bool is_readonly() const; }; diff --git a/sql/share/charsets/README b/sql/share/charsets/README index 172d1ee8e1e..3c5b3206faa 100644 --- a/sql/share/charsets/README +++ b/sql/share/charsets/README @@ -1,28 +1,31 @@ -This directory holds configuration files which allow MySQL to work with +This directory holds configuration files that enable MySQL to work with different character sets. It contains: -*.conf - Each conf file contains four tables which describe character types, +charset_name.xml + Each charset_name.xml file contains information for a simple character + set. The information in the file describes character types, lower- and upper-case equivalencies and sorting orders for the character values in the set. -Index - The Index file lists all of the available charset configurations. +Index.xml + The Index.xml file lists all of the available charset configurations, + including collations. - Each charset is paired with a number. The number is stored - IN THE DATABASE TABLE FILES and must not be changed. Always - add new character sets to the end of the list, so that the - numbers of the other character sets will not be changed. + Each collation must have a unique number. The number is stored + IN THE DATABASE TABLE FILES and must not be changed. + + The max-id attribute of the <charsets> element must be set to + the largest collation number. Compiled in or configuration file? When should a character set be compiled in to MySQL's string library - (libmystrings), and when should it be placed in a configuration - file? + (libmystrings), and when should it be placed in a charset_name.xml + configuration file? If the character set requires the strcoll functions or is a multi-byte character set, it MUST be compiled in to the string library. If it does not require these functions, it should be - placed in a configuration file. + placed in a charset_name.xml configuration file. If the character set uses any one of the strcoll functions, it must define all of them. Likewise, if the set uses one of the @@ -30,11 +33,7 @@ Compiled in or configuration file? more information on how to add a complex character set to MySQL. Syntax of configuration files - The syntax is very simple. Comments start with a '#' character and - proceed to the end of the line. Words are separated by arbitrary - amounts of whitespace. - - For the character set configuration files, every word must be a - number in hexadecimal format. The ctype array takes up the first - 257 words; the to_lower, to_upper and sort_order arrays take up 256 - words each after that. + The syntax is very simple. Words in <map> array elements are + separated by arbitrary amounts of whitespace. Each word must be a + number in hexadecimal format. The ctype array has 257 words; the + other arrays (lower, upper, etc.) take up 256 words each after that. diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 894e2094968..84eb5f5ba64 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -1773,30 +1773,30 @@ ER_BLOB_USED_AS_KEY 42000 S1009 swe "En BLOB '%-.192s' kan inte vara nyckel med den använda tabelltypen" ukr "BLOB ÓÔÏ×ÂÅÃØ '%-.192s' ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÉÊ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ × ÃØÏÍÕ ÔÉЦ ÔÁÂÌÉæ" ER_TOO_BIG_FIELDLENGTH 42000 S1009 - cze "P-Bøíli¹ velká délka sloupce '%-.192s' (nejvíce %d). Pou¾ijte BLOB" - dan "For stor feltlængde for kolonne '%-.192s' (maks = %d). Brug BLOB i stedet" - nla "Te grote kolomlengte voor '%-.192s' (max = %d). Maak hiervoor gebruik van het type BLOB" - eng "Column length too big for column '%-.192s' (max = %d); use BLOB or TEXT instead" - jps "column '%-.192s' ‚Í,Šm•Û‚·‚é column ‚Ì‘å‚«‚³‚ª‘½‚·‚¬‚Ü‚·. (Å‘å %d ‚Ü‚Å). BLOB ‚ð‚©‚í‚è‚ÉŽg—p‚µ‚Ä‚‚¾‚³‚¢.", - est "Tulba '%-.192s' pikkus on liiga pikk (maksimaalne pikkus: %d). Kasuta BLOB väljatüüpi" - fre "Champ '%-.192s' trop long (max = %d). Utilisez un BLOB" - ger "Feldlänge für Feld '%-.192s' zu groß (maximal %d). BLOB- oder TEXT-Spaltentyp verwenden!" - greek "Ðïëý ìåãÜëï ìÞêïò ãéá ôï ðåäßï '%-.192s' (max = %d). Ðáñáêáëþ ÷ñçóéìïðïéåßóôå ôïí ôýðï BLOB" - hun "A(z) '%-.192s' oszlop tul hosszu. (maximum = %d). Hasznaljon BLOB tipust inkabb." - ita "La colonna '%-.192s' e` troppo grande (max=%d). Utilizza un BLOB." - jpn "column '%-.192s' ¤Ï,³ÎÊݤ¹¤ë column ¤ÎÂ礤µ¤¬Â¿¤¹¤®¤Þ¤¹. (ºÇÂç %d ¤Þ¤Ç). BLOB ¤ò¤«¤ï¤ê¤Ë»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤." - kor "Ä®·³ '%-.192s'ÀÇ Ä®·³ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù (ÃÖ´ë = %d). ´ë½Å¿¡ BLOB¸¦ »ç¿ëÇϼ¼¿ä." - nor "For stor nøkkellengde for kolonne '%-.192s' (maks = %d). Bruk BLOB istedenfor" - norwegian-ny "For stor nykkellengde for felt '%-.192s' (maks = %d). Bruk BLOB istadenfor" - pol "Zbyt du¿a d³ugo?æ kolumny '%-.192s' (maks. = %d). W zamian u¿yj typu BLOB" - por "Comprimento da coluna '%-.192s' grande demais (max = %d); use BLOB em seu lugar" - rum "Lungimea coloanei '%-.192s' este prea lunga (maximum = %d). Foloseste BLOB mai bine" - rus "óÌÉÛËÏÍ ÂÏÌØÛÁÑ ÄÌÉÎÁ ÓÔÏÌÂÃÁ '%-.192s' (ÍÁËÓÉÍÕÍ = %d). éÓÐÏÌØÚÕÊÔÅ ÔÉÐ BLOB ÉÌÉ TEXT ×ÍÅÓÔÏ ÔÅËÕÝÅÇÏ" - serbian "Previše podataka za kolonu '%-.192s' (maksimum je %d). Upotrebite BLOB polje" - slo "Príli¹ veµká då¾ka pre pole '%-.192s' (maximum = %d). Pou¾ite BLOB" - spa "Longitud de columna demasiado grande para la columna '%-.192s' (maximo = %d).Usar BLOB en su lugar" - swe "För stor kolumnlängd angiven för '%-.192s' (max= %d). Använd en BLOB instället" - ukr "úÁÄÏ×ÇÁ ÄÏ×ÖÉÎÁ ÓÔÏ×ÂÃÑ '%-.192s' (max = %d). ÷ÉËÏÒÉÓÔÁÊÔÅ ÔÉÐ BLOB" + cze "P-Bøíli¹ velká délka sloupce '%-.192s' (nejvíce %lu). Pou¾ijte BLOB" + dan "For stor feltlængde for kolonne '%-.192s' (maks = %lu). Brug BLOB i stedet" + nla "Te grote kolomlengte voor '%-.192s' (max = %lu). Maak hiervoor gebruik van het type BLOB" + eng "Column length too big for column '%-.192s' (max = %lu); use BLOB or TEXT instead" + jps "column '%-.192s' ‚Í,Šm•Û‚·‚é column ‚Ì‘å‚«‚³‚ª‘½‚·‚¬‚Ü‚·. (Å‘å %lu ‚Ü‚Å). BLOB ‚ð‚©‚í‚è‚ÉŽg—p‚µ‚Ä‚‚¾‚³‚¢.", + est "Tulba '%-.192s' pikkus on liiga pikk (maksimaalne pikkus: %lu). Kasuta BLOB väljatüüpi" + fre "Champ '%-.192s' trop long (max = %lu). Utilisez un BLOB" + ger "Feldlänge für Feld '%-.192s' zu groß (maximal %lu). BLOB- oder TEXT-Spaltentyp verwenden!" + greek "Ðïëý ìåãÜëï ìÞêïò ãéá ôï ðåäßï '%-.192s' (max = %lu). Ðáñáêáëþ ÷ñçóéìïðïéåßóôå ôïí ôýðï BLOB" + hun "A(z) '%-.192s' oszlop tul hosszu. (maximum = %lu). Hasznaljon BLOB tipust inkabb." + ita "La colonna '%-.192s' e` troppo grande (max=%lu). Utilizza un BLOB." + jpn "column '%-.192s' ¤Ï,³ÎÊݤ¹¤ë column ¤ÎÂ礤µ¤¬Â¿¤¹¤®¤Þ¤¹. (ºÇÂç %lu ¤Þ¤Ç). BLOB ¤ò¤«¤ï¤ê¤Ë»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤." + kor "Ä®·³ '%-.192s'ÀÇ Ä®·³ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù (ÃÖ´ë = %lu). ´ë½Å¿¡ BLOB¸¦ »ç¿ëÇϼ¼¿ä." + nor "For stor nøkkellengde for kolonne '%-.192s' (maks = %lu). Bruk BLOB istedenfor" + norwegian-ny "For stor nykkellengde for felt '%-.192s' (maks = %lu). Bruk BLOB istadenfor" + pol "Zbyt du¿a d³ugo?æ kolumny '%-.192s' (maks. = %lu). W zamian u¿yj typu BLOB" + por "Comprimento da coluna '%-.192s' grande demais (max = %lu); use BLOB em seu lugar" + rum "Lungimea coloanei '%-.192s' este prea lunga (maximum = %lu). Foloseste BLOB mai bine" + rus "óÌÉÛËÏÍ ÂÏÌØÛÁÑ ÄÌÉÎÁ ÓÔÏÌÂÃÁ '%-.192s' (ÍÁËÓÉÍÕÍ = %lu). éÓÐÏÌØÚÕÊÔÅ ÔÉÐ BLOB ÉÌÉ TEXT ×ÍÅÓÔÏ ÔÅËÕÝÅÇÏ" + serbian "Previše podataka za kolonu '%-.192s' (maksimum je %lu). Upotrebite BLOB polje" + slo "Príli¹ veµká då¾ka pre pole '%-.192s' (maximum = %lu). Pou¾ite BLOB" + spa "Longitud de columna demasiado grande para la columna '%-.192s' (maximo = %lu).Usar BLOB en su lugar" + swe "För stor kolumnlängd angiven för '%-.192s' (max= %lu). Använd en BLOB instället" + ukr "úÁÄÏ×ÇÁ ÄÏ×ÖÉÎÁ ÓÔÏ×ÂÃÑ '%-.192s' (max = %lu). ÷ÉËÏÒÉÓÔÁÊÔÅ ÔÉÐ BLOB" ER_WRONG_AUTO_KEY 42000 S1009 cze "M-Bù¾ete mít pouze jedno AUTO pole a to musí být definováno jako klíè" dan "Der kan kun specificeres eet AUTO_INCREMENT-felt, og det skal være indekseret" @@ -4718,7 +4718,7 @@ ER_SLAVE_IGNORED_TABLE swe "Slav SQL tråden ignorerade frågan pga en replicate-*-table regel" ER_INCORRECT_GLOBAL_LOCAL_VAR eng "Variable '%-.192s' is a %s variable" - serbian "Incorrect foreign key definition for '%-.192s': %s" + serbian "Promenljiva '%-.192s' je %s promenljiva" ger "Variable '%-.192s' ist eine %s-Variable" nla "Variabele '%-.192s' is geen %s variabele" spa "Variable '%-.192s' es una %s variable" @@ -5513,11 +5513,11 @@ ER_SP_NO_RECURSION eng "Recursive stored functions and triggers are not allowed." ger "Rekursive gespeicherte Routinen und Triggers sind nicht erlaubt" ER_TOO_BIG_SCALE 42000 S1009 - eng "Too big scale %d specified for column '%-.192s'. Maximum is %d." - ger "Zu großer Skalierungsfaktor %d für Feld '%-.192s' angegeben. Maximum ist %d" + eng "Too big scale %d specified for column '%-.192s'. Maximum is %lu." + ger "Zu großer Skalierungsfaktor %d für Feld '%-.192s' angegeben. Maximum ist %lu" ER_TOO_BIG_PRECISION 42000 S1009 - eng "Too big precision %d specified for column '%-.192s'. Maximum is %d." - ger "Zu große Genauigkeit %d für Feld '%-.192s' angegeben. Maximum ist %d" + eng "Too big precision %d specified for column '%-.192s'. Maximum is %lu." + ger "Zu große Genauigkeit %d für Feld '%-.192s' angegeben. Maximum ist %lu" ER_M_BIGGER_THAN_D 42000 S1009 eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s')." ger "Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%-.192s')" @@ -5555,8 +5555,8 @@ ER_WARN_CANT_DROP_DEFAULT_KEYCACHE eng "Cannot drop default keycache" ger "Der vorgabemäßige Schlüssel-Cache kann nicht gelöscht werden" ER_TOO_BIG_DISPLAYWIDTH 42000 S1009 - eng "Display width out of range for column '%-.192s' (max = %d)" - ger "Anzeigebreite außerhalb des zulässigen Bereichs für Spalte '%-.192s' (Maximum: %d)" + eng "Display width out of range for column '%-.192s' (max = %lu)" + ger "Anzeigebreite außerhalb des zulässigen Bereichs für Spalte '%-.192s' (Maximum: %lu)" ER_XAER_DUPID XAE08 eng "XAER_DUPID: The XID already exists" ger "XAER_DUPID: Die XID existiert bereits" @@ -6121,8 +6121,15 @@ ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT eng "The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement." ER_SLAVE_CORRUPT_EVENT eng "Corrupted replication event was detected" + ER_LOAD_DATA_INVALID_COLUMN eng "Invalid column reference (%-.64s) in LOAD DATA" ER_LOG_PURGE_NO_FILE eng "Being purged log %s was not found" + +ER_NEED_REPREPARE + eng "Prepared statement needs to be re-prepared" + +ER_DELAYED_NOT_SUPPORTED + eng "DELAYED option not supported for table '%-.192s'" diff --git a/sql/slave.cc b/sql/slave.cc index dcc808625c0..0040b69f8de 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4057,9 +4057,17 @@ end: @param rli Relay_log_info which tells the master's version @param bug_id Number of the bug as found in bugs.mysql.com @param report bool report error message, default TRUE + + @param pred Predicate function that will be called with @c param to + check for the bug. If the function return @c true, the bug is present, + otherwise, it is not. + + @param param State passed to @c pred function. + @return TRUE if master has the bug, FALSE if it does not. */ -bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id, bool report) +bool rpl_master_has_bug(const Relay_log_info *rli, uint bug_id, bool report, + bool (*pred)(const void *), const void *param) { struct st_version_range_for_one_bug { uint bug_id; @@ -4072,6 +4080,7 @@ bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id, bool report) {24432, { 5, 1, 12 }, { 5, 1, 17 } }, {33029, { 5, 0, 0 }, { 5, 0, 58 } }, {33029, { 5, 1, 0 }, { 5, 1, 12 } }, + {37426, { 5, 1, 0 }, { 5, 1, 26 } }, }; const uchar *master_ver= rli->relay_log.description_event_for_exec->server_version_split; @@ -4085,11 +4094,11 @@ bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id, bool report) *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)) + (memcmp(fixed_in, master_ver, 3) > 0) && + (pred == NULL || (*pred)(param))) { if (!report) return TRUE; - // 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" @@ -4136,7 +4145,8 @@ bool rpl_master_erroneous_autoinc(THD *thd) if (active_mi && active_mi->rli.sql_thd == thd) { Relay_log_info *rli= &active_mi->rli; - return rpl_master_has_bug(rli, 33029, FALSE); + DBUG_EXECUTE_IF("simulate_bug33029", return TRUE;); + return rpl_master_has_bug(rli, 33029, FALSE, NULL, NULL); } return FALSE; } diff --git a/sql/slave.h b/sql/slave.h index 80d267e5b27..dc2d668c97b 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -165,7 +165,8 @@ 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, bool report=TRUE); +bool rpl_master_has_bug(const Relay_log_info *rli, uint bug_id, bool report, + bool (*pred)(const void *), const void *param); bool rpl_master_erroneous_autoinc(THD* thd); const char *print_slave_db_safe(const char *db); diff --git a/sql/sp.cc b/sql/sp.cc index 69eae8de207..cc545992857 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -24,7 +24,8 @@ static bool create_string(THD *thd, String *buf, int sp_type, - sp_name *name, + const char *db, ulong dblen, + const char *name, ulong namelen, const char *params, ulong paramslen, const char *returns, ulong returnslen, const char *body, ulong bodylen, @@ -588,12 +589,13 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, */ if (!create_string(thd, &defstr, - type, - name, - params, strlen(params), - returns, strlen(returns), - body, strlen(body), - &chistics, &definer_user_name, &definer_host_name)) + type, + NULL, 0, + name->m_name.str, name->m_name.length, + params, strlen(params), + returns, strlen(returns), + body, strlen(body), + &chistics, &definer_user_name, &definer_host_name)) { ret= SP_INTERNAL_ERROR; goto end; @@ -615,12 +617,12 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, thd->spcont= NULL; { - Lex_input_stream lip(thd, defstr.c_ptr(), defstr.length()); + Parser_state parser_state(thd, defstr.c_ptr(), defstr.length()); lex_start(thd); thd->push_internal_handler(&warning_handler); - ret= parse_sql(thd, &lip, creation_ctx) || newlex.sphead == NULL; + ret= parse_sql(thd, & parser_state, creation_ctx) || newlex.sphead == NULL; thd->pop_internal_handler(); /* @@ -732,6 +734,7 @@ sp_create_routine(THD *thd, int type, sp_head *sp) DBUG_ENTER("sp_create_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s",type, (int) sp->m_name.length, sp->m_name.str)); + String retstr(64); DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE || type == TYPE_ENUM_FUNCTION); @@ -819,7 +822,6 @@ sp_create_routine(THD *thd, int type, sp_head *sp) if (sp->m_type == TYPE_ENUM_FUNCTION) { - String retstr(64); sp_returns_type(thd, retstr, sp); store_failed= store_failed || @@ -919,17 +921,21 @@ sp_create_routine(THD *thd, int type, sp_head *sp) String log_query; log_query.set_charset(system_charset_info); - log_query.append(STRING_WITH_LEN("CREATE ")); - append_definer(thd, &log_query, &thd->lex->definer->user, - &thd->lex->definer->host); - LEX_STRING stmt_definition; - stmt_definition.str= (char*) thd->lex->stmt_definition_begin; - stmt_definition.length= thd->lex->stmt_definition_end - - thd->lex->stmt_definition_begin; - trim_whitespace(thd->charset(), & stmt_definition); - - log_query.append(stmt_definition.str, stmt_definition.length); + if (!create_string(thd, &log_query, + sp->m_type, + (sp->m_explicit_name ? sp->m_db.str : NULL), + (sp->m_explicit_name ? sp->m_db.length : 0), + sp->m_name.str, sp->m_name.length, + sp->m_params.str, sp->m_params.length, + retstr.c_ptr(), retstr.length(), + sp->m_body.str, sp->m_body.length, + sp->m_chistics, &(thd->lex->definer->user), + &(thd->lex->definer->host))) + { + ret= SP_INTERNAL_ERROR; + goto done; + } /* Such a statement can always go directly to binlog, no trans cache */ thd->binlog_query(THD::MYSQL_QUERY_TYPE, @@ -1070,210 +1076,6 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) } -struct st_used_field -{ - const char *field_name; - uint field_length; - enum enum_field_types field_type; - Field *field; -}; - -static struct st_used_field init_fields[]= -{ - { "Db", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0}, - { "Name", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0}, - { "Type", 9, MYSQL_TYPE_STRING, 0}, - { "Definer", USER_HOST_BUFF_SIZE, MYSQL_TYPE_STRING, 0}, - { "Modified", 0, MYSQL_TYPE_TIMESTAMP, 0}, - { "Created", 0, MYSQL_TYPE_TIMESTAMP, 0}, - { "Security_type", 1, MYSQL_TYPE_STRING, 0}, - { "Comment", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0}, - { "character_set_client", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0}, - { "collation_connection", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0}, - { "Database Collation", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0}, - { 0, 0, MYSQL_TYPE_STRING, 0} -}; - - -static int -print_field_values(THD *thd, TABLE *table, - struct st_used_field *used_fields, - int type, const char *wild) -{ - Protocol *protocol= thd->protocol; - - if (table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() == type) - { - String db_string; - String name_string; - struct st_used_field *used_field= used_fields; - - if (get_field(thd->mem_root, used_field->field, &db_string)) - db_string.set_ascii("", 0); - used_field+= 1; - get_field(thd->mem_root, used_field->field, &name_string); - - if (!wild || !wild[0] || !wild_compare(name_string.ptr(), wild, 0)) - { - protocol->prepare_for_resend(); - protocol->store(&db_string); - protocol->store(&name_string); - for (used_field++; - used_field->field_name; - used_field++) - { - switch (used_field->field_type) { - case MYSQL_TYPE_TIMESTAMP: - { - MYSQL_TIME tmp_time; - - bzero((char *)&tmp_time, sizeof(tmp_time)); - ((Field_timestamp *) used_field->field)->get_time(&tmp_time); - protocol->store(&tmp_time); - } - break; - default: - { - String tmp_string; - - get_field(thd->mem_root, used_field->field, &tmp_string); - protocol->store(&tmp_string); - } - break; - } - } - if (protocol->write()) - return SP_INTERNAL_ERROR; - } - } - - return SP_OK; -} - - -/** - Implement SHOW STATUS statement for stored routines. - - @param thd Thread context. - @param type Stored routine type - (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION) - @param name_pattern Stored routine name pattern. - - @return Error code. SP_OK is returned on success. Other SP_ constants are - used to indicate about errors. -*/ - -int -sp_show_status_routine(THD *thd, int type, const char *name_pattern) -{ - TABLE *table; - TABLE_LIST tables; - int res; - DBUG_ENTER("sp_show_status_routine"); - - DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE || - type == TYPE_ENUM_FUNCTION); - - memset(&tables, 0, sizeof(tables)); - tables.db= (char*)"mysql"; - tables.table_name= tables.alias= (char*)"proc"; - - if (! (table= open_ltable(thd, &tables, TL_READ, 0))) - { - res= SP_OPEN_TABLE_FAILED; - goto done; - } - else - { - Item *item; - List<Item> field_list; - struct st_used_field *used_field; - TABLE_LIST *leaves= 0; - st_used_field used_fields[array_elements(init_fields)]; - - table->use_all_columns(); - memcpy((char*) used_fields, (char*) init_fields, sizeof(used_fields)); - /* Init header */ - for (used_field= &used_fields[0]; - used_field->field_name; - used_field++) - { - switch (used_field->field_type) { - case MYSQL_TYPE_TIMESTAMP: - item= new Item_return_date_time(used_field->field_name, - MYSQL_TYPE_DATETIME); - field_list.push_back(item); - break; - default: - item= new Item_empty_string(used_field->field_name, - used_field->field_length); - field_list.push_back(item); - break; - } - } - /* Print header */ - if (thd->protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | - Protocol::SEND_EOF)) - { - res= SP_INTERNAL_ERROR; - goto err_case; - } - - /* - Init fields - - tables is not VIEW for sure => we can pass 0 as condition - */ - thd->lex->select_lex.context.resolve_in_table_list_only(&tables); - setup_tables(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, - &tables, &leaves, FALSE); - for (used_field= &used_fields[0]; - used_field->field_name; - used_field++) - { - Item_field *field= new Item_field(&thd->lex->select_lex.context, - "mysql", "proc", - used_field->field_name); - if (!field || - !(used_field->field= find_field_in_tables(thd, field, &tables, NULL, - 0, REPORT_ALL_ERRORS, 1, - TRUE))) - { - res= SP_INTERNAL_ERROR; - goto err_case1; - } - } - - table->file->ha_index_init(0, 1); - if ((res= table->file->index_first(table->record[0]))) - { - res= (res == HA_ERR_END_OF_FILE) ? 0 : SP_INTERNAL_ERROR; - goto err_case1; - } - - do - { - res= print_field_values(thd, table, used_fields, type, name_pattern); - - if (res) - goto err_case1; - } - while (!table->file->index_next(table->record[0])); - - res= SP_OK; - } - -err_case1: - my_eof(thd); -err_case: - table->file->ha_index_end(); - close_thread_tables(thd); -done: - DBUG_RETURN(res); -} - - /** Drop all routines in database 'db' @@ -2068,17 +1870,18 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, */ static bool create_string(THD *thd, String *buf, - int type, - sp_name *name, - const char *params, ulong paramslen, - const char *returns, ulong returnslen, - const char *body, ulong bodylen, - st_sp_chistics *chistics, + int type, + const char *db, ulong dblen, + const char *name, ulong namelen, + const char *params, ulong paramslen, + const char *returns, ulong returnslen, + const char *body, ulong bodylen, + st_sp_chistics *chistics, const LEX_STRING *definer_user, const LEX_STRING *definer_host) { /* Make some room to begin with */ - if (buf->alloc(100 + name->m_qname.length + paramslen + returnslen + bodylen + + if (buf->alloc(100 + dblen + 1 + namelen + paramslen + returnslen + bodylen + chistics->comment.length + 10 /* length of " DEFINER= "*/ + USER_HOST_BUFF_SIZE)) return FALSE; @@ -2089,7 +1892,12 @@ create_string(THD *thd, String *buf, buf->append(STRING_WITH_LEN("FUNCTION ")); else buf->append(STRING_WITH_LEN("PROCEDURE ")); - append_identifier(thd, buf, name->m_name.str, name->m_name.length); + if (dblen > 0) + { + append_identifier(thd, buf, db, dblen); + buf->append('.'); + } + append_identifier(thd, buf, name, namelen); buf->append('('); buf->append(params, paramslen); buf->append(')'); @@ -49,9 +49,6 @@ bool sp_show_create_routine(THD *thd, int type, sp_name *name); int -sp_show_status_routine(THD *thd, int type, const char *wild); - -int sp_create_routine(THD *thd, int type, sp_head *sp); int diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index cc6ba9ef1d0..64898915b7e 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -210,6 +210,19 @@ void sp_cache_flush_obsolete(sp_cache **cp) } +/** + Return the current version of the cache. +*/ + +ulong sp_cache_version(sp_cache **cp) +{ + sp_cache *c= *cp; + if (c) + return c->version; + return 0; +} + + /************************************************************************* Internal functions *************************************************************************/ diff --git a/sql/sp_cache.h b/sql/sp_cache.h index 9d34c9a2fb5..f4d44a1f29f 100644 --- a/sql/sp_cache.h +++ b/sql/sp_cache.h @@ -58,5 +58,6 @@ void sp_cache_insert(sp_cache **cp, sp_head *sp); sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name); void sp_cache_invalidate(); void sp_cache_flush_obsolete(sp_cache **cp); +ulong sp_cache_version(sp_cache **cp); #endif /* _SP_CACHE_H_ */ diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8bd10e00f15..d1f920fd3a5 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -475,7 +475,7 @@ sp_head::operator new(size_t size) throw() init_sql_alloc(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC); sp= (sp_head *) alloc_root(&own_root, size); if (sp == NULL) - return NULL; + DBUG_RETURN(NULL); sp->main_mem_root= own_root; DBUG_PRINT("info", ("mem_root 0x%lx", (ulong) &sp->mem_root)); DBUG_RETURN(sp); @@ -561,6 +561,8 @@ sp_head::init(LEX *lex) m_qname.str= NULL; m_qname.length= 0; + m_explicit_name= false; + m_db.str= NULL; m_db.length= 0; @@ -603,6 +605,8 @@ sp_head::init_sp_name(THD *thd, sp_name *spname) m_name.str= strmake_root(thd->mem_root, spname->m_name.str, spname->m_name.length); + m_explicit_name= spname->m_explicit_name; + if (spname->m_qname.length == 0) spname->init_qname(thd); @@ -623,14 +627,14 @@ void sp_head::set_body_start(THD *thd, const char *begin_ptr) { m_body_begin= begin_ptr; - thd->m_lip->body_utf8_start(thd, begin_ptr); + thd->m_parser_state->m_lip.body_utf8_start(thd, begin_ptr); } void sp_head::set_stmt_end(THD *thd) { - Lex_input_stream *lip= thd->m_lip; /* shortcut */ + Lex_input_stream *lip= & thd->m_parser_state->m_lip; /* shortcut */ const char *end_ptr= lip->get_cpp_ptr(); /* shortcut */ /* Make the string of parameters. */ @@ -1068,6 +1072,7 @@ sp_head::execute(THD *thd) LEX *old_lex; Item_change_list old_change_list; String old_packet; + Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer; Object_creation_ctx *saved_creation_ctx; @@ -1135,6 +1140,25 @@ sp_head::execute(THD *thd) thd->variables.sql_mode= m_sql_mode; save_abort_on_warning= thd->abort_on_warning; thd->abort_on_warning= 0; + /** + When inside a substatement (a stored function or trigger + statement), clear the metadata observer in THD, if any. + Remember the value of the observer here, to be able + to restore it when leaving the substatement. + + We reset the observer to suppress errors when a substatement + uses temporary tables. If a temporary table does not exist + at start of the main statement, it's not prelocked + and thus is not validated with other prelocked tables. + + Later on, when the temporary table is opened, metadata + versions mismatch, expectedly. + + The proper solution for the problem is to re-validate tables + of substatements (Bug#12257, Bug#27011, Bug#32868, Bug#33000), + but it's not implemented yet. + */ + thd->m_reprepare_observer= 0; /* It is also more efficient to save/restore current thd->lex once when @@ -1297,6 +1321,7 @@ sp_head::execute(THD *thd) thd->derived_tables= old_derived_tables; thd->variables.sql_mode= save_sql_mode; thd->abort_on_warning= save_abort_on_warning; + thd->m_reprepare_observer= save_reprepare_observer; thd->stmt_arena= old_arena; state= EXECUTED; diff --git a/sql/sp_head.h b/sql/sp_head.h index 8d7062740c8..3d7597e2402 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -180,6 +180,7 @@ public: st_sp_chistics *m_chistics; ulong m_sql_mode; ///< For SHOW CREATE and execution LEX_STRING m_qname; ///< db.name + bool m_explicit_name; ///< Prepend the db name? */ /** Key representing routine in the set of stored routines used by statement. [routine_type]db.name diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 4694ca707b7..f91971717be 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -324,7 +324,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) acl_cache->clear(1); // Clear locked hostname cache init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0); - init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0); + init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0, + FALSE); table->use_all_columns(); VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50)); while (!(read_record_info.read_record(&read_record_info))) @@ -373,7 +374,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) end_read_record(&read_record_info); freeze_size(&acl_hosts); - init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0); + init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0,FALSE); table->use_all_columns(); VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100)); password_length= table->field[2]->field_length / @@ -561,7 +562,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) end_read_record(&read_record_info); freeze_size(&acl_users); - init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0); + init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0,FALSE); table->use_all_columns(); VOID(my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100)); while (!(read_record_info.read_record(&read_record_info))) @@ -695,6 +696,8 @@ my_bool acl_reload(THD *thd) tables[0].next_local= tables[0].next_global= tables+1; tables[1].next_local= tables[1].next_global= tables+2; tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ; + tables[0].skip_temporary= tables[1].skip_temporary= + tables[2].skip_temporary= TRUE; if (simple_open_n_lock_tables(thd, tables)) { @@ -3089,12 +3092,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, continue; // Add next user } - db_name= (table_list->view_db.length ? - table_list->view_db.str : - table_list->db); - table_name= (table_list->view_name.length ? - table_list->view_name.str : - table_list->table_name); + db_name= table_list->get_db_name(); + table_name= table_list->get_table_name(); /* Find/create cached table grant */ grant_table= table_hash_search(Str->host.str, NullS, db_name, @@ -3537,7 +3536,7 @@ static my_bool grant_load_procs_priv(TABLE *p_table) bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC); - DBUG_ENTER("grant_load"); + DBUG_ENTER("grant_load_procs_priv"); (void) hash_init(&proc_priv_hash,system_charset_info, 0,0,0, (hash_get_key) get_grant_table, 0,0); @@ -3721,6 +3720,7 @@ static my_bool grant_reload_procs_priv(THD *thd) table.alias= table.table_name= (char*) "procs_priv"; table.db= (char *) "mysql"; table.lock_type= TL_READ; + table.skip_temporary= 1; if (simple_open_n_lock_tables(thd, &table)) { @@ -3786,7 +3786,7 @@ my_bool grant_reload(THD *thd) tables[0].db= tables[1].db= (char *) "mysql"; tables[0].next_local= tables[0].next_global= tables+1; tables[0].lock_type= tables[1].lock_type= TL_READ; - + tables[0].skip_temporary= tables[1].skip_temporary= TRUE; /* To avoid deadlocks we should obtain table locks before obtaining LOCK_grant rwlock. @@ -3903,8 +3903,8 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, if (!want_access) continue; // ok - if (!(~table->grant.privilege & want_access) || - table->derived || table->schema_table) + if (!(~table->grant.privilege & want_access) || + table->is_anonymous_derived_table() || table->schema_table) { /* It is subquery in the FROM clause. VIEW set table->derived after @@ -3922,8 +3922,8 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, continue; } if (!(grant_table= table_hash_search(sctx->host, sctx->ip, - table->db, sctx->priv_user, - table->table_name,0))) + table->get_db_name(), sctx->priv_user, + table->get_table_name(), FALSE))) { want_access &= ~table->grant.privilege; goto err; // No grants @@ -3959,7 +3959,7 @@ err: command, sctx->priv_user, sctx->host_or_ip, - table ? table->table_name : "unknown"); + table ? table->get_table_name() : "unknown"); } DBUG_RETURN(1); } @@ -4114,7 +4114,7 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref, @retval 1 Falure @details This function walks over the columns of a table reference The columns may originate from different tables, depending on the kind of - table reference, e.g. join. + table reference, e.g. join, view. For each table it will retrieve the grant information and will use it to check the required access privileges for the fields requested from it. */ @@ -4129,6 +4129,11 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, GRANT_INFO *grant; /* Initialized only to make gcc happy */ GRANT_TABLE *grant_table= NULL; + /* + Flag that gets set if privilege checking has to be performed on column + level. + */ + bool using_column_privileges= FALSE; rw_rdlock(&LOCK_grant); @@ -4136,10 +4141,10 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, { const char *field_name= fields->name(); - if (table_name != fields->table_name()) + if (table_name != fields->get_table_name()) { - table_name= fields->table_name(); - db_name= fields->db_name(); + table_name= fields->get_table_name(); + db_name= fields->get_db_name(); grant= fields->grant(); /* get a fresh one for each table */ want_access= want_access_arg & ~grant->privilege; @@ -4165,6 +4170,8 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, GRANT_COLUMN *grant_column= column_hash_search(grant_table, field_name, (uint) strlen(field_name)); + if (grant_column) + using_column_privileges= TRUE; if (!grant_column || (~grant_column->rights & want_access)) goto err; } @@ -4177,12 +4184,21 @@ err: char command[128]; get_privilege_desc(command, sizeof(command), want_access); - my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), - command, - sctx->priv_user, - sctx->host_or_ip, - fields->name(), - table_name); + /* + Do not give an error message listing a column name unless the user has + privilege to see all columns. + */ + if (using_column_privileges) + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), + command, sctx->priv_user, + sctx->host_or_ip, table_name); + else + my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), + command, + sctx->priv_user, + sctx->host_or_ip, + fields->name(), + table_name); return 1; } @@ -5695,7 +5711,6 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) while ((tmp_user_name= user_list++)) { - user_name= get_current_user(thd, tmp_user_name); if (!(user_name= get_current_user(thd, tmp_user_name))) { result= TRUE; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 34395332118..ab9fff22b9a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -345,26 +345,9 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key, if (!(share= alloc_table_share(table_list, key, key_length))) { -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - pthread_mutex_unlock(&LOCK_open); -#endif DBUG_RETURN(0); } -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - // We need a write lock to be able to add a new entry - pthread_mutex_unlock(&LOCK_open); - pthread_mutex_lock(&LOCK_open); - /* Check that another thread didn't insert the same table in between */ - if ((old_share= hash_search(&table_def_cache, (uchar*) key, key_length))) - { - (void) pthread_mutex_lock(&share->mutex); - free_table_share(share); - share= old_share; - goto found; - } -#endif - /* Lock mutex to be able to read table definition from file without conflicts @@ -388,29 +371,11 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key, if (my_hash_insert(&table_def_cache, (uchar*) share)) { -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - pthread_mutex_unlock(&LOCK_open); - (void) pthread_mutex_unlock(&share->mutex); -#endif free_table_share(share); DBUG_RETURN(0); // return error } -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - pthread_mutex_unlock(&LOCK_open); -#endif if (open_table_def(thd, share, db_flags)) { -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - /* - No such table or wrong table definition file - Lock first the table cache and then the mutex. - This will ensure that no other thread is using the share - structure. - */ - (void) pthread_mutex_unlock(&share->mutex); - (void) pthread_mutex_lock(&LOCK_open); - (void) pthread_mutex_lock(&share->mutex); -#endif *error= share->error; (void) hash_delete(&table_def_cache, (uchar*) share); DBUG_RETURN(0); @@ -429,9 +394,6 @@ found: /* We must do a lock to ensure that the structure is initialized */ (void) pthread_mutex_lock(&share->mutex); -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - pthread_mutex_unlock(&LOCK_open); -#endif if (share->error) { /* Table definition contained an error */ @@ -618,52 +580,6 @@ void release_table_share(TABLE_SHARE *share, enum release_type type) } pthread_mutex_unlock(&share->mutex); DBUG_VOID_RETURN; - - -#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3 - if (to_be_deleted) - { - /* - We must try again with new locks as we must get LOCK_open - before share->mutex - */ - pthread_mutex_unlock(&share->mutex); - pthread_mutex_lock(&LOCK_open); - pthread_mutex_lock(&share->mutex); - if (!share->ref_count) - { // No one is using this now - TABLE_SHARE *name_lock; - if (share->replace_with_name_lock && (name_lock=get_name_lock(share))) - { - /* - This code is execured when someone does FLUSH TABLES while on has - locked tables. - */ - (void) hash_search(&def_cache,(uchar*) key,key_length); - hash_replace(&def_cache, def_cache.current_record,(uchar*) name_lock); - } - else - { - /* Remove table definition */ - hash_delete(&def_cache,(uchar*) share); - } - pthread_mutex_unlock(&LOCK_open); - free_table_share(share); - } - else - { - pthread_mutex_unlock(&LOCK_open); - if (type == RELEASE_WAIT_FOR_DROP) - wait_for_table(share, "Waiting for close"); - else - pthread_mutex_unlock(&share->mutex); - } - } - else if (type == RELEASE_WAIT_FOR_DROP) - wait_for_table(share, "Waiting for close"); - else - pthread_mutex_unlock(&share->mutex); -#endif } @@ -1453,6 +1369,8 @@ bool close_thread_table(THD *thd, TABLE **table_ptr) DBUG_ASSERT(!table->is_children_attached()); /* Free memory and reset for next loop */ + free_field_buffers_larger_than(table,MAX_TDC_BLOB_SIZE); + table->file->ha_reset(); table->in_use=0; if (unused_tables) @@ -3781,9 +3699,10 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name) share->table_map_id is not ~0UL. */ +static ulong last_table_id= ~0UL; + void assign_new_table_id(TABLE_SHARE *share) { - static ulong last_table_id= ~0UL; DBUG_ENTER("assign_new_table_id"); @@ -3807,6 +3726,70 @@ void assign_new_table_id(TABLE_SHARE *share) DBUG_VOID_RETURN; } +/** + Compare metadata versions of an element obtained from the table + definition cache and its corresponding node in the parse tree. + + @details If the new and the old values mismatch, invoke + Metadata_version_observer. + At prepared statement prepare, all TABLE_LIST version values are + NULL and we always have a mismatch. But there is no observer set + in THD, and therefore no error is reported. Instead, we update + the value in the parse tree, effectively recording the original + version. + At prepared statement execute, an observer may be installed. If + there is a version mismatch, we push an error and return TRUE. + + For conventional execution (no prepared statements), the + observer is never installed. + + @sa Execute_observer + @sa check_prepared_statement() to see cases when an observer is installed + @sa TABLE_LIST::is_table_ref_id_equal() + @sa TABLE_SHARE::get_table_ref_id() + + @param[in] thd used to report errors + @param[in,out] tables TABLE_LIST instance created by the parser + Metadata version information in this object + is updated upon success. + @param[in] table_share an element from the table definition cache + + @retval TRUE an error, which has been reported + @retval FALSE success, version in TABLE_LIST has been updated +*/ + +bool +check_and_update_table_version(THD *thd, + TABLE_LIST *tables, TABLE_SHARE *table_share) +{ + if (! tables->is_table_ref_id_equal(table_share)) + { + if (thd->m_reprepare_observer && + thd->m_reprepare_observer->report_error(thd)) + { + /* + Version of the table share is different from the + previous execution of the prepared statement, and it is + unacceptable for this SQLCOM. Error has been reported. + */ + DBUG_ASSERT(thd->is_error()); + return TRUE; + } + /* Always maintain the latest version and type */ + tables->set_table_ref_id(table_share); + } + + DBUG_EXECUTE_IF("reprepare_each_statement", + if (thd->m_reprepare_observer && + thd->stmt_arena->is_reprepared == FALSE) + { + thd->m_reprepare_observer->report_error(thd); + return TRUE; + }); + + return FALSE; +} + /* Load a table definition from file and open unireg table @@ -3852,6 +3835,12 @@ retry: if (share->is_view) { + /* + This table is a view. Validate its metadata version: in particular, + that it was a view when the statement was prepared. + */ + if (check_and_update_table_version(thd, table_list, share)) + goto err; if (table_list->i_s_requested_object & OPEN_TABLE_ONLY) goto err; @@ -3869,6 +3858,26 @@ retry: release_table_share(share, RELEASE_NORMAL); DBUG_RETURN((flags & OPEN_VIEW_NO_PARSE)? -1 : 0); } + else if (table_list->view) + { + /* + We're trying to open a table for what was a view. + This can only happen during (re-)execution. + At prepared statement prepare the view has been opened and + merged into the statement parse tree. After that, someone + performed a DDL and replaced the view with a base table. + Don't try to open the table inside a prepared statement, + invalidate it instead. + + Note, the assert below is known to fail inside stored + procedures (Bug#27011). + */ + DBUG_ASSERT(thd->m_reprepare_observer); + check_and_update_table_version(thd, table_list, share); + /* Always an error. */ + DBUG_ASSERT(thd->is_error()); + goto err; + } if (table_list->i_s_requested_object & OPEN_VIEW_ONLY) goto err; @@ -4373,6 +4382,11 @@ bool fix_merge_after_open(TABLE_LIST *old_child_list, TABLE_LIST **old_last, prelocking it won't do such precaching and will simply reuse table list which is already built. + If any table has a trigger and start->trg_event_map is non-zero + the final lock will end up in thd->locked_tables, otherwise, the + lock will be placed in thd->lock. See also comments in + st_lex::set_trg_event_type_for_tables(). + RETURN 0 - OK -1 - error @@ -4465,8 +4479,18 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) */ if (tables->schema_table) { - if (!mysql_schema_table(thd, thd->lex, tables)) + /* + If this information_schema table is merged into a mergeable + view, ignore it for now -- it will be filled when its respective + TABLE_LIST is processed. This code works only during re-execution. + */ + if (tables->view) + goto process_view_routines; + if (!mysql_schema_table(thd, thd->lex, tables) && + !check_and_update_table_version(thd, tables, tables->table->s)) + { continue; + } DBUG_RETURN(-1); } (*counter)++; @@ -4585,7 +4609,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) process its triggers since they never will be activated. */ if (!thd->prelocked_mode && !thd->lex->requires_prelocking() && - tables->table->triggers && + tables->trg_event_map && tables->table->triggers && tables->lock_type >= TL_WRITE_ALLOW_WRITE) { if (!query_tables_last_own) @@ -4614,6 +4638,13 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) } tables->table->grant= tables->grant; + /* Check and update metadata version of a base table. */ + if (check_and_update_table_version(thd, tables, tables->table->s)) + { + result= -1; + goto err; + } + /* Attach MERGE children if not locked already. */ DBUG_PRINT("tcache", ("is parent: %d is child: %d", test(tables->table->child_l), @@ -4672,7 +4703,11 @@ process_view_routines: error happens on a MERGE child, clear the parents TABLE reference. */ if (tables->parent_l) + { + if (tables->parent_l->next_global == tables->parent_l->table->child_l) + tables->parent_l->next_global= *tables->parent_l->table->child_last_l; tables->parent_l->table= NULL; + } tables->table= NULL; } DBUG_PRINT("tcache", ("returning: %d", result)); @@ -7583,9 +7618,34 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, continue; #ifndef NO_EMBEDDED_ACCESS_CHECKS - /* Ensure that we have access rights to all fields to be inserted. */ - if (!((table && (table->grant.privilege & SELECT_ACL) || - tables->view && (tables->grant.privilege & SELECT_ACL))) && + /* + Ensure that we have access rights to all fields to be inserted. Under + some circumstances, this check may be skipped. + + - If any_privileges is true, skip the check. + + - If the SELECT privilege has been found as fulfilled already for both + the TABLE and TABLE_LIST objects (and both of these exist, of + course), the check is skipped. + + - If the SELECT privilege has been found fulfilled for the TABLE object + and the TABLE_LIST represents a derived table other than a view (see + below), the check is skipped. + + - If the TABLE_LIST object represents a view, we may skip checking if + the SELECT privilege has been found fulfilled for it, regardless of + the TABLE object. + + - If there is no TABLE object, the test is skipped if either + * the TABLE_LIST does not represent a view, or + * the SELECT privilege has been found fulfilled. + + A TABLE_LIST that is not a view may be a subquery, an + information_schema table, or a nested table reference. See the comment + for TABLE_LIST. + */ + if (!(table && !tables->view && (table->grant.privilege & SELECT_ACL) || + tables->view && (tables->grant.privilege & SELECT_ACL)) && !any_privileges) { field_iterator.set(tables); @@ -7639,19 +7699,19 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, tables->is_natural_join); DBUG_ASSERT(item->type() == Item::FIELD_ITEM); Item_field *fld= (Item_field*) item; - const char *field_table_name= field_iterator.table_name(); + const char *field_table_name= field_iterator.get_table_name(); if (!tables->schema_table && !(fld->have_privileges= (get_column_grant(thd, field_iterator.grant(), - field_iterator.db_name(), + field_iterator.get_db_name(), field_table_name, fld->field_name) & VIEW_ANY_ACL))) { - my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY", + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), "ANY", thd->security_ctx->priv_user, thd->security_ctx->host_or_ip, - fld->field_name, field_table_name); + field_table_name); DBUG_RETURN(TRUE); } } diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index a6d0c8c9e9b..7ca7bef3a56 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -208,6 +208,7 @@ void mysql_client_binlog_statement(THD* thd) #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) if (apply_event_and_update_pos(ev, thd, thd->rli_fake, FALSE)) { + delete ev; /* TODO: Maybe a better error message since the BINLOG statement now contains several events. diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 5d85202aed2..f82cad27207 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -2639,7 +2639,7 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used, tables_used; tables_used= tables_used->next_global, n++, block_table++) { - if (tables_used->derived && !tables_used->view) + if (tables_used->is_anonymous_derived_table()) { DBUG_PRINT("qcache", ("derived table skipped")); n--; @@ -2752,7 +2752,7 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block, tmp++) unlink_table(tmp); } - return (n); + return test(n); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 70947145ef2..a88d0ce5dd1 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -198,6 +198,19 @@ bool foreign_key_prefix(Key *a, Key *b) ** Thread specific functions ****************************************************************************/ +/** Push an error to the error stack and return TRUE for now. */ + +bool +Reprepare_observer::report_error(THD *thd) +{ + my_error(ER_NEED_REPREPARE, MYF(ME_NO_WARNING_FOR_ERROR|ME_NO_SP_HANDLER)); + + m_invalidated= TRUE; + + return TRUE; +} + + Open_tables_state::Open_tables_state(ulong version_arg) :version(version_arg), state_flags(0U) { @@ -506,6 +519,7 @@ THD::THD() lock_id(&main_lock_id), user_time(0), in_sub_stmt(0), binlog_table_maps(0), binlog_flags(0UL), + table_map_for_update(0), arg_of_last_insert_id_function(FALSE), first_successful_insert_id_in_prev_stmt(0), first_successful_insert_id_in_prev_stmt_for_binlog(0), @@ -521,7 +535,7 @@ THD::THD() bootstrap(0), derived_tables_processing(FALSE), spcont(NULL), - m_lip(NULL) + m_parser_state(NULL) { ulong tmp; @@ -1110,6 +1124,8 @@ void THD::cleanup_after_query() free_items(); /* Reset where. */ where= THD::DEFAULT_WHERE; + /* reset table map for multi-table update */ + table_map_for_update= 0; } @@ -1440,6 +1456,7 @@ void THD::rollback_item_tree_changes() select_result::select_result() { thd=current_thd; + nest_level= -1; } void select_result::send_error(uint errcode,const char *err) @@ -1576,6 +1593,12 @@ bool select_send::send_eof() mysql_unlock_tables(thd, thd->lock); thd->lock=0; } + /* + Don't send EOF if we're in error condition (which implies we've already + sent or are sending an error) + */ + if (thd->is_error()) + return TRUE; ::my_eof(thd); is_result_set_started= 0; return FALSE; @@ -2779,7 +2802,8 @@ void THD::restore_backup_open_tables_state(Open_tables_state *backup) DBUG_ASSERT(open_tables == 0 && temporary_tables == 0 && handler_tables == 0 && derived_tables == 0 && lock == 0 && locked_tables == 0 && - prelocked_mode == NON_PRELOCKED); + prelocked_mode == NON_PRELOCKED && + m_reprepare_observer == NULL); set_open_tables_state(backup); DBUG_VOID_RETURN; } @@ -2877,8 +2901,8 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, */ if (rpl_master_erroneous_autoinc(this)) { - backup->auto_inc_intervals_forced= auto_inc_intervals_forced; - auto_inc_intervals_forced.empty(); + DBUG_ASSERT(backup->auto_inc_intervals_forced.nb_elements() == 0); + auto_inc_intervals_forced.swap(&backup->auto_inc_intervals_forced); } #endif @@ -2926,8 +2950,8 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) */ if (rpl_master_erroneous_autoinc(this)) { - auto_inc_intervals_forced= backup->auto_inc_intervals_forced; - backup->auto_inc_intervals_forced.empty(); + backup->auto_inc_intervals_forced.swap(&auto_inc_intervals_forced); + DBUG_ASSERT(backup->auto_inc_intervals_forced.nb_elements() == 0); } #endif @@ -3424,6 +3448,21 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans, } +int THD::binlog_remove_pending_rows_event(bool clear_maps) +{ + DBUG_ENTER(__FUNCTION__); + + if (!mysql_bin_log.is_open()) + DBUG_RETURN(0); + + mysql_bin_log.remove_pending_rows_event(this); + + if (clear_maps) + binlog_table_maps= 0; + + DBUG_RETURN(0); +} + int THD::binlog_flush_pending_rows_event(bool stmt_end) { DBUG_ENTER("THD::binlog_flush_pending_rows_event"); diff --git a/sql/sql_class.h b/sql/sql_class.h index c4f48517be9..8bf3e2390ea 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -22,6 +22,51 @@ #include "log.h" #include "rpl_tblmap.h" + +/** + An interface that is used to take an action when + the locking module notices that a table version has changed + since the last execution. "Table" here may refer to any kind of + table -- a base table, a temporary table, a view or an + information schema table. + + When we open and lock tables for execution of a prepared + statement, we must verify that they did not change + since statement prepare. If some table did change, the statement + parse tree *may* be no longer valid, e.g. in case it contains + optimizations that depend on table metadata. + + This class provides an interface (a method) that is + invoked when such a situation takes place. + The implementation of the method simply reports an error, but + the exact details depend on the nature of the SQL statement. + + At most 1 instance of this class is active at a time, in which + case THD::m_reprepare_observer is not NULL. + + @sa check_and_update_table_version() for details of the + version tracking algorithm + + @sa Open_tables_state::m_reprepare_observer for the life cycle + of metadata observers. +*/ + +class Reprepare_observer +{ +public: + /** + Check if a change of metadata is OK. In future + the signature of this method may be extended to accept the old + and the new versions, but since currently the check is very + simple, we only need the THD to report an error. + */ + bool report_error(THD *thd); + bool is_invalidated() const { return m_invalidated; } + void reset_reprepare_observer() { m_invalidated= FALSE; } +private: + bool m_invalidated; +}; + #include <waiting_threads.h> class Relay_log_info; @@ -32,6 +77,7 @@ class Slave_log_event; class sp_rcontext; class sp_cache; class Lex_input_stream; +class Parser_state; class Rows_log_event; enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; @@ -410,6 +456,7 @@ typedef struct system_status_var ulong filesort_scan_count; /* Prepared statements and binary protocol */ ulong com_stmt_prepare; + ulong com_stmt_reprepare; ulong com_stmt_execute; ulong com_stmt_send_long_data; ulong com_stmt_fetch; @@ -440,7 +487,7 @@ void free_tmp_table(THD *thd, TABLE *entry); /* The following macro is to make init of Query_arena simpler */ #ifndef DBUG_OFF -#define INIT_ARENA_DBUG_INFO is_backup_arena= 0 +#define INIT_ARENA_DBUG_INFO is_backup_arena= 0; is_reprepared= FALSE; #else #define INIT_ARENA_DBUG_INFO #endif @@ -456,6 +503,7 @@ public: MEM_ROOT *mem_root; // Pointer to current memroot #ifndef DBUG_OFF bool is_backup_arena; /* True if this arena is used for backup. */ + bool is_reprepared; #endif /* The states relfects three diffrent life cycles for three @@ -793,6 +841,20 @@ class Open_tables_state { public: /** + As part of class THD, this member is set during execution + of a prepared statement. When it is set, it is used + by the locking subsystem to report a change in table metadata. + + When Open_tables_state part of THD is reset to open + a system or INFORMATION_SCHEMA table, the member is cleared + to avoid spurious ER_NEED_REPREPARE errors -- system and + INFORMATION_SCHEMA tables are not subject to metadata version + tracking. + @sa check_and_update_table_version() + */ + Reprepare_observer *m_reprepare_observer; + + /** List of regular tables in use by this thread. Contains temporary and base tables that were opened with @see open_tables(). */ @@ -895,6 +957,7 @@ public: extra_lock= lock= locked_tables= 0; prelocked_mode= NON_PRELOCKED; state_flags= 0U; + m_reprepare_observer= NULL; } }; @@ -1303,9 +1366,14 @@ public: Rows_log_event* binlog_get_pending_rows_event() const; void binlog_set_pending_rows_event(Rows_log_event* ev); int binlog_flush_pending_rows_event(bool stmt_end); + int binlog_remove_pending_rows_event(bool clear_maps); private: - uint binlog_table_maps; // Number of table maps currently in the binlog + /* + Number of outstanding table maps, i.e., table maps in the + transaction cache. + */ + uint binlog_table_maps; enum enum_binlog_flag { BINLOG_FLAG_UNSAFE_STMT_PRINTED, @@ -1389,6 +1457,13 @@ public: Note: in the parser, stmt_arena == thd, even for PS/SP. */ Query_arena *stmt_arena; + + /* + map for tables that will be updated for a multi-table update query + statement, for other query statements, this will be zero. + */ + table_map table_map_for_update; + /* Tells if LAST_INSERT_ID(#) was called for the current statement */ bool arg_of_last_insert_id_function; /* @@ -1714,13 +1789,11 @@ public: } binlog_evt_union; /** - Character input stream consumed by the lexical analyser, - used during parsing. - Note that since the parser is not re-entrant, we keep only one input - stream here. This member is valid only when executing code during parsing, - and may point to invalid memory after that. + Internal parser state. + Note that since the parser is not re-entrant, we keep only one parser + state here. This member is valid only when executing code during parsing. */ - Lex_input_stream *m_lip; + Parser_state *m_parser_state; #ifdef WITH_PARTITION_STORAGE_ENGINE partition_info *work_part_info; @@ -2198,6 +2271,7 @@ class select_result :public Sql_alloc { protected: THD *thd; SELECT_LEX_UNIT *unit; + uint nest_level; public: select_result(); virtual ~select_result() {}; @@ -2234,6 +2308,12 @@ public: */ virtual void cleanup(); void set_thd(THD *thd_arg) { thd= thd_arg; } + /** + The nest level, if supported. + @return + -1 if nest level is undefined, otherwise a positive integer. + */ + int get_nest_level() { return nest_level; } #ifdef EMBEDDED_LIBRARY virtual void begin_dataset() {} #else @@ -2327,6 +2407,14 @@ class select_export :public select_to_file { bool fixed_row_size; public: select_export(sql_exchange *ex) :select_to_file(ex) {} + /** + Creates a select_export to represent INTO OUTFILE <filename> with a + defined level of subquery nesting. + */ + select_export(sql_exchange *ex, uint nest_level_arg) :select_to_file(ex) + { + nest_level= nest_level_arg; + } ~select_export(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_data(List<Item> &items); @@ -2336,6 +2424,15 @@ public: class select_dump :public select_to_file { public: select_dump(sql_exchange *ex) :select_to_file(ex) {} + /** + Creates a select_export to represent INTO DUMPFILE <filename> with a + defined level of subquery nesting. + */ + select_dump(sql_exchange *ex, uint nest_level_arg) : + select_to_file(ex) + { + nest_level= nest_level_arg; + } int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_data(List<Item> &items); }; @@ -2775,6 +2872,16 @@ class select_dumpvar :public select_result_interceptor { public: List<my_var> var_list; select_dumpvar() { var_list.empty(); row_count= 0;} + /** + Creates a select_dumpvar to represent INTO <variable> with a defined + level of subquery nesting. + */ + select_dumpvar(uint nest_level_arg) + { + var_list.empty(); + row_count= 0; + nest_level= nest_level_arg; + } ~select_dumpvar() {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_data(List<Item> &items); @@ -2790,6 +2897,20 @@ public: #define CF_STATUS_COMMAND 4 #define CF_SHOW_TABLE_COMMAND 8 #define CF_WRITE_LOGS_COMMAND 16 +/** + Must be set for SQL statements that may contain + Item expressions and/or use joins and tables. + Indicates that the parse tree of such statement may + contain rule-based optimizations that depend on metadata + (i.e. number of columns in a table), and consequently + that the statement must be re-prepared whenever + referenced metadata changes. Must not be set for + statements that themselves change metadata, e.g. RENAME, + ALTER and other DDL, since otherwise will trigger constant + reprepare. Consequently, complex item expressions and + joins are currently prohibited in these statements. +*/ +#define CF_REEXECUTION_FRAGILE 32 /* Functions in sql_class.cc */ diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 5c4e93d4c74..7c530cb9013 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -111,7 +111,8 @@ class Select_materialize: public select_union select_result *result; /**< the result object of the caller (PS or SP) */ public: Materialized_cursor *materialized_cursor; - Select_materialize(select_result *result_arg) :result(result_arg) {} + Select_materialize(select_result *result_arg) + :result(result_arg), materialized_cursor(0) {} virtual bool send_fields(List<Item> &list, uint flags); }; @@ -154,6 +155,7 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result, if (! (sensitive_cursor= new (thd->mem_root) Sensitive_cursor(thd, result))) { delete result_materialize; + result_materialize= NULL; return 1; } @@ -211,6 +213,7 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result, if ((rc= materialized_cursor->open(0))) { delete materialized_cursor; + materialized_cursor= NULL; goto err_open; } diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 2c7e0e82b3c..e1bff5e435b 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -883,13 +883,6 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); - /* - 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(); - length= build_table_filename(path, sizeof(path), db, "", "", 0); strmov(path+length, MY_DB_OPT_FILE); // Append db option file name del_dbopt(path); // Remove dboption hash entry @@ -916,14 +909,36 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) error= -1; + /* + We temporarily disable the binary log while dropping the objects + in the database. Since the DROP DATABASE statement is always + replicated as a statement, execution of it will drop all objects + in the database on the slave as well, so there is no need to + replicate the removal of the individual objects in the database + as well. + + This is more of a safety precaution, since normally no objects + should be dropped while the database is being cleaned, but in + the event that a change in the code to remove other objects is + made, these drops should still not be logged. + + Notice that the binary log have to be enabled over the call to + ha_drop_database(), since NDB otherwise detects the binary log + as disabled and will not log the drop database statement on any + other connected server. + */ if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0, &dropped_tables)) >= 0) { ha_drop_database(path); + tmp_disable_binlog(thd); query_cache_invalidate1(db); (void) sp_drop_db_routines(thd, db); /* @todo Do not ignore errors */ +#ifdef HAVE_EVENT_SCHEDULER Events::drop_schema_events(thd, db); +#endif error = 0; + reenable_binlog(thd); } } if (!silent && deleted>=0) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 225c23525ec..5debb3170f7 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -245,7 +245,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, DBUG_RETURN(TRUE); } if (usable_index==MAX_KEY) - init_read_record(&info,thd,table,select,1,1); + init_read_record(&info, thd, table, select, 1, 1, FALSE); else init_read_record_idx(&info, thd, table, 1, usable_index); @@ -834,7 +834,7 @@ int multi_delete::do_deletes() } READ_RECORD info; - init_read_record(&info,thd,table,NULL,0,1); + init_read_record(&info, thd, table, NULL, 0, 1, FALSE); /* Ignore any rows not found in reference tables as they may already have been deleted by foreign key handling diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 10b42e11b26..41be98621a6 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -73,29 +73,59 @@ out: } -/* - Create temporary table structure (but do not fill it) - - SYNOPSIS - mysql_derived_prepare() - thd Thread handle - lex LEX for this thread - orig_table_list TABLE_LIST for the upper SELECT - - IMPLEMENTATION - Derived table is resolved with temporary table. - - After table creation, the above TABLE_LIST is updated with a new table. - - This function is called before any command containing derived table - is executed. - - Derived tables is stored in thd->derived_tables and freed in - close_thread_tables() - - RETURN - FALSE OK - TRUE Error +/** + @brief Create temporary table structure (but do not fill it). + + @param thd Thread handle + @param lex LEX for this thread + @param orig_table_list TABLE_LIST for the upper SELECT + + @details + + This function is called before any command containing derived tables is + executed. Currently the function is used for derived tables, i.e. + + - Anonymous derived tables, or + - Named derived tables (aka views) with the @c TEMPTABLE algorithm. + + The table reference, contained in @c orig_table_list, is updated with the + fields of a new temporary table. + + Derived tables are stored in @c thd->derived_tables and closed by + close_thread_tables(). + + This function is part of the procedure that starts in + open_and_lock_tables(), a procedure that - among other things - introduces + new table and table reference objects (to represent derived tables) that + don't exist in the privilege database. This means that normal privilege + checking cannot handle them. Hence this function does some extra tricks in + order to bypass normal privilege checking, by exploiting the fact that the + current state of privilege verification is attached as GRANT_INFO structures + on the relevant TABLE and TABLE_REF objects. + + For table references, the current state of accrued access is stored inside + TABLE_LIST::grant. Hence this function must update the state of fulfilled + privileges for the new TABLE_LIST, an operation which is normally performed + exclusively by the table and database access checking functions, + check_access() and check_grant(), respectively. This modification is done + for both views and anonymous derived tables: The @c SELECT privilege is set + as fulfilled by the user. However, if a view is referenced and the table + reference is queried against directly (see TABLE_LIST::referencing_view), + the state of privilege checking (GRANT_INFO struct) is copied as-is to the + temporary table. + + This function implements a signature called "derived table processor", and + is passed as a function pointer to mysql_handle_derived(). + + @note This function sets @c SELECT_ACL for @c TEMPTABLE views as well as + anonymous derived tables, but this is ok since later access checking will + distinguish between them. + + @see mysql_handle_derived(), mysql_derived_filling(), GRANT_INFO + + @return + false OK + true Error */ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) diff --git a/sql/sql_help.cc b/sql/sql_help.cc index e424425272e..f51ad318568 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -186,7 +186,7 @@ int search_topics(THD *thd, TABLE *topics, struct st_find_field *find_fields, int count= 0; READ_RECORD read_record_info; - init_read_record(&read_record_info, thd, topics, select,1,0); + init_read_record(&read_record_info, thd, topics, select, 1, 0, FALSE); while (!read_record_info.read_record(&read_record_info)) { if (!select->cond->val_int()) // Doesn't match like @@ -226,7 +226,7 @@ int search_keyword(THD *thd, TABLE *keywords, struct st_find_field *find_fields, int count= 0; READ_RECORD read_record_info; - init_read_record(&read_record_info, thd, keywords, select,1,0); + init_read_record(&read_record_info, thd, keywords, select, 1, 0, FALSE); while (!read_record_info.read_record(&read_record_info) && count<2) { if (!select->cond->val_int()) // Dosn't match like @@ -350,7 +350,7 @@ int search_categories(THD *thd, TABLE *categories, DBUG_ENTER("search_categories"); - init_read_record(&read_record_info, thd, categories, select,1,0); + init_read_record(&read_record_info, thd, categories, select,1,0,FALSE); while (!read_record_info.read_record(&read_record_info)) { if (select && !select->cond->val_int()) @@ -384,7 +384,7 @@ void get_all_items_for_category(THD *thd, TABLE *items, Field *pfname, DBUG_ENTER("get_all_items_for_category"); READ_RECORD read_record_info; - init_read_record(&read_record_info, thd, items, select,1,0); + init_read_record(&read_record_info, thd, items, select,1,0,FALSE); while (!read_record_info.read_record(&read_record_info)) { if (!select->cond->val_int()) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 8ea912ac13f..a275c680cb5 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -695,7 +695,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (thd->slave_thread && (info.handle_duplicates == DUP_UPDATE) && (table->next_number_field != NULL) && - rpl_master_has_bug(&active_mi->rli, 24432)) + rpl_master_has_bug(&active_mi->rli, 24432, TRUE, NULL, NULL)) goto abort; #endif @@ -2308,7 +2308,7 @@ pthread_handler_t handle_delayed_insert(void *arg) if (!(di->table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED)) { thd->fatal_error(); - my_error(ER_ILLEGAL_HA, MYF(0), di->table_list.table_name); + my_error(ER_DELAYED_NOT_SUPPORTED, MYF(0), di->table_list.table_name); goto err; } if (di->table->triggers) @@ -2970,7 +2970,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) if (thd->slave_thread && (info.handle_duplicates == DUP_UPDATE) && (table->next_number_field != NULL) && - rpl_master_has_bug(&active_mi->rli, 24432)) + rpl_master_has_bug(&active_mi->rli, 24432, TRUE, NULL, NULL)) DBUG_RETURN(1); #endif @@ -3068,9 +3068,10 @@ bool select_insert::send_data(List<Item> &values) DBUG_RETURN(1); } } - + error= write_record(thd, table, &info); - + table->auto_increment_field_not_null= FALSE; + if (!error) { if (table->triggers || info.handle_duplicates == DUP_UPDATE) @@ -3526,7 +3527,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) temporary table, we need to start a statement transaction. */ if ((thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) == 0 && - thd->current_stmt_binlog_row_based) + thd->current_stmt_binlog_row_based && + mysql_bin_log.is_open()) { thd->binlog_start_trans_and_stmt(); } @@ -3622,10 +3624,11 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) result= store_create_info(thd, &tmp_table_list, &query, create_info); DBUG_ASSERT(result == 0); /* store_create_info() always return 0 */ - thd->binlog_query(THD::STMT_QUERY_TYPE, - query.ptr(), query.length(), - /* is_trans */ TRUE, - /* suppress_use */ FALSE); + if (mysql_bin_log.is_open()) + thd->binlog_query(THD::STMT_QUERY_TYPE, + query.ptr(), query.length(), + /* is_trans */ TRUE, + /* suppress_use */ FALSE); } void select_create::store_values(List<Item> &values) @@ -3723,7 +3726,7 @@ void select_create::abort() select_insert::abort(); thd->transaction.stmt.modified_non_trans_table= FALSE; reenable_binlog(thd); - + thd->binlog_flush_pending_rows_event(TRUE); if (m_plock) { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 449c2fccb0b..1822176f00a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -371,13 +371,6 @@ void lex_end(LEX *lex) { DBUG_ENTER("lex_end"); DBUG_PRINT("enter", ("lex: 0x%lx", (long) lex)); - if (lex->yacc_yyss) - { - my_free(lex->yacc_yyss, MYF(0)); - my_free(lex->yacc_yyvs, MYF(0)); - lex->yacc_yyss= 0; - lex->yacc_yyvs= 0; - } /* release used plugins */ plugin_unlock_list(0, (plugin_ref*)lex->plugins.buffer, @@ -387,6 +380,14 @@ void lex_end(LEX *lex) DBUG_VOID_RETURN; } +Yacc_state::~Yacc_state() +{ + if (yacc_yyss) + { + my_free(yacc_yyss, MYF(0)); + my_free(yacc_yyvs, MYF(0)); + } +} static int find_keyword(Lex_input_stream *lip, uint len, bool function) { @@ -726,7 +727,7 @@ int MYSQLlex(void *arg, void *yythd) uint length; enum my_lex_states state; THD *thd= (THD *)yythd; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= & thd->m_parser_state->m_lip; LEX *lex= thd->lex; YYSTYPE *yylval=(YYSTYPE*) arg; CHARSET_INFO *cs= thd->charset(); @@ -1317,23 +1318,8 @@ int MYSQLlex(void *arg, void *yythd) lip->yySkip(); return (SET_VAR); case MY_LEX_SEMICOLON: // optional line terminator - if (lip->yyPeek()) - { - if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) && - !lip->stmt_prepare_mode) - { - lex->safe_to_cache_query= 0; - lip->found_semicolon= lip->get_ptr(); - thd->server_status|= SERVER_MORE_RESULTS_EXISTS; - lip->next_state= MY_LEX_END; - lip->set_echo(TRUE); - return (END_OF_INPUT); - } - state= MY_LEX_CHAR; // Return ';' - break; - } - lip->next_state=MY_LEX_END; // Mark for next loop - return(END_OF_INPUT); + state= MY_LEX_CHAR; // Return ';' + break; case MY_LEX_EOL: if (lip->eof()) { @@ -1352,7 +1338,7 @@ int MYSQLlex(void *arg, void *yythd) case MY_LEX_END: lip->next_state=MY_LEX_END; return(0); // We found end of input last time - + /* Actually real shouldn't start with . but allow them anyhow */ case MY_LEX_REAL_OR_POINT: if (my_isdigit(cs,lip->yyPeek())) @@ -2143,7 +2129,7 @@ void Query_tables_list::destroy_query_tables_list() */ st_lex::st_lex() - :result(0), yacc_yyss(0), yacc_yyvs(0), + :result(0), sql_command(SQLCOM_END), option_type(OPT_DEFAULT), is_lex_started(0) { diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 443c85b4854..bb3dc00fc8d 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -417,11 +417,11 @@ public: bool no_table_names_allowed; /* used for global order by */ bool no_error; /* suppress error message (convert it to warnings) */ - static void *operator new(size_t size) + static void *operator new(size_t size) throw () { return sql_alloc(size); } - static void *operator new(size_t size, MEM_ROOT *mem_root) + static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return (void*) alloc_root(mem_root, (uint) size); } static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) {} @@ -1513,7 +1513,6 @@ typedef struct st_lex : public Query_tables_list LEX_STRING comment, ident; LEX_USER *grant_user; XID *xid; - uchar* yacc_yyss, *yacc_yyvs; THD *thd; /* maintain a list of used plugins for this LEX */ @@ -1847,6 +1846,59 @@ typedef struct st_lex : public Query_tables_list } } LEX; + +/** + The internal state of the syntax parser. + This object is only available during parsing, + and is private to the syntax parser implementation (sql_yacc.yy). +*/ +class Yacc_state +{ +public: + Yacc_state() + : yacc_yyss(NULL), yacc_yyvs(NULL) + {} + + ~Yacc_state(); + + /** + Bison internal state stack, yyss, when dynamically allocated using + my_yyoverflow(). + */ + uchar *yacc_yyss; + + /** + Bison internal semantic value stack, yyvs, when dynamically allocated using + my_yyoverflow(). + */ + uchar *yacc_yyvs; + + /* + TODO: move more attributes from the LEX structure here. + */ +}; + +/** + Internal state of the parser. + The complete state consist of: + - state data used during lexical parsing, + - state data used during syntactic parsing. +*/ +class Parser_state +{ +public: + Parser_state(THD *thd, const char* buff, unsigned int length) + : m_lip(thd, buff, length), m_yacc() + {} + + ~Parser_state() + {} + + Lex_input_stream m_lip; + Yacc_state m_yacc; +}; + + struct st_lex_local: public st_lex { static void *operator new(size_t size) throw() diff --git a/sql/sql_list.h b/sql/sql_list.h index 2e068f7f961..0d267111dad 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -29,7 +29,7 @@ public: { return sql_alloc(size); } - static void *operator new[](size_t size) + static void *operator new[](size_t size) throw () { return sql_alloc(size); } @@ -450,7 +450,7 @@ public: struct ilink { struct ilink **prev,*next; - static void *operator new(size_t size) + static void *operator new(size_t size) throw () { return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE)); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 391d2a15df0..1495a5d8e6c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -207,45 +207,56 @@ void init_update_queries(void) { bzero((uchar*) &sql_command_flags, sizeof(sql_command_flags)); - sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA; + sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND; sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND; sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA; - sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA; + sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_BACKUP_TABLE]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_RESTORE_TABLE]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA; - sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA; + sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA; - sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT; - - sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_DATABASES]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_TRIGGERS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_EVENTS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_OPEN_TABLES]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | + CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE; + + sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_DATABASES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_TRIGGERS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_EVENTS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_OPEN_TABLES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_PLUGINS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_FIELDS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_KEYS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_VARIABLES]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_CHARSETS]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_COLLATIONS]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_FIELDS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_KEYS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_VARIABLES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_CHARSETS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_SHOW_COLLATIONS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_NEW_MASTER]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_BINLOGS]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_SLAVE_HOSTS]= CF_STATUS_COMMAND; @@ -269,7 +280,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]= CF_STATUS_COMMAND; - sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_PROC_CODE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_FUNC_CODE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]= CF_STATUS_COMMAND; @@ -277,9 +288,11 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_TABLES]= (CF_STATUS_COMMAND | - CF_SHOW_TABLE_COMMAND); + CF_SHOW_TABLE_COMMAND | + CF_REEXECUTION_FRAGILE); sql_command_flags[SQLCOM_SHOW_TABLE_STATUS]= (CF_STATUS_COMMAND | - CF_SHOW_TABLE_COMMAND); + CF_SHOW_TABLE_COMMAND | + CF_REEXECUTION_FRAGILE); /* The following is used to preserver CF_ROW_COUNT during the @@ -287,7 +300,7 @@ void init_update_queries(void) last called (or executed) statement is preserved. See mysql_execute_command() for how CF_ROW_COUNT is used. */ - sql_command_flags[SQLCOM_CALL]= CF_HAS_ROW_COUNT; + sql_command_flags[SQLCOM_CALL]= CF_HAS_ROW_COUNT | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_EXECUTE]= CF_HAS_ROW_COUNT; /* @@ -323,6 +336,12 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, Vio* save_vio; ulong save_client_capabilities; +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) + thd->profiling.start_new_query(); + thd->profiling.set_query_source(init_command_var->value, + init_command_var->value_length); +#endif + thd_proc_info(thd, "Execution of init_command"); /* We need to lock init_command_var because @@ -344,6 +363,10 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, rw_unlock(var_mutex); thd->client_capabilities= save_client_capabilities; thd->net.vio= save_vio; + +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) + thd->profiling.finish_current_query(); +#endif } @@ -435,6 +458,7 @@ pthread_handler_t handle_bootstrap(void *arg) thd->query[length] = '\0'; DBUG_PRINT("query",("%-.4096s",thd->query)); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) + thd->profiling.start_new_query(); thd->profiling.set_query_source(thd->query, length); #endif @@ -450,6 +474,10 @@ pthread_handler_t handle_bootstrap(void *arg) bootstrap_error= thd->is_error(); net_end_statement(thd); +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) + thd->profiling.finish_current_query(); +#endif + if (bootstrap_error) break; @@ -909,8 +937,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* TODO: set thd->lex->sql_command to SQLCOM_END here */ VOID(pthread_mutex_unlock(&LOCK_thread_count)); - thd->server_status&= - ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); + /** + Clear the set of flags that are expected to be cleared at the + beginning of each command. + */ + thd->server_status&= ~SERVER_STATUS_CLEAR_SET; switch (command) { case COM_INIT_DB: { @@ -1891,6 +1922,10 @@ mysql_execute_command(THD *thd) TABLE_LIST *all_tables; /* most outer SELECT_LEX_UNIT of query */ SELECT_LEX_UNIT *unit= &lex->unit; +#ifdef HAVE_REPLICATION + /* have table map for update for multi-update statement (BUG#37051) */ + bool have_table_map_for_update= FALSE; +#endif /* Saved variable value */ DBUG_ENTER("mysql_execute_command"); #ifdef WITH_PARTITION_STORAGE_ENGINE @@ -1956,6 +1991,48 @@ mysql_execute_command(THD *thd) // force searching in slave.cc:tables_ok() all_tables->updating= 1; } + + /* + For fix of BUG#37051, the master stores the table map for update + in the Query_log_event, and the value is assigned to + thd->variables.table_map_for_update before executing the update + query. + + If thd->variables.table_map_for_update is set, then we are + replicating from a new master, we can use this value to apply + filter rules without opening all the tables. However If + thd->variables.table_map_for_update is not set, then we are + replicating from an old master, so we just skip this and + continue with the old method. And of course, the bug would still + exist for old masters. + */ + if (lex->sql_command == SQLCOM_UPDATE_MULTI && + thd->table_map_for_update) + { + have_table_map_for_update= TRUE; + table_map table_map_for_update= thd->table_map_for_update; + uint nr= 0; + TABLE_LIST *table; + for (table=all_tables; table; table=table->next_global, nr++) + { + if (table_map_for_update & ((table_map)1 << nr)) + table->updating= TRUE; + else + table->updating= FALSE; + } + + if (all_tables_not_ok(thd, all_tables)) + { + /* we warn the slave SQL thread */ + my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); + if (thd->one_shot_set) + reset_one_shot_variables(thd); + DBUG_RETURN(0); + } + + for (table=all_tables; table; table=table->next_global) + table->updating= TRUE; + } /* Check if statment should be skipped because of slave filtering @@ -2018,16 +2095,23 @@ mysql_execute_command(THD *thd) DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE); switch (lex->sql_command) { + case SQLCOM_SHOW_EVENTS: +#ifndef HAVE_EVENT_SCHEDULER + my_error(ER_NOT_SUPPORTED_YET, MYF(0), "embedded server"); + break; +#endif case SQLCOM_SHOW_STATUS_PROC: case SQLCOM_SHOW_STATUS_FUNC: - res= execute_sqlcom_select(thd, all_tables); + if (!(res= check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE))) + res= execute_sqlcom_select(thd, all_tables); break; case SQLCOM_SHOW_STATUS: { system_status_var old_status_var= thd->status_var; thd->initial_status_var= &old_status_var; - res= execute_sqlcom_select(thd, all_tables); + if (!(res= check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE))) + res= execute_sqlcom_select(thd, all_tables); /* Don't log SHOW STATUS commands to slow query log */ thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); @@ -2867,7 +2951,7 @@ end_with_restore_list: #ifdef HAVE_REPLICATION /* Check slave filtering rules */ - if (unlikely(thd->slave_thread)) + if (unlikely(thd->slave_thread && !have_table_map_for_update)) { if (all_tables_not_ok(thd, all_tables)) { @@ -3323,6 +3407,7 @@ end_with_restore_list: can free its locks if LOCK TABLES locked some tables before finding that it can't lock a table in its list */ + ha_autocommit_or_rollback(thd, 1); end_active_trans(thd); thd->options&= ~(OPTION_TABLE_LOCK); } @@ -3504,6 +3589,7 @@ end_with_restore_list: } case SQLCOM_CREATE_EVENT: case SQLCOM_ALTER_EVENT: + #ifdef HAVE_EVENT_SCHEDULER do { DBUG_ASSERT(lex->event_parse_data); @@ -3557,6 +3643,10 @@ end_with_restore_list: lex->drop_if_exists))) my_ok(thd); break; +#else + my_error(ER_NOT_SUPPORTED_YET,MYF(0),"embedded server"); + break; +#endif case SQLCOM_CREATE_FUNCTION: // UDF function { if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0)) @@ -4326,20 +4416,6 @@ create_sp_error: } break; } -#ifdef NOT_USED - case SQLCOM_SHOW_STATUS_PROC: - { - res= sp_show_status_routine(thd, TYPE_ENUM_PROCEDURE, - (lex->wild ? lex->wild->ptr() : NullS)); - break; - } - case SQLCOM_SHOW_STATUS_FUNC: - { - res= sp_show_status_routine(thd, TYPE_ENUM_FUNCTION, - (lex->wild ? lex->wild->ptr() : NullS)); - break; - } -#endif #ifndef DBUG_OFF case SQLCOM_SHOW_PROC_CODE: case SQLCOM_SHOW_FUNC_CODE: @@ -4820,6 +4896,8 @@ bool check_single_table_access(THD *thd, ulong privilege, /* Show only 1 table for check_grant */ if (!(all_tables->belong_to_view && (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && + !(all_tables->view && + all_tables->effective_algorithm == VIEW_ALGORITHM_TMPTABLE) && check_grant(thd, privilege, all_tables, 0, 1, no_errors)) goto deny; @@ -5131,7 +5209,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, continue; } - if (tables->derived || + if (tables->is_anonymous_derived_table() || (tables->table && (int)tables->table->s->tmp_table)) continue; thd->security_ctx= sctx; @@ -5141,12 +5219,14 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, tables->grant.privilege= want_access; else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0) { - if (check_access(thd,want_access,tables->db,&tables->grant.privilege, - 0, no_errors, test(tables->schema_table))) + if (check_access(thd, want_access, tables->get_db_name(), + &tables->grant.privilege, 0, no_errors, + test(tables->schema_table))) goto deny; // Access denied } - else if (check_access(thd,want_access,tables->db,&tables->grant.privilege, - 0, no_errors, test(tables->schema_table))) + else if (check_access(thd, want_access, tables->get_db_name(), + &tables->grant.privilege, 0, no_errors, + test(tables->schema_table))) goto deny; } thd->security_ctx= backup_ctx; @@ -5331,29 +5411,35 @@ bool check_stack_overrun(THD *thd, long margin, bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize) { - LEX *lex= current_thd->lex; + Yacc_state *state= & current_thd->m_parser_state->m_yacc; ulong old_info=0; + DBUG_ASSERT(state); if ((uint) *yystacksize >= MY_YACC_MAX) return 1; - if (!lex->yacc_yyvs) + if (!state->yacc_yyvs) old_info= *yystacksize; *yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX); - if (!(lex->yacc_yyvs= (uchar*) - my_realloc(lex->yacc_yyvs, - *yystacksize*sizeof(**yyvs), - MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) || - !(lex->yacc_yyss= (uchar*) - my_realloc(lex->yacc_yyss, - *yystacksize*sizeof(**yyss), - MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR)))) + if (!(state->yacc_yyvs= (uchar*) + my_realloc(state->yacc_yyvs, + *yystacksize*sizeof(**yyvs), + MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) || + !(state->yacc_yyss= (uchar*) + my_realloc(state->yacc_yyss, + *yystacksize*sizeof(**yyss), + MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR)))) return 1; if (old_info) - { // Copy old info from stack - memcpy(lex->yacc_yyss, (uchar*) *yyss, old_info*sizeof(**yyss)); - memcpy(lex->yacc_yyvs, (uchar*) *yyvs, old_info*sizeof(**yyvs)); + { + /* + Only copy the old stack on the first call to my_yyoverflow(), + when replacing a static stack (YYINITDEPTH) by a dynamic stack. + For subsequent calls, my_realloc already did preserve the old stack. + */ + memcpy(state->yacc_yyss, *yyss, old_info*sizeof(**yyss)); + memcpy(state->yacc_yyvs, *yyvs, old_info*sizeof(**yyvs)); } - *yyss=(short*) lex->yacc_yyss; - *yyvs=(YYSTYPE*) lex->yacc_yyvs; + *yyss= (short*) state->yacc_yyss; + *yyvs= (YYSTYPE*) state->yacc_yyvs; return 0; } @@ -5389,9 +5475,11 @@ void mysql_reset_thd_for_next_command(THD *thd) thd->query_start_used= 0; thd->is_fatal_error= thd->time_zone_used= 0; - thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | - SERVER_QUERY_NO_INDEX_USED | - SERVER_QUERY_NO_GOOD_INDEX_USED); + /* + Clear the status flag that are expected to be cleared at the + beginning of each SQL statement. + */ + thd->server_status&= ~SERVER_STATUS_CLEAR_SET; /* If in autocommit mode and not in a transaction, reset OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG to not get warnings @@ -5616,10 +5704,10 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, sp_cache_flush_obsolete(&thd->sp_proc_cache); sp_cache_flush_obsolete(&thd->sp_func_cache); - Lex_input_stream lip(thd, inBuf, length); + Parser_state parser_state(thd, inBuf, length); - bool err= parse_sql(thd, &lip, NULL); - *found_semicolon= lip.found_semicolon; + bool err= parse_sql(thd, & parser_state, NULL); + *found_semicolon= parser_state.m_lip.found_semicolon; if (!err) { @@ -5648,6 +5736,11 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, (thd->query_length= (ulong)(*found_semicolon - thd->query))) thd->query_length--; /* Actually execute the query */ + if (*found_semicolon) + { + lex->safe_to_cache_query= 0; + thd->server_status|= SERVER_MORE_RESULTS_EXISTS; + } lex->set_trg_event_type_for_tables(); mysql_execute_command(thd); } @@ -5699,11 +5792,11 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length) bool error= 0; DBUG_ENTER("mysql_test_parse_for_slave"); - Lex_input_stream lip(thd, inBuf, length); + Parser_state parser_state(thd, inBuf, length); lex_start(thd); mysql_reset_thd_for_next_command(thd); - if (!parse_sql(thd, &lip, NULL) && + if (!parse_sql(thd, & parser_state, NULL) && all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first)) error= 1; /* Ignore question */ thd->end_statement(); @@ -6480,15 +6573,24 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, thd->store_globals(); lex_start(thd); } + if (thd) { - if (acl_reload(thd)) - result= 1; - if (grant_reload(thd)) + bool reload_acl_failed= acl_reload(thd); + bool reload_grants_failed= grant_reload(thd); + bool reload_servers_failed= servers_reload(thd); + + if (reload_acl_failed || reload_grants_failed || reload_servers_failed) + { result= 1; - if (servers_reload(thd)) - result= 1; /* purecov: inspected */ + /* + When an error is returned, my_message may have not been called and + the client will hang waiting for a response. + */ + my_error(ER_UNKNOWN_ERROR, MYF(0), "FLUSH PRIVILEGES failed"); + } } + if (tmp_thd) { delete tmp_thd; @@ -6577,8 +6679,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, tmp_write_to_binlog= 0; if (lock_global_read_lock(thd)) return 1; // Killed - result= close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ? - FALSE : TRUE, TRUE); + if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ? + FALSE : TRUE, TRUE)) + result= 1; + if (make_global_read_lock_block_commit(thd)) // Killed { /* Don't leave things in a half-locked state */ @@ -6587,8 +6691,11 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, } } else - result= close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ? - FALSE : TRUE, FALSE); + { + if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ? + FALSE : TRUE, FALSE)) + result= 1; + } my_dbopt_cleanup(); } if (options & REFRESH_HOSTS) @@ -6611,8 +6718,8 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, #ifdef OPENSSL if (options & REFRESH_DES_KEY_FILE) { - if (des_key_file) - result=load_des_key_file(des_key_file); + if (des_key_file && load_des_key_file(des_key_file)) + result= 1; } #endif #ifdef HAVE_REPLICATION @@ -6742,7 +6849,7 @@ bool check_simple_select() if (lex->current_select != &lex->select_lex) { char command[80]; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= & thd->m_parser_state->m_lip; strmake(command, lip->yylval->symbol.str, min(lip->yylval->symbol.length, sizeof(command)-1)); my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command); @@ -7380,11 +7487,12 @@ bool check_string_char_length(LEX_STRING *str, const char *err_msg, 0 ok 1 error */ +C_MODE_START -bool test_if_data_home_dir(const char *dir) +int test_if_data_home_dir(const char *dir) { - char path[FN_REFLEN], conv_path[FN_REFLEN]; - uint dir_len, home_dir_len= strlen(mysql_unpacked_real_data_home); + char path[FN_REFLEN]; + int dir_len; DBUG_ENTER("test_if_data_home_dir"); if (!dir) @@ -7392,24 +7500,30 @@ bool test_if_data_home_dir(const char *dir) (void) fn_format(path, dir, "", "", (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS)); - dir_len= unpack_dirname(conv_path, dir); - - if (home_dir_len < dir_len) + dir_len= strlen(path); + if (mysql_unpacked_real_data_home_len<= dir_len) { + if (dir_len > mysql_unpacked_real_data_home_len && + path[mysql_unpacked_real_data_home_len] != FN_LIBCHAR) + DBUG_RETURN(0); + if (lower_case_file_system) { - if (!my_strnncoll(character_set_filesystem, - (const uchar*) conv_path, home_dir_len, + if (!my_strnncoll(default_charset_info, (const uchar*) path, + mysql_unpacked_real_data_home_len, (const uchar*) mysql_unpacked_real_data_home, - home_dir_len)) + mysql_unpacked_real_data_home_len)) DBUG_RETURN(1); } - else if (!memcmp(conv_path, mysql_unpacked_real_data_home, home_dir_len)) + else if (!memcmp(path, mysql_unpacked_real_data_home, + mysql_unpacked_real_data_home_len)) DBUG_RETURN(1); } DBUG_RETURN(0); } +C_MODE_END + extern int MYSQLparse(void *thd); // from sql_yacc.cc @@ -7419,7 +7533,7 @@ extern int MYSQLparse(void *thd); // from sql_yacc.cc instead of MYSQLparse(). @param thd Thread context. - @param lip Lexer context. + @param parser_state Parser state. @param creation_ctx Object creation context. @return Error status. @@ -7428,11 +7542,11 @@ extern int MYSQLparse(void *thd); // from sql_yacc.cc */ bool parse_sql(THD *thd, - Lex_input_stream *lip, + Parser_state *parser_state, Object_creation_ctx *creation_ctx) { bool mysql_parse_status; - DBUG_ASSERT(thd->m_lip == NULL); + DBUG_ASSERT(thd->m_parser_state == NULL); /* Backup creation context. */ @@ -7441,9 +7555,9 @@ bool parse_sql(THD *thd, if (creation_ctx) backup_ctx= creation_ctx->set_n_backup(thd); - /* Set Lex_input_stream. */ + /* Set parser state. */ - thd->m_lip= lip; + thd->m_parser_state= parser_state; /* Parse the query. */ @@ -7454,9 +7568,9 @@ bool parse_sql(THD *thd, DBUG_ASSERT(!mysql_parse_status || mysql_parse_status && thd->is_error()); - /* Reset Lex_input_stream. */ + /* Reset parser state. */ - thd->m_lip= NULL; + thd->m_parser_state= NULL; /* Restore creation context. */ diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 037da87be7f..6419d336b9f 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3767,7 +3767,7 @@ bool mysql_unpack_partition(THD *thd, thd->lex= &lex; thd->variables.character_set_client= system_charset_info; - Lex_input_stream lip(thd, part_buf, part_info_len); + Parser_state parser_state(thd, part_buf, part_info_len); lex_start(thd); *work_part_info_used= false; @@ -3797,7 +3797,7 @@ bool mysql_unpack_partition(THD *thd, lex.part_info->part_state= part_state; lex.part_info->part_state_len= part_state_len; DBUG_PRINT("info", ("Parse: %s", part_buf)); - if (parse_sql(thd, &lip, NULL)) + if (parse_sql(thd, & parser_state, NULL)) { thd->free_items(); goto end; @@ -4080,6 +4080,38 @@ error: /* + Sets which partitions to be used in the command +*/ +uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info, + enum partition_state part_state) +{ + uint part_count= 0; + uint no_parts_found= 0; + List_iterator<partition_element> part_it(tab_part_info->partitions); + + do + { + partition_element *part_elem= part_it++; + if ((alter_info->flags & ALTER_ALL_PARTITION) || + (is_name_in_list(part_elem->partition_name, + alter_info->partition_names))) + { + /* + Mark the partition. + I.e mark the partition as a partition to be "changed" by + analyzing/optimizing/rebuilding/checking/repairing + */ + no_parts_found++; + part_elem->part_state= part_state; + DBUG_PRINT("info", ("Setting part_state to %u for partition %s", + part_state, part_elem->partition_name)); + } + } while (++part_count < tab_part_info->no_parts); + return no_parts_found; +} + + +/* Prepare for ALTER TABLE of partition structure SYNOPSIS @@ -4534,26 +4566,9 @@ that are reorganised. (alter_info->flags & ALTER_REPAIR_PARTITION) || (alter_info->flags & ALTER_REBUILD_PARTITION)) { + uint no_parts_found; uint no_parts_opt= alter_info->partition_names.elements; - uint part_count= 0; - uint no_parts_found= 0; - List_iterator<partition_element> part_it(tab_part_info->partitions); - - do - { - partition_element *part_elem= part_it++; - if ((alter_info->flags & ALTER_ALL_PARTITION) || - (is_name_in_list(part_elem->partition_name, - alter_info->partition_names))) - { - /* - Mark the partition as a partition to be "changed" by - analyzing/optimizing/rebuilding/checking/repairing - */ - no_parts_found++; - part_elem->part_state= PART_CHANGED; - } - } while (++part_count < tab_part_info->no_parts); + no_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED); if (no_parts_found != no_parts_opt && (!(alter_info->flags & ALTER_ALL_PARTITION))) { @@ -6026,48 +6041,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, lpt->pack_frm_len= 0; thd->work_part_info= part_info; - if (alter_info->flags & ALTER_OPTIMIZE_PARTITION || - alter_info->flags & ALTER_ANALYZE_PARTITION || - alter_info->flags & ALTER_CHECK_PARTITION || - alter_info->flags & ALTER_REPAIR_PARTITION) - { - /* - In this case the user has specified that he wants a set of partitions - to be optimised and the partition engine can handle optimising - partitions natively without requiring a full rebuild of the - partitions. - - In this case it is enough to call optimise_partitions, there is no - need to change frm files or anything else. - */ - int error; - written_bin_log= FALSE; - if (((alter_info->flags & ALTER_OPTIMIZE_PARTITION) && - (error= table->file->ha_optimize_partitions(thd))) || - ((alter_info->flags & ALTER_ANALYZE_PARTITION) && - (error= table->file->ha_analyze_partitions(thd))) || - ((alter_info->flags & ALTER_CHECK_PARTITION) && - (error= table->file->ha_check_partitions(thd))) || - ((alter_info->flags & ALTER_REPAIR_PARTITION) && - (error= table->file->ha_repair_partitions(thd)))) - { - if (error == HA_ADMIN_NOT_IMPLEMENTED) { - if (alter_info->flags & ALTER_OPTIMIZE_PARTITION) - my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "optimize partition"); - else if (alter_info->flags & ALTER_ANALYZE_PARTITION) - my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "analyze partition"); - else if (alter_info->flags & ALTER_CHECK_PARTITION) - my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "check partition"); - else if (alter_info->flags & ALTER_REPAIR_PARTITION) - my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "repair partition"); - else - table->file->print_error(error, MYF(0)); - } else - table->file->print_error(error, MYF(0)); - goto err; - } - } - else if (fast_alter_partition & HA_PARTITION_ONE_PHASE) + if (fast_alter_partition & HA_PARTITION_ONE_PHASE) { /* In the case where the engine supports one phase online partition diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index e3ee1305e01..1b56683c0ed 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1137,9 +1137,10 @@ int plugin_init(int *argc, char **argv, int flags) { for (plugin= *builtins; plugin->info; plugin++) { - /* by default, only ndbcluster is disabled */ + /* by default, ndbcluster and federated are disabled */ def_enabled= - my_strcasecmp(&my_charset_latin1, plugin->name, "NDBCLUSTER") != 0; + my_strcasecmp(&my_charset_latin1, plugin->name, "NDBCLUSTER") != 0 && + my_strcasecmp(&my_charset_latin1, plugin->name, "FEDERATED") != 0; bzero(&tmp, sizeof(tmp)); tmp.plugin= plugin; tmp.name.str= (char *)plugin->name; @@ -1360,7 +1361,7 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv) goto end; } table= tables.table; - init_read_record(&read_record_info, new_thd, table, NULL, 1, 0); + init_read_record(&read_record_info, new_thd, table, NULL, 1, 0, FALSE); table->use_all_columns(); /* there're no other threads running yet, so we don't need a mutex. @@ -1661,11 +1662,18 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl goto deinit; } + /* + We do not replicate the INSTALL PLUGIN statement. Disable binlogging + of the insert into the plugin table, so that it is not replicated in + row based mode. + */ + tmp_disable_binlog(thd); table->use_all_columns(); restore_record(table, s->default_values); table->field[0]->store(name->str, name->length, system_charset_info); table->field[1]->store(dl->str, dl->length, files_charset_info); error= table->file->ha_write_row(table->record[0]); + reenable_binlog(thd); if (error) { table->file->print_error(error, MYF(0)); @@ -1730,7 +1738,15 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) HA_READ_KEY_EXACT)) { int error; - if ((error= table->file->ha_delete_row(table->record[0]))) + /* + We do not replicate the UNINSTALL PLUGIN statement. Disable binlogging + of the delete from the plugin table, so that it is not replicated in + row based mode. + */ + tmp_disable_binlog(thd); + error= table->file->ha_delete_row(table->record[0]); + reenable_binlog(thd); + if (error) { table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); @@ -1881,7 +1897,7 @@ static int check_func_bool(THD *thd, struct st_mysql_sys_var *var, } result= (int) tmp; } - *(int*)save= -result; + *(my_bool *) save= -result; return 0; err: my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue); @@ -2062,7 +2078,7 @@ err: static void update_func_bool(THD *thd, struct st_mysql_sys_var *var, void *tgt, const void *save) { - *(my_bool *) tgt= *(int *) save ? 1 : 0; + *(my_bool *) tgt= *(my_bool *) save ? TRUE : FALSE; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 233dcefa4e0..1a93d8d5099 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -155,21 +155,30 @@ public: virtual void cleanup_stmt(); bool set_name(LEX_STRING *name); inline void close_cursor() { delete cursor; cursor= 0; } - + inline bool is_in_use() { return flags & (uint) IS_IN_USE; } + inline bool is_protocol_text() const { return protocol == &thd->protocol_text; } bool prepare(const char *packet, uint packet_length); - bool execute(String *expanded_query, bool open_cursor); + bool execute_loop(String *expanded_query, + bool open_cursor, + uchar *packet_arg, uchar *packet_end_arg); /* Destroy this statement */ - bool deallocate(); + void 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; + /* Version of the stored functions cache at the time of prepare. */ + ulong m_sp_cache_version; +private: + bool set_db(const char *db, uint db_length); + bool set_parameters(String *expanded_query, + uchar *packet, uchar *packet_end); + bool execute(String *expanded_query, bool open_cursor); + bool reprepare(); + bool validate_metadata(Prepared_statement *copy); + void swap_prepared_statement(Prepared_statement *copy); }; @@ -198,7 +207,7 @@ inline bool is_param_null(const uchar *pos, ulong param_no) */ static Prepared_statement * -find_prepared_statement(THD *thd, ulong id, const char *where) +find_prepared_statement(THD *thd, ulong id) { /* To strictly separate namespaces of SQL prepared statements and C API @@ -208,12 +217,8 @@ find_prepared_statement(THD *thd, ulong id, const char *where) Statement *stmt= thd->stmt_map.find(id); if (stmt == 0 || stmt->type() != Query_arena::PREPARED_STATEMENT) - { - char llbuf[22]; - my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), llstr(id, llbuf), - where); - return 0; - } + return NULL; + return (Prepared_statement *) stmt; } @@ -945,6 +950,55 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt, #endif /*!EMBEDDED_LIBRARY*/ +/** + Setup data conversion routines using an array of parameter + markers from the original prepared statement. + Swap the parameter data of the original prepared + statement to the new one. + + Used only when we re-prepare a prepared statement. + There are two reasons for this function to exist: + + 1) In the binary client/server protocol, parameter metadata + is sent only at first execute. Consequently, if we need to + reprepare a prepared statement at a subsequent execution, + we may not have metadata information in the packet. + In that case we use the parameter array of the original + prepared statement to setup parameter types of the new + prepared statement. + + 2) In the binary client/server protocol, we may supply + long data in pieces. When the last piece is supplied, + we assemble the pieces and convert them from client + character set to the connection character set. After + that the parameter value is only available inside + the parameter, the original pieces are lost, and thus + we can only assign the corresponding parameter of the + reprepared statement from the original value. + + @param[out] param_array_dst parameter markers of the new statement + @param[in] param_array_src parameter markers of the original + statement + @param[in] param_count total number of parameters. Is the + same in src and dst arrays, since + the statement query is the same + + @return this function never fails +*/ + +static void +swap_parameter_array(Item_param **param_array_dst, + Item_param **param_array_src, + uint param_count) +{ + Item_param **dst= param_array_dst; + Item_param **src= param_array_src; + Item_param **end= param_array_dst + param_count; + + for (; dst < end; ++src, ++dst) + (*dst)->set_param_type_and_swap_value(*src); +} + /** Assign prepared statement parameters from user variables. @@ -1104,9 +1158,9 @@ static bool mysql_test_insert(Prepared_statement *stmt, if (table_list->lock_type == TL_WRITE_DELAYED && !(table_list->table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED)) { - my_error(ER_ILLEGAL_HA, MYF(0), (table_list->view ? - table_list->view_name.str : - table_list->table_name)); + my_error(ER_DELAYED_NOT_SUPPORTED, MYF(0), (table_list->view ? + table_list->view_name.str : + table_list->table_name)); goto error; } while ((values= its++)) @@ -1270,7 +1324,7 @@ error: */ static int mysql_test_select(Prepared_statement *stmt, - TABLE_LIST *tables, bool text_protocol) + TABLE_LIST *tables) { THD *thd= stmt->thd; LEX *lex= stmt->lex; @@ -1306,7 +1360,7 @@ static int mysql_test_select(Prepared_statement *stmt, */ if (unit->prepare(thd, 0, 0)) goto error; - if (!lex->describe && !text_protocol) + if (!lex->describe && !stmt->is_protocol_text()) { /* Make copy of item list, as change_columns may change it */ List<Item> fields(lex->select_lex.item_list); @@ -1398,6 +1452,43 @@ error: /** + Validate and prepare for execution CALL statement expressions. + + @param stmt prepared statement + @param tables list of tables used in this query + @param value_list list of expressions + + @retval FALSE success + @retval TRUE error, error message is set in THD +*/ + +static bool mysql_test_call_fields(Prepared_statement *stmt, + TABLE_LIST *tables, + List<Item> *value_list) +{ + DBUG_ENTER("mysql_test_call_fields"); + + List_iterator<Item> it(*value_list); + THD *thd= stmt->thd; + Item *item; + + if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE) || + open_normal_and_derived_tables(thd, tables, 0)) + goto err; + + while ((item= it++)) + { + if (!item->fixed && item->fix_fields(thd, it.ref()) || + item->check_cols(1)) + goto err; + } + DBUG_RETURN(FALSE); +err: + DBUG_RETURN(TRUE); +} + + +/** Check internal SELECT of the prepared command. @param stmt prepared statement @@ -1518,6 +1609,17 @@ static bool mysql_test_create_table(Prepared_statement *stmt) res= select_like_stmt_test(stmt, 0, 0); } + else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE) + { + /* + Check that the source table exist, and also record + its metadata version. Even though not strictly necessary, + we validate metadata of all CREATE TABLE statements, + which keeps metadata validation code simple. + */ + if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0)) + DBUG_RETURN(TRUE); + } /* put tables back for PS rexecuting */ lex->link_first_table_back(create_table, link_to_local); @@ -1714,8 +1816,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt, TRUE error, error message is set in THD (but not sent) */ -static bool check_prepared_statement(Prepared_statement *stmt, - bool text_protocol) +static bool check_prepared_statement(Prepared_statement *stmt) { THD *thd= stmt->thd; LEX *lex= stmt->lex; @@ -1756,9 +1857,23 @@ static bool check_prepared_statement(Prepared_statement *stmt, case SQLCOM_DELETE: res= mysql_test_delete(stmt, tables); break; - + /* The following allow WHERE clause, so they must be tested like SELECT */ + case SQLCOM_SHOW_DATABASES: + case SQLCOM_SHOW_TABLES: + case SQLCOM_SHOW_TRIGGERS: + case SQLCOM_SHOW_EVENTS: + case SQLCOM_SHOW_OPEN_TABLES: + case SQLCOM_SHOW_FIELDS: + case SQLCOM_SHOW_KEYS: + case SQLCOM_SHOW_COLLATIONS: + case SQLCOM_SHOW_CHARSETS: + case SQLCOM_SHOW_VARIABLES: + case SQLCOM_SHOW_STATUS: + case SQLCOM_SHOW_TABLE_STATUS: + case SQLCOM_SHOW_STATUS_PROC: + case SQLCOM_SHOW_STATUS_FUNC: case SQLCOM_SELECT: - res= mysql_test_select(stmt, tables, text_protocol); + res= mysql_test_select(stmt, tables); if (res == 2) { /* Statement and field info has already been sent */ @@ -1781,6 +1896,9 @@ static bool check_prepared_statement(Prepared_statement *stmt, res= mysql_test_do_fields(stmt, tables, lex->insert_list); break; + case SQLCOM_CALL: + res= mysql_test_call_fields(stmt, tables, &lex->value_list); + break; case SQLCOM_SET_OPTION: res= mysql_test_set_fields(stmt, tables, &lex->var_list); break; @@ -1830,7 +1948,6 @@ static bool check_prepared_statement(Prepared_statement *stmt, case SQLCOM_DROP_INDEX: case SQLCOM_ROLLBACK: case SQLCOM_TRUNCATE: - case SQLCOM_CALL: case SQLCOM_DROP_VIEW: case SQLCOM_REPAIR: case SQLCOM_ANALYZE: @@ -1873,8 +1990,8 @@ static bool check_prepared_statement(Prepared_statement *stmt, break; } if (res == 0) - DBUG_RETURN(text_protocol? FALSE : (send_prep_stmt(stmt, 0) || - thd->protocol->flush())); + DBUG_RETURN(stmt->is_protocol_text() ? + FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush())); error: DBUG_RETURN(TRUE); } @@ -2123,8 +2240,13 @@ void mysql_sql_stmt_prepare(THD *thd) If there is a statement with the same name, remove it. It is ok to remove old and fail to insert a new one at the same time. */ - if (stmt->deallocate()) + if (stmt->is_in_use()) + { + my_error(ER_PS_NO_RECURSION, MYF(0)); DBUG_VOID_RETURN; + } + + stmt->deallocate(); } if (! (query= get_dynamic_sql_string(lex, &query_len)) || @@ -2310,10 +2432,9 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) 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= packet + packet_length; -#endif Prepared_statement *stmt; + bool open_cursor; DBUG_ENTER("mysql_stmt_execute"); packet+= 9; /* stmt_id + 5 bytes of flags */ @@ -2321,8 +2442,13 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) /* First of all clear possible warnings from the previous command */ mysql_reset_thd_for_next_command(thd); - if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) + if (!(stmt= find_prepared_statement(thd, stmt_id))) + { + char llbuf[22]; + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), + llstr(stmt_id, llbuf), "mysql_stmt_execute"); DBUG_VOID_RETURN; + } #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.set_query_source(stmt->query, stmt->query_length); @@ -2333,43 +2459,10 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) sp_cache_flush_obsolete(&thd->sp_proc_cache); sp_cache_flush_obsolete(&thd->sp_func_cache); -#ifndef EMBEDDED_LIBRARY - if (stmt->param_count) - { - 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; - } -#else - /* - In embedded library we re-install conversion routines each time - we set params, and also we don't need to parse packet. - So we do it in one function. - */ - if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query)) - goto set_params_data_err; -#endif - if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(),QUERY_PRIOR); - - /* - If the free_list is not empty, we'll wrongly free some externally - allocated items when cleaning up after validation of the prepared - statement. - */ - DBUG_ASSERT(thd->free_list == NULL); + open_cursor= test(flags & (ulong) CURSOR_TYPE_READ_ONLY); - (void) stmt->execute(&expanded_query, - test(flags & (ulong) CURSOR_TYPE_READ_ONLY)); - if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(), WAIT_PRIOR); - DBUG_VOID_RETURN; + stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end); -set_params_data_err: - my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute"); - reset_stmt_params(stmt); DBUG_VOID_RETURN; } @@ -2416,25 +2509,9 @@ void mysql_sql_stmt_execute(THD *thd) DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt)); - /* - If the free_list is not empty, we'll wrongly free some externally - allocated items when cleaning up after validation of the prepared - statement. - */ - DBUG_ASSERT(thd->free_list == NULL); - - if (stmt->set_params_from_vars(stmt, lex->prepared_stmt_params, - &expanded_query)) - goto set_params_data_err; - - (void) stmt->execute(&expanded_query, FALSE); + (void) stmt->execute_loop(&expanded_query, FALSE, NULL, NULL); DBUG_VOID_RETURN; - -set_params_data_err: - my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE"); - reset_stmt_params(stmt); - DBUG_VOID_RETURN; } @@ -2459,8 +2536,13 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) /* First of all clear possible warnings from the previous command */ mysql_reset_thd_for_next_command(thd); status_var_increment(thd->status_var.com_stmt_fetch); - if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch"))) + if (!(stmt= find_prepared_statement(thd, stmt_id))) + { + char llbuf[22]; + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), + llstr(stmt_id, llbuf), "mysql_stmt_fetch"); DBUG_VOID_RETURN; + } cursor= stmt->cursor; if (!cursor) @@ -2521,8 +2603,13 @@ void mysql_stmt_reset(THD *thd, char *packet) mysql_reset_thd_for_next_command(thd); status_var_increment(thd->status_var.com_stmt_reset); - if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset"))) + if (!(stmt= find_prepared_statement(thd, stmt_id))) + { + char llbuf[22]; + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), + llstr(stmt_id, llbuf), "mysql_stmt_reset"); DBUG_VOID_RETURN; + } stmt->close_cursor(); @@ -2558,15 +2645,15 @@ void mysql_stmt_close(THD *thd, char *packet) thd->main_da.disable_status(); - if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close"))) + if (!(stmt= find_prepared_statement(thd, stmt_id))) DBUG_VOID_RETURN; /* The only way currently a statement can be deallocated when it's in use is from within Dynamic SQL. */ - DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE)); - (void) stmt->deallocate(); + DBUG_ASSERT(! stmt->is_in_use()); + stmt->deallocate(); general_log_print(thd, thd->command, NullS); DBUG_VOID_RETURN; @@ -2593,14 +2680,15 @@ void mysql_sql_stmt_close(THD *thd) name->str)); if (! (stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name))) - { my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), name->length, name->str, "DEALLOCATE PREPARE"); - return; - } - - if (stmt->deallocate() == 0) + else if (stmt->is_in_use()) + my_error(ER_PS_NO_RECURSION, MYF(0)); + else + { + stmt->deallocate(); my_ok(thd); + } } /** @@ -2634,17 +2722,13 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) #ifndef EMBEDDED_LIBRARY /* Minimal size of long data packet is 6 bytes */ if (packet_length < MYSQL_LONG_DATA_HEADER) - { - my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data"); DBUG_VOID_RETURN; - } #endif stmt_id= uint4korr(packet); packet+= 4; - if (!(stmt=find_prepared_statement(thd, stmt_id, - "mysql_stmt_send_long_data"))) + if (!(stmt=find_prepared_statement(thd, stmt_id))) DBUG_VOID_RETURN; param_number= uint2korr(packet); @@ -2730,7 +2814,7 @@ Select_fetch_protocol_binary::send_data(List<Item> &fields) ****************************************************************************/ Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg) - :Statement(&main_lex, &main_mem_root, + :Statement(NULL, &main_mem_root, INITIALIZED, ++thd_arg->statement_id_counter), thd(thd_arg), result(thd_arg), @@ -2738,7 +2822,8 @@ Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg) param_array(0), param_count(0), last_errno(0), - flags((uint) IS_IN_USE) + flags((uint) IS_IN_USE), + m_sp_cache_version(0) { init_sql_alloc(&main_mem_root, thd_arg->variables.query_alloc_block_size, thd_arg->variables.query_prealloc_size); @@ -2801,7 +2886,11 @@ Prepared_statement::~Prepared_statement() like Item_param, don't free everything until free_items() */ free_items(); - delete lex->result; + if (lex) + { + delete lex->result; + delete (st_lex_local *) lex; + } free_root(&main_mem_root, MYF(0)); DBUG_VOID_RETURN; } @@ -2837,6 +2926,34 @@ bool Prepared_statement::set_name(LEX_STRING *name_arg) return name.str == 0; } + +/** + Remember the current database. + + We must reset/restore the current database during execution of + a prepared statement since it affects execution environment: + privileges, @@character_set_database, and other. + + @return Returns an error if out of memory. +*/ + +bool +Prepared_statement::set_db(const char *db_arg, uint db_length_arg) +{ + /* Remember the current database. */ + if (db_arg && db_length_arg) + { + db= this->strmake(db_arg, db_length_arg); + db_length= db_length_arg; + } + else + { + db= NULL; + db_length= 0; + } + return db_arg != NULL && db == NULL; +} + /************************************************************************** Common parts of mysql_[sql]_stmt_prepare, mysql_[sql]_stmt_execute. Essentially, these functions do all the magic of preparing/executing @@ -2878,6 +2995,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) */ status_var_increment(thd->status_var.com_stmt_prepare); + if (! (lex= new (mem_root) st_lex_local)) + DBUG_RETURN(TRUE); + + if (set_db(thd->db, thd->db_length)) + DBUG_RETURN(TRUE); + /* alloc_query() uses thd->memroot && thd->query, so we should call both of backup_statement() and backup_query_arena() here. @@ -2895,29 +3018,16 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) old_stmt_arena= thd->stmt_arena; thd->stmt_arena= this; - Lex_input_stream lip(thd, thd->query, thd->query_length); - lip.stmt_prepare_mode= TRUE; + Parser_state parser_state(thd, thd->query, thd->query_length); + parser_state.m_lip.stmt_prepare_mode= TRUE; lex_start(thd); - error= parse_sql(thd, &lip, NULL) || + error= parse_sql(thd, & parser_state, NULL) || thd->is_error() || init_param_array(this); lex->set_trg_event_type_for_tables(); - /* Remember the current database. */ - - if (thd->db && thd->db_length) - { - db= this->strmake(thd->db, thd->db_length); - db_length= thd->db_length; - } - else - { - db= NULL; - db_length= 0; - } - /* While doing context analysis of the query (in check_prepared_statement) we allocate a lot of additional memory: for open tables, JOINs, derived @@ -2941,7 +3051,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) */ if (error == 0) - error= check_prepared_statement(this, name.str != 0); + error= check_prepared_statement(this); /* Currently CREATE PROCEDURE/TRIGGER/EVENT are prohibited in prepared @@ -2966,6 +3076,20 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) init_stmt_after_parse(lex); state= Query_arena::PREPARED; flags&= ~ (uint) IS_IN_USE; + /* + This is for prepared statement validation purposes. + A statement looks up and pre-loads all its stored functions + at prepare. Later on, if a function is gone from the cache, + execute may fail. + Remember the cache version to be able to invalidate the prepared + statement at execute if it changes. + We only need to care about version of the stored functions cache: + if a prepared statement uses a stored procedure, it's indirect, + via a stored function. The only exception is SQLCOM_CALL, + but the latter one looks up the stored procedure each time + it's invoked, rather than once at prepare. + */ + m_sp_cache_version= sp_cache_version(&thd->sp_func_cache); /* Log COM_EXECUTE to the general log. Note, that in case of SQL @@ -2988,6 +3112,306 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) DBUG_RETURN(error); } + +/** + Assign parameter values either from variables, in case of SQL PS + or from the execute packet. + + @param expanded_query a container with the original SQL statement. + '?' placeholders will be replaced with + their values in case of success. + The result is used for logging and replication + @param packet pointer to execute packet. + NULL in case of SQL PS + @param packet_end end of the packet. NULL in case of SQL PS + + @todo Use a paremeter source class family instead of 'if's, and + support stored procedure variables. + + @retval TRUE an error occurred when assigning a parameter (likely + a conversion error or out of memory, or malformed packet) + @retval FALSE success +*/ + +bool +Prepared_statement::set_parameters(String *expanded_query, + uchar *packet, uchar *packet_end) +{ + bool is_sql_ps= packet == NULL; + bool res= FALSE; + + if (is_sql_ps) + { + /* SQL prepared statement */ + res= set_params_from_vars(this, thd->lex->prepared_stmt_params, + expanded_query); + } + else if (param_count) + { +#ifndef EMBEDDED_LIBRARY + uchar *null_array= packet; + res= (setup_conversion_functions(this, &packet, packet_end) || + set_params(this, null_array, packet, packet_end, expanded_query)); +#else + /* + In embedded library we re-install conversion routines each time + we set parameters, and also we don't need to parse packet. + So we do it in one function. + */ + res= set_params_data(this, expanded_query); +#endif + } + if (res) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), + is_sql_ps ? "EXECUTE" : "mysql_stmt_execute"); + reset_stmt_params(this); + } + return res; +} + + +/** + Execute a prepared statement. Re-prepare it a limited number + of times if necessary. + + Try to execute a prepared statement. If there is a metadata + validation error, prepare a new copy of the prepared statement, + swap the old and the new statements, and try again. + If there is a validation error again, repeat the above, but + perform no more than MAX_REPREPARE_ATTEMPTS. + + @note We have to try several times in a loop since we + release metadata locks on tables after prepared statement + prepare. Therefore, a DDL statement may sneak in between prepare + and execute of a new statement. If this happens repeatedly + more than MAX_REPREPARE_ATTEMPTS times, we give up. + + In future we need to be able to keep the metadata locks between + prepare and execute, but right now open_and_lock_tables(), as + well as close_thread_tables() are buried deep inside + execution code (mysql_execute_command()). + + @return TRUE if an error, FALSE if success + @retval TRUE either MAX_REPREPARE_ATTEMPTS has been reached, + or some general error + @retval FALSE successfully executed the statement, perhaps + after having reprepared it a few times. +*/ + +bool +Prepared_statement::execute_loop(String *expanded_query, + bool open_cursor, + uchar *packet, + uchar *packet_end) +{ + const int MAX_REPREPARE_ATTEMPTS= 3; + Reprepare_observer reprepare_observer; + bool error; + int reprepare_attempt= 0; + + if (set_parameters(expanded_query, packet, packet_end)) + return TRUE; + +reexecute: + reprepare_observer.reset_reprepare_observer(); + + /* + If the free_list is not empty, we'll wrongly free some externally + allocated items when cleaning up after validation of the prepared + statement. + */ + DBUG_ASSERT(thd->free_list == NULL); + + /* + Install the metadata observer. If some metadata version is + different from prepare time and an observer is installed, + the observer method will be invoked to push an error into + the error stack. + */ + if (sql_command_flags[lex->sql_command] & + CF_REEXECUTION_FRAGILE) + { + DBUG_ASSERT(thd->m_reprepare_observer == NULL); + thd->m_reprepare_observer = &reprepare_observer; + } + + if (!(specialflag & SPECIAL_NO_PRIOR)) + my_pthread_setprio(pthread_self(),QUERY_PRIOR); + + error= execute(expanded_query, open_cursor) || thd->is_error(); + + if (!(specialflag & SPECIAL_NO_PRIOR)) + my_pthread_setprio(pthread_self(), WAIT_PRIOR); + + thd->m_reprepare_observer= NULL; + + if (error && !thd->is_fatal_error && !thd->killed && + reprepare_observer.is_invalidated() && + reprepare_attempt++ < MAX_REPREPARE_ATTEMPTS) + { + DBUG_ASSERT(thd->main_da.sql_errno() == ER_NEED_REPREPARE); + thd->clear_error(); + + error= reprepare(); + + if (! error) /* Success */ + goto reexecute; + } + reset_stmt_params(this); + + return error; +} + + +/** + Reprepare this prepared statement. + + Currently this is implemented by creating a new prepared + statement, preparing it with the original query and then + swapping the new statement and the original one. + + @retval TRUE an error occurred. Possible errors include + incompatibility of new and old result set + metadata + @retval FALSE success, the statement has been reprepared +*/ + +bool +Prepared_statement::reprepare() +{ + char saved_cur_db_name_buf[NAME_LEN+1]; + LEX_STRING saved_cur_db_name= + { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) }; + LEX_STRING stmt_db_name= { db, db_length }; + bool cur_db_changed; + bool error; + + Prepared_statement copy(thd, &thd->protocol_text); + + status_var_increment(thd->status_var.com_stmt_reprepare); + + if (mysql_opt_change_db(thd, &stmt_db_name, &saved_cur_db_name, TRUE, + &cur_db_changed)) + return TRUE; + + error= (name.str && copy.set_name(&name) || + copy.prepare(query, query_length) || + validate_metadata(©)); + + if (cur_db_changed) + mysql_change_db(thd, &saved_cur_db_name, TRUE); + + if (! error) + { + swap_prepared_statement(©); + swap_parameter_array(param_array, copy.param_array, param_count); +#ifndef DBUG_OFF + is_reprepared= TRUE; +#endif + /* + Clear possible warnings during reprepare, it has to be completely + transparent to the user. We use mysql_reset_errors() since + there were no separate query id issued for re-prepare. + Sic: we can't simply silence warnings during reprepare, because if + it's failed, we need to return all the warnings to the user. + */ + mysql_reset_errors(thd, TRUE); + } + return error; +} + + +/** + Validate statement result set metadata (if the statement returns + a result set). + + Currently we only check that the number of columns of the result + set did not change. + This is a helper method used during re-prepare. + + @param[in] copy the re-prepared prepared statement to verify + the metadata of + + @retval TRUE error, ER_PS_REBIND is reported + @retval FALSE statement return no or compatible metadata +*/ + + +bool Prepared_statement::validate_metadata(Prepared_statement *copy) +{ + /** + If this is an SQL prepared statement or EXPLAIN, + return FALSE -- the metadata of the original SELECT, + if any, has not been sent to the client. + */ + if (is_protocol_text() || lex->describe) + return FALSE; + + if (lex->select_lex.item_list.elements != + copy->lex->select_lex.item_list.elements) + { + /** Column counts mismatch, update the client */ + thd->server_status|= SERVER_STATUS_METADATA_CHANGED; + } + + return FALSE; +} + + +/** + Replace the original prepared statement with a prepared copy. + + This is a private helper that is used as part of statement + reprepare + + @return This function does not return any errors. +*/ + +void +Prepared_statement::swap_prepared_statement(Prepared_statement *copy) +{ + Statement tmp_stmt; + + /* Swap memory roots. */ + swap_variables(MEM_ROOT, main_mem_root, copy->main_mem_root); + + /* Swap the arenas */ + tmp_stmt.set_query_arena(this); + set_query_arena(copy); + copy->set_query_arena(&tmp_stmt); + + /* Swap the statement parent classes */ + tmp_stmt.set_statement(this); + set_statement(copy); + copy->set_statement(&tmp_stmt); + + /* Swap ids back, we need the original id */ + swap_variables(ulong, id, copy->id); + /* Swap mem_roots back, they must continue pointing at the main_mem_roots */ + swap_variables(MEM_ROOT *, mem_root, copy->mem_root); + /* + Swap the old and the new parameters array. The old array + is allocated in the old arena. + */ + swap_variables(Item_param **, param_array, copy->param_array); + /* Swap flags: this is perhaps unnecessary */ + swap_variables(uint, flags, copy->flags); + /* Swap names, the old name is allocated in the wrong memory root */ + swap_variables(LEX_STRING, name, copy->name); + /* Ditto */ + swap_variables(char *, db, copy->db); + swap_variables(ulong, m_sp_cache_version, copy->m_sp_cache_version); + + DBUG_ASSERT(db_length == copy->db_length); + DBUG_ASSERT(param_count == copy->param_count); + DBUG_ASSERT(thd == copy->thd); + last_error[0]= '\0'; + last_errno= 0; + /* Do not swap protocols, the copy always has protocol_text */ +} + + /** Execute a prepared statement. @@ -3038,6 +3462,19 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) } /* + Reprepare the statement if we're using stored functions + and the version of the stored routines cache has changed. + */ + if (lex->uses_stored_routines() && + m_sp_cache_version != sp_cache_version(&thd->sp_func_cache) && + thd->m_reprepare_observer && + thd->m_reprepare_observer->report_error(thd)) + { + return TRUE; + } + + + /* For SHOW VARIABLES lex->result is NULL, as it's a non-SELECT command. For such queries we don't return an error and don't open a cursor -- the client library will recognize this case and @@ -3150,10 +3587,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) DBUG_ASSERT(! (error && cursor)); if (! cursor) - { cleanup_stmt(); - reset_stmt_params(this); - } thd->set_statement(&stmt_backup); thd->stmt_arena= old_stmt_arena; @@ -3187,16 +3621,10 @@ error: /** Common part of DEALLOCATE PREPARE and mysql_stmt_close. */ -bool Prepared_statement::deallocate() +void Prepared_statement::deallocate() { /* We account deallocate in the same manner as mysql_stmt_close */ status_var_increment(thd->status_var.com_stmt_close); - if (flags & (uint) IS_IN_USE) - { - my_error(ER_PS_NO_RECURSION, MYF(0)); - return TRUE; - } /* Statement map calls delete stmt on erase */ thd->stmt_map.erase(this); - return FALSE; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3d18ba681d1..af33fdba71a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -856,6 +856,7 @@ JOIN::optimize() "Impossible HAVING" : "Impossible WHERE")); zero_result_cause= having_value == Item::COND_FALSE ? "Impossible HAVING" : "Impossible WHERE"; + tables= 0; error= 0; DBUG_RETURN(0); } @@ -897,6 +898,7 @@ JOIN::optimize() { DBUG_PRINT("info",("No matching min/max row")); zero_result_cause= "No matching min/max row"; + tables= 0; error=0; DBUG_RETURN(0); } @@ -910,6 +912,7 @@ JOIN::optimize() { DBUG_PRINT("info",("No matching min/max row")); zero_result_cause= "No matching min/max row"; + tables= 0; error=0; DBUG_RETURN(0); } @@ -1804,7 +1807,8 @@ JOIN::exec() if (!items1) { items1= items0 + all_fields.elements; - if (sort_and_group || curr_tmp_table->group) + if (sort_and_group || curr_tmp_table->group || + tmp_table_param.precomputed_group_by) { if (change_to_use_tmp_fields(thd, items1, tmp_fields_list1, tmp_all_fields1, @@ -2210,11 +2214,12 @@ JOIN::exec() /* With EXPLAIN EXTENDED we have to restore original ref_array for a derived table which is always materialized. - Otherwise we would not be able to print the query correctly. + We also need to do this when we have temp table(s). + Otherwise we would not be able to print the query correctly. */ - if (items0 && - (thd->lex->describe & DESCRIBE_EXTENDED) && - select_lex->linkage == DERIVED_TABLE_TYPE) + if (items0 && (thd->lex->describe & DESCRIBE_EXTENDED) && + (select_lex->linkage == DERIVED_TABLE_TYPE || + exec_tmp_table1 || exec_tmp_table2)) set_items_ref_array(items0); DBUG_VOID_RETURN; @@ -6528,13 +6533,16 @@ make_join_readinfo(JOIN *join, ulonglong options) !(tab->select && tab->select->quick)) { // Only read index tree /* - See bug #26447: "Using the clustered index for a table scan - is always faster than using a secondary index". - */ + It has turned out that the below change, while speeding things + up for disk-bound loads, slows them down for cases when the data + is in disk cache (see BUG#35850): + // See bug #26447: "Using the clustered index for a table scan + // is always faster than using a secondary index". if (table->s->primary_key != MAX_KEY && table->file->primary_key_is_clustered()) tab->index= table->s->primary_key; else + */ tab->index=find_shortest_key(table, & table->covering_keys); tab->read_first_record= join_read_first; tab->type=JT_NEXT; // Read with index_first / index_next @@ -6770,6 +6778,12 @@ void JOIN::cleanup(bool full) if (tmp_join) tmp_table_param.copy_field= 0; group_fields.delete_elements(); + /* + Ensure that the above delete_elements() would not be called + twice for the same list. + */ + if (tmp_join && tmp_join != this) + tmp_join->group_fields= group_fields; /* We can't call delete_elements() on copy_funcs as this will cause problems in free_elements() as some of the elements are then deleted. @@ -9638,6 +9652,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ENGINE_COLUMNDEF *recinfo; uint total_uneven_bit_length= 0; bool force_copy_fields= param->force_copy_fields; + /* Treat sum functions as normal ones when loose index scan is used. */ + save_sum_fields|= param->precomputed_group_by; DBUG_ENTER("create_tmp_table"); DBUG_PRINT("enter", ("distinct: %d save_sum_fields: %d rows_limit: %lu group: %d", @@ -11895,7 +11911,7 @@ join_init_read_record(JOIN_TAB *tab) if (tab->select && tab->select->quick && tab->select->quick->reset()) return 1; init_read_record(&tab->read_record, tab->join->thd, tab->table, - tab->select,1,1); + tab->select,1,1, FALSE); return (*tab->read_record.read_record)(&tab->read_record); } @@ -12690,6 +12706,9 @@ part_of_refkey(TABLE *table,Field *field) @note used_key_parts is set to correct key parts used if return value != 0 (On other cases, used_key_part may be changed) + Note that the value may actually be greater than the number of index + key parts. This can happen for storage engines that have the primary + key parts as a suffix for every secondary key. @retval 1 key is ok. @@ -12762,11 +12781,27 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, reverse=flag; // Remember if reverse key_part++; } - *used_key_parts= on_primary_key ? table->key_info[idx].key_parts : - (uint) (key_part - table->key_info[idx].key_part); - if (reverse == -1 && !(table->file->index_flags(idx, *used_key_parts-1, 1) & - HA_READ_PREV)) - reverse= 0; // Index can't be used + if (on_primary_key) + { + uint used_key_parts_secondary= table->key_info[idx].key_parts; + uint used_key_parts_pk= + (uint) (key_part - table->key_info[table->s->primary_key].key_part); + *used_key_parts= used_key_parts_pk + used_key_parts_secondary; + + if (reverse == -1 && + (!(table->file->index_flags(idx, used_key_parts_secondary - 1, 1) & + HA_READ_PREV) || + !(table->file->index_flags(table->s->primary_key, + used_key_parts_pk - 1, 1) & HA_READ_PREV))) + reverse= 0; // Index can't be used + } + else + { + *used_key_parts= (uint) (key_part - table->key_info[idx].key_part); + if (reverse == -1 && + !(table->file->index_flags(idx, *used_key_parts-1, 1) & HA_READ_PREV)) + reverse= 0; // Index can't be used + } DBUG_RETURN(reverse); } @@ -13155,6 +13190,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, uint tablenr= tab - join->join_tab; ha_rows table_records= table->file->stats.records; bool group= join->group && order == join->group_list; + ha_rows ref_key_quick_rows= HA_POS_ERROR; LINT_INIT(best_key_parts); LINT_INIT(best_key_direction); LINT_INIT(best_records); @@ -13188,6 +13224,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, else keys= usable_keys; + if (ref_key >= 0 && table->covering_keys.is_set(ref_key)) + ref_key_quick_rows= table->quick_rows[ref_key]; + read_time= join->best_positions[tablenr].read_time; for (uint i= tablenr+1; i < join->tables; i++) fanout*= join->best_positions[i].records_read; // fanout is always >= 1 @@ -13282,7 +13321,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, index_scan_time < read_time) { ha_rows quick_records= table_records; - if (is_best_covering && !is_covering) + if (is_best_covering && !is_covering || + is_covering && ref_key_quick_rows < select_limit) continue; if (table->quick_keys.is_set(nr)) quick_records= table->quick_rows[nr]; @@ -13334,6 +13374,16 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, table->key_read=1; table->file->extra(HA_EXTRA_KEYREAD); } + else if (table->key_read) + { + /* + Clear the covering key read flags that might have been + previously set for some key other than the current best_key. + */ + table->key_read= 0; + table->file->extra(HA_EXTRA_NO_KEYREAD); + } + table->file->ha_index_or_rnd_end(); if (join->select_options & SELECT_DESCRIBE) { @@ -13356,6 +13406,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, tab->ref.key= -1; tab->ref.key_parts=0; // Don't use ref key. tab->read_first_record= join_init_read_record; + if (tab->is_using_loose_index_scan()) + join->tmp_table_param.precomputed_group_by= TRUE; /* TODO: update the number of records in join->best_positions[tablenr] */ diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 4390919f8c7..13bed8001a3 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -182,7 +182,8 @@ static bool servers_load(THD *thd, TABLE_LIST *tables) free_root(&mem, MYF(0)); init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0); - init_read_record(&read_record_info,thd,table=tables[0].table,NULL,1,0); + init_read_record(&read_record_info,thd,table=tables[0].table,NULL,1,0, + FALSE); while (!(read_record_info.read_record(&read_record_info))) { /* return_val is already TRUE, so no need to set */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bde1274631a..b5ab6484d12 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -25,8 +25,10 @@ #include "sql_trigger.h" #include "authors.h" #include "contributors.h" +#ifdef HAVE_EVENT_SCHEDULER #include "events.h" #include "event_data_objects.h" +#endif #include <my_dir.h> #define STR_OR_NIL(S) ((S) ? (S) : "<nil>") @@ -287,7 +289,9 @@ static struct show_privileges_st sys_privileges[]= {"Create user", "Server Admin", "To create new users"}, {"Delete", "Tables", "To delete existing rows"}, {"Drop", "Databases,Tables", "To drop databases, tables, and views"}, +#ifdef HAVE_EVENT_SCHEDULER {"Event","Server Admin","To create, alter, drop and execute events"}, +#endif {"Execute", "Functions,Procedures", "To execute stored routines"}, {"File", "File access on server", "To read and write files on the server"}, {"Grant option", "Databases,Tables,Functions,Procedures", "To give to other users those privileges you possess"}, @@ -3541,8 +3545,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, if(file) { - file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO | - HA_STATUS_NO_LOCK); + file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO); enum row_type row_type = file->get_row_type(); switch (row_type) { case ROW_TYPE_NOT_USED: @@ -3890,7 +3893,6 @@ static my_bool iter_schema_engines(THD *thd, plugin_ref plugin, DBUG_RETURN(0); } - int fill_schema_engines(THD *thd, TABLE_LIST *tables, COND *cond) { return plugin_foreach(thd, iter_schema_engines, @@ -4955,7 +4957,7 @@ static interval_type get_real_interval_type(interval_type i_type) #endif - +#ifdef HAVE_EVENT_SCHEDULER /* Loads an event from mysql.event and copies it's data to a row of I_S.EVENTS @@ -5075,14 +5077,14 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) switch (et.status) { - case Event_timed::ENABLED: + case Event_parse_data::ENABLED: sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("ENABLED"), scs); break; - case Event_timed::SLAVESIDE_DISABLED: + case Event_parse_data::SLAVESIDE_DISABLED: sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("SLAVESIDE_DISABLED"), scs); break; - case Event_timed::DISABLED: + case Event_parse_data::DISABLED: sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("DISABLED"), scs); break; default: @@ -5091,7 +5093,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) sch_table->field[ISE_ORIGINATOR]->store(et.originator, TRUE); /* on_completion */ - if (et.on_completion == Event_timed::ON_COMPLETION_DROP) + if (et.on_completion == Event_parse_data::ON_COMPLETION_DROP) sch_table->field[ISE_ON_COMPLETION]-> store(STRING_WITH_LEN("NOT PRESERVE"), scs); else @@ -5141,7 +5143,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) DBUG_RETURN(0); } - +#endif int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond) { @@ -5862,6 +5864,9 @@ bool get_schema_tables_result(JOIN *join, bool is_subselect= (&lex->unit != lex->current_select->master_unit() && lex->current_select->master_unit()->item); + /* A value of 0 indicates a dummy implementation */ + if (table_list->schema_table->fill_table == 0) + continue; /* skip I_S optimizations specific to get_all_tables */ if (thd->lex->describe && @@ -6537,8 +6542,13 @@ ST_SCHEMA_TABLE schema_tables[]= fill_schema_column_privileges, 0, 0, -1, -1, 0, 0}, {"ENGINES", engines_fields_info, create_schema_table, fill_schema_engines, make_old_format, 0, -1, -1, 0, 0}, +#ifdef HAVE_EVENT_SCHEDULER {"EVENTS", events_fields_info, create_schema_table, Events::fill_schema_events, make_old_format, 0, -1, -1, 0, 0}, +#else + {"EVENTS", events_fields_info, create_schema_table, + 0, make_old_format, 0, -1, -1, 0, 0}, +#endif {"FILES", files_fields_info, create_schema_table, fill_schema_files, 0, 0, -1, -1, 0, 0}, {"GLOBAL_STATUS", variables_fields_info, create_schema_table, @@ -6629,17 +6639,15 @@ int initialize_schema_table(st_plugin_int *plugin) { sql_print_error("Plugin '%s' init function returned error.", plugin->name.str); - goto err; + plugin->data= NULL; + my_free(schema_table, MYF(0)); + DBUG_RETURN(1); } /* Make sure the plugin name is not set inside the init() function. */ schema_table->table_name= plugin->name.str; } - DBUG_RETURN(0); -err: - my_free(schema_table, MYF(0)); - DBUG_RETURN(1); } int finalize_schema_table(st_plugin_int *plugin) diff --git a/sql/sql_string.h b/sql/sql_string.h index b4d76a1779a..be11fea70dc 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -79,7 +79,7 @@ public: Alloced_length=str.Alloced_length; alloced=0; str_charset=str.str_charset; } - static void *operator new(size_t size, MEM_ROOT *mem_root) + static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return (void*) alloc_root(mem_root, (uint) size); } static void operator delete(void *ptr_arg,size_t size) { TRASH(ptr_arg, size); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b0275e3c860..e3447664922 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4030,6 +4030,13 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, - Run a normal repair using the new index file and the old data file */ + if (table->s->frm_version != FRM_VER_TRUE_VARCHAR) + { + error= send_check_errmsg(thd, table_list, "repair", + "Failed repairing incompatible .frm file"); + goto end; + } + /* Check if this is a table type that stores index and data separately, like ISAM or MyISAM. We assume fixed order of engine file name @@ -4196,6 +4203,46 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, table->next_global= save_next_global; table->next_local= save_next_local; thd->open_options&= ~extra_open_options; +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (table->table && table->table->part_info) + { + /* + Set up which partitions that should be processed + if ALTER TABLE t ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION .. + */ + Alter_info *alter_info= &lex->alter_info; + + if (alter_info->flags & ALTER_ANALYZE_PARTITION || + alter_info->flags & ALTER_CHECK_PARTITION || + alter_info->flags & ALTER_OPTIMIZE_PARTITION || + alter_info->flags & ALTER_REPAIR_PARTITION) + { + uint no_parts_found; + uint no_parts_opt= alter_info->partition_names.elements; + no_parts_found= set_part_state(alter_info, table->table->part_info, + PART_CHANGED); + if (no_parts_found != no_parts_opt && + (!(alter_info->flags & ALTER_ALL_PARTITION))) + { + char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE]; + uint length; + DBUG_PRINT("admin", ("sending non existent partition error")); + protocol->prepare_for_resend(); + protocol->store(table_name, system_charset_info); + protocol->store(operator_name, system_charset_info); + protocol->store(STRING_WITH_LEN("error"), system_charset_info); + length= my_snprintf(buff, sizeof(buff), + ER(ER_DROP_PARTITION_NON_EXISTENT), + table_name); + protocol->store(buff, length, system_charset_info); + if(protocol->write()) + goto err; + my_eof(thd); + goto err; + } + } + } +#endif } DBUG_PRINT("admin", ("table: 0x%lx", (long) table->table)); @@ -4430,9 +4477,17 @@ send_result_message: This is currently used only by InnoDB. ha_innobase::optimize() answers "try with alter", so here we close the table, do an ALTER TABLE, reopen the table and do ha_innobase::analyze() on it. + We have to end the row, so analyze could return more rows. */ + protocol->store(STRING_WITH_LEN("note"), system_charset_info); + protocol->store(STRING_WITH_LEN( + "Table does not support optimize, doing recreate + analyze instead"), + system_charset_info); + if (protocol->write()) + goto err; ha_autocommit_or_rollback(thd, 0); close_thread_tables(thd); + DBUG_PRINT("info", ("HA_ADMIN_TRY_ALTER, trying analyze...")); TABLE_LIST *save_next_local= table->next_local, *save_next_global= table->next_global; table->next_local= table->next_global= 0; @@ -4455,6 +4510,10 @@ send_result_message: ((result_code= table->table->file->ha_analyze(thd, check_opt)) > 0)) result_code= 0; // analyze went ok } + /* Start a new row for the final status row */ + protocol->prepare_for_resend(); + protocol->store(table_name, system_charset_info); + protocol->store(operator_name, system_charset_info); if (result_code) // either mysql_recreate_table or analyze failed { DBUG_ASSERT(thd->is_error()); @@ -4470,7 +4529,8 @@ send_result_message: /* Hijack the row already in-progress. */ protocol->store(STRING_WITH_LEN("error"), system_charset_info); protocol->store(err_msg, system_charset_info); - (void)protocol->write(); + if (protocol->write()) + goto err; /* Start off another row for HA_ADMIN_FAILED */ protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); @@ -4785,9 +4845,6 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, DBUG_ENTER("mysql_create_like_table"); - /* CREATE TABLE ... LIKE is not allowed for views. */ - src_table->required_type= FRMTYPE_TABLE; - /* By opening source table we guarantee that it exists and no concurrent DDL operation will mess with it. Later we also take an exclusive @@ -5150,51 +5207,51 @@ compare_tables(TABLE *table, Field **f_ptr, *field; uint changes= 0, tmp; uint key_count; - List_iterator_fast<Create_field> new_field_it(alter_info->create_list); - Create_field *new_field; + List_iterator_fast<Create_field> new_field_it, tmp_new_field_it; + Create_field *new_field, *tmp_new_field; KEY_PART_INFO *key_part; KEY_PART_INFO *end; + THD *thd= table->in_use; /* Remember if the new definition has new VARCHAR column; create_info->varchar will be reset in mysql_prepare_create_table. */ bool varchar= create_info->varchar; + /* + Create a copy of alter_info. + To compare the new and old table definitions, we need to "prepare" + the new definition - transform it from parser output to a format + that describes the final table layout (all column defaults are + initialized, duplicate columns are removed). This is done by + mysql_prepare_create_table. Unfortunately, + mysql_prepare_create_table performs its transformations + "in-place", that is, modifies the argument. Since we would + like to keep compare_tables() idempotent (not altering any + of the arguments) we create a copy of alter_info here and + pass it to mysql_prepare_create_table, then use the result + to evaluate possibility of fast ALTER TABLE, and then + destroy the copy. + */ + Alter_info tmp_alter_info(*alter_info, thd->mem_root); + uint db_options= 0; /* not used */ + DBUG_ENTER("compare_tables"); - { - THD *thd= table->in_use; - /* - Create a copy of alter_info. - To compare the new and old table definitions, we need to "prepare" - the new definition - transform it from parser output to a format - that describes the final table layout (all column defaults are - initialized, duplicate columns are removed). This is done by - mysql_prepare_create_table. Unfortunately, - mysql_prepare_create_table performs its transformations - "in-place", that is, modifies the argument. Since we would - like to keep compare_tables() idempotent (not altering any - of the arguments) we create a copy of alter_info here and - pass it to mysql_prepare_create_table, then use the result - to evaluate possibility of fast ALTER TABLE, and then - destroy the copy. - */ - Alter_info tmp_alter_info(*alter_info, thd->mem_root); - uint db_options= 0; /* not used */ - /* Create the prepared information. */ - if (mysql_prepare_create_table(thd, create_info, - &tmp_alter_info, - (table->s->tmp_table != NO_TMP_TABLE), - &db_options, - table->file, key_info_buffer, - &key_count, 0)) - DBUG_RETURN(1); - /* Allocate result buffers. */ - if (! (*index_drop_buffer= - (uint*) thd->alloc(sizeof(uint) * table->s->keys)) || - ! (*index_add_buffer= - (uint*) thd->alloc(sizeof(uint) * tmp_alter_info.key_list.elements))) - DBUG_RETURN(1); - } + /* Create the prepared information. */ + if (mysql_prepare_create_table(thd, create_info, + &tmp_alter_info, + (table->s->tmp_table != NO_TMP_TABLE), + &db_options, + table->file, key_info_buffer, + &key_count, 0)) + DBUG_RETURN(1); + /* Allocate result buffers. */ + if (! (*index_drop_buffer= + (uint*) thd->alloc(sizeof(uint) * table->s->keys)) || + ! (*index_add_buffer= + (uint*) thd->alloc(sizeof(uint) * tmp_alter_info.key_list.elements))) + DBUG_RETURN(1); + /* Some very basic checks. If number of fields changes, or the handler, we need to run full ALTER TABLE. In the future @@ -5240,18 +5297,27 @@ compare_tables(TABLE *table, } /* - Go through fields and check if the original ones are compatible + Use transformed info to evaluate possibility of fast ALTER TABLE + but use the preserved field to persist modifications. + */ + new_field_it.init(alter_info->create_list); + tmp_new_field_it.init(tmp_alter_info.create_list); + + /* Go through fields and check if the original ones are compatible with new table. */ - for (f_ptr= table->field, new_field= new_field_it++; - (field= *f_ptr); f_ptr++, new_field= new_field_it++) + for (f_ptr= table->field, new_field= new_field_it++, + tmp_new_field= tmp_new_field_it++; + (field= *f_ptr); + f_ptr++, new_field= new_field_it++, + tmp_new_field= tmp_new_field_it++) { /* Make sure we have at least the default charset in use. */ if (!new_field->charset) new_field->charset= create_info->default_table_charset; /* Check that NULL behavior is same for old and new fields */ - if ((new_field->flags & NOT_NULL_FLAG) != + if ((tmp_new_field->flags & NOT_NULL_FLAG) != (uint) (field->flags & NOT_NULL_FLAG)) { *need_copy_table= ALTER_TABLE_DATA_CHANGED; @@ -5259,20 +5325,21 @@ compare_tables(TABLE *table, } /* Don't pack rows in old tables if the user has requested this. */ - if ((new_field->flags & BLOB_FLAG) || - new_field->sql_type == MYSQL_TYPE_VARCHAR && - create_info->row_type != ROW_TYPE_FIXED) - create_info->table_options|= HA_OPTION_PACK_RECORD; + if (create_info->row_type == ROW_TYPE_DYNAMIC || + (tmp_new_field->flags & BLOB_FLAG) || + tmp_new_field->sql_type == MYSQL_TYPE_VARCHAR && + create_info->row_type != ROW_TYPE_FIXED) + create_info->table_options|= HA_OPTION_PACK_RECORD; /* Check if field was renamed */ field->flags&= ~FIELD_IS_RENAMED; if (my_strcasecmp(system_charset_info, field->field_name, - new_field->field_name)) + tmp_new_field->field_name)) field->flags|= FIELD_IS_RENAMED; /* Evaluate changes bitmap and send to check_if_incompatible_data() */ - if (!(tmp= field->is_equal(new_field))) + if (!(tmp= field->is_equal(tmp_new_field))) { *need_copy_table= ALTER_TABLE_DATA_CHANGED; DBUG_RETURN(0); @@ -7108,7 +7175,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, /* Tell handler that we have values for all columns in the to table */ to->use_all_columns(); - init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1,1); + init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE); errpos= 4; if (ignore) to->file->extra(HA_EXTRA_IGNORE_DUP_KEY); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 1a522b852e9..01363714484 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -27,7 +27,9 @@ #include <sys/malloc.h> #endif +#ifdef HAVE_EVENT_SCHEDULER #include "events.h" +#endif static const char *lock_descriptions[] = { @@ -539,6 +541,8 @@ Estimated memory (with thread stack): %ld\n", (long) (thread_count * my_thread_stack_size + info.hblkhd + info.arena)); #endif +#ifdef HAVE_EVENT_SCHEDULER Events::dump_internal_status(); +#endif puts(""); } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index d426904e4b2..32389bde44c 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1287,7 +1287,9 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, thd->variables.sql_mode= (ulong)*trg_sql_mode; - Lex_input_stream lip(thd, trg_create_str->str, trg_create_str->length); + Parser_state parser_state(thd, + trg_create_str->str, + trg_create_str->length); Trigger_creation_ctx *creation_ctx= Trigger_creation_ctx::create(thd, @@ -1300,7 +1302,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, lex_start(thd); thd->spcont= NULL; - if (parse_sql(thd, &lip, creation_ctx)) + if (parse_sql(thd, & parser_state, creation_ctx)) { /* Currently sphead is always deleted in case of a parse error */ DBUG_ASSERT(lex.sphead == 0); diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index ae3f43eba5b..ebd183c6803 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -152,7 +152,7 @@ void udf_init() } table= tables.table; - init_read_record(&read_record_info, new_thd, table, NULL,1,0); + init_read_record(&read_record_info, new_thd, table, NULL,1,0,FALSE); table->use_all_columns(); while (!(error= read_record_info.read_record(&read_record_info))) { diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 0c6e9a89a17..dbbc0e58d8a 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -457,7 +457,7 @@ int mysql_update(THD *thd, */ if (used_index == MAX_KEY || (select && select->quick)) - init_read_record(&info,thd,table,select,0,1); + init_read_record(&info, thd, table, select, 0, 1, FALSE); else init_read_record_idx(&info, thd, table, 1, used_index); @@ -523,7 +523,7 @@ int mysql_update(THD *thd, if (select && select->quick && select->quick->reset()) goto err; table->file->try_semi_consistent_read(1); - init_read_record(&info,thd,table,select,0,1); + init_read_record(&info, thd, table, select, 0, 1, FALSE); updated= found= 0; /* Generate an error when trying to set a NOT NULL field to NULL. */ @@ -853,8 +853,9 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, Item **conds, uint order_num, ORDER *order) { Item *fake_conds= 0; +#ifndef NO_EMBEDDED_ACCESS_CHECKS TABLE *table= table_list->table; - TABLE_LIST tables; +#endif List<Item> all_fields; SELECT_LEX *select_lex= &thd->lex->select_lex; DBUG_ENTER("mysql_prepare_update"); @@ -878,9 +879,6 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, table_list->register_want_access(SELECT_ACL); #endif - bzero((char*) &tables,sizeof(tables)); // For ORDER BY - tables.table= table; - tables.alias= table_list->alias; thd->lex->allow_sum_func= 0; if (setup_tables_and_check_access(thd, &select_lex->context, @@ -1002,7 +1000,7 @@ reopen_tables: DBUG_RETURN(TRUE); } - tables_for_update= get_table_map(fields); + thd->table_map_for_update= tables_for_update= get_table_map(fields); /* Setup timestamp handling and locking mode @@ -1669,6 +1667,12 @@ bool multi_update::send_data(List<Item> ¬_used_values) tbl->file->position(tbl->record[0]); memcpy((char*) tmp_table->field[field_num]->ptr, (char*) tbl->file->ref, tbl->file->ref_length); + /* + For outer joins a rowid field may have no NOT_NULL_FLAG, + so we have to reset NULL bit for this field. + (set_notnull() resets NULL bit only if available). + */ + tmp_table->field[field_num]->set_notnull(); field_num++; } while ((tbl= tbl_it++)); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 1761a7b1957..37fee49d37a 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1146,9 +1146,9 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, char old_db_buf[NAME_LEN+1]; LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; bool dbchanged; - Lex_input_stream lip(thd, - table->select_stmt.str, - table->select_stmt.length); + Parser_state parser_state(thd, + table->select_stmt.str, + table->select_stmt.length); /* Use view db name as thread default database, in order to ensure @@ -1192,7 +1192,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, /* Parse the query. */ - parse_status= parse_sql(thd, &lip, table->view_creation_ctx); + parse_status= parse_sql(thd, & parser_state, table->view_creation_ctx); /* Restore environment. */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c23049017e2..113248e980a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -28,6 +28,7 @@ #define YYPARSE_PARAM yythd #define YYLEX_PARAM yythd #define YYTHD ((THD *)yythd) +#define YYLIP (& YYTHD->m_parser_state->m_lip) #define MYSQL_YACC #define YYINITDEPTH 100 @@ -42,7 +43,7 @@ #include "sp_pcontext.h" #include "sp_rcontext.h" #include "sp.h" -#include "event_data_objects.h" +#include "event_parse_data.h" #include <myisam.h> #include <myisammrg.h> @@ -121,7 +122,7 @@ const LEX_STRING null_lex_str= {0,0}; void my_parse_error(const char *s) { THD *thd= current_thd; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= & thd->m_parser_state->m_lip; const char *yytext= lip->get_tok_start(); /* Push an error into the error stack */ @@ -1282,7 +1283,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); single_multi table_wild_list table_wild_one opt_wild union_clause union_list precision subselect_start opt_and charset - subselect_end select_var_list select_var_list_init help opt_len + subselect_end select_var_list select_var_list_init help + field_length opt_field_length opt_extended_describe prepare prepare_src execute deallocate statement sp_suid @@ -1354,12 +1356,44 @@ query: my_message(ER_EMPTY_QUERY, ER(ER_EMPTY_QUERY), MYF(0)); MYSQL_YYABORT; } + thd->lex->sql_command= SQLCOM_EMPTY_QUERY; + YYLIP->found_semicolon= NULL; + } + | verb_clause + { + Lex_input_stream *lip = YYLIP; + + if ((YYTHD->client_capabilities & CLIENT_MULTI_QUERIES) && + ! lip->stmt_prepare_mode && + ! lip->eof()) + { + /* + We found a well formed query, and multi queries are allowed: + - force the parser to stop after the ';' + - mark the start of the next query for the next invocation + of the parser. + */ + lip->next_state= MY_LEX_END; + lip->found_semicolon= lip->get_ptr(); + } else { - thd->lex->sql_command= SQLCOM_EMPTY_QUERY; + /* Single query, terminated. */ + lip->found_semicolon= NULL; } } - | verb_clause END_OF_INPUT {} + ';' + opt_end_of_input + | verb_clause END_OF_INPUT + { + /* Single query, not terminated. */ + YYLIP->found_semicolon= NULL; + } + ; + +opt_end_of_input: + /* empty */ + | END_OF_INPUT ; verb_clause: @@ -1681,6 +1715,8 @@ create: } key= new Key($2, $4.str, &lex->key_create_info, 0, lex->col_list); + if (key == NULL) + MYSQL_YYABORT; lex->alter_info.key_list.push_back(key); lex->col_list.empty(); } @@ -1773,28 +1809,15 @@ server_option: event_tail: EVENT_SYM opt_if_not_exists sp_name - /* - BE CAREFUL when you add a new rule to update the block where - YYTHD->client_capabilities is set back to original value - */ { THD *thd= YYTHD; LEX *lex=Lex; lex->create_info.options= $2; - if (!(lex->event_parse_data= Event_parse_data::new_instance(thd))) MYSQL_YYABORT; lex->event_parse_data->identifier= $3; - /* - We have to turn of CLIENT_MULTI_QUERIES while parsing a - stored procedure, otherwise yylex will chop it into pieces - at each ';'. - */ - $<ulong_num>$= thd->client_capabilities & CLIENT_MULTI_QUERIES; - thd->client_capabilities &= (~CLIENT_MULTI_QUERIES); - lex->sql_command= SQLCOM_CREATE_EVENT; /* We need that for disallowing subqueries */ } @@ -1805,15 +1828,6 @@ event_tail: DO_SYM ev_sql_stmt { /* - Restore flag if it was cleared above - $1 - EVENT_SYM - $2 - opt_if_not_exists - $3 - sp_name - $4 - the block above - */ - YYTHD->client_capabilities |= $<ulong_num>4; - - /* sql_command is set here because some rules in ev_sql_stmt can overwrite it */ @@ -1839,17 +1853,17 @@ opt_ev_status: /* empty */ { $$= 0; } | ENABLE_SYM { - Lex->event_parse_data->status= Event_basic::ENABLED; + Lex->event_parse_data->status= Event_parse_data::ENABLED; $$= 1; } | DISABLE_SYM ON SLAVE { - Lex->event_parse_data->status= Event_basic::SLAVESIDE_DISABLED; + Lex->event_parse_data->status= Event_parse_data::SLAVESIDE_DISABLED; $$= 1; } | DISABLE_SYM { - Lex->event_parse_data->status= Event_basic::DISABLED; + Lex->event_parse_data->status= Event_parse_data::DISABLED; $$= 1; } ; @@ -1857,7 +1871,10 @@ opt_ev_status: ev_starts: /* empty */ { - Lex->event_parse_data->item_starts= new Item_func_now_local(); + Item *item= new (YYTHD->mem_root) Item_func_now_local(); + if (item == NULL) + MYSQL_YYABORT; + Lex->event_parse_data->item_starts= item; } | STARTS_SYM expr { @@ -1882,13 +1899,13 @@ ev_on_completion: ON COMPLETION_SYM PRESERVE_SYM { Lex->event_parse_data->on_completion= - Event_basic::ON_COMPLETION_PRESERVE; + Event_parse_data::ON_COMPLETION_PRESERVE; $$= 1; } | ON COMPLETION_SYM NOT_SYM PRESERVE_SYM { Lex->event_parse_data->on_completion= - Event_basic::ON_COMPLETION_DROP; + Event_parse_data::ON_COMPLETION_DROP; $$= 1; } ; @@ -1906,7 +1923,7 @@ ev_sql_stmt: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; /* This stops the following : @@ -2004,6 +2021,8 @@ sp_name: MYSQL_YYABORT; } $$= new sp_name($1, $3, true); + if ($$ == NULL) + MYSQL_YYABORT; $$->init_qname(YYTHD); } | ident @@ -2018,8 +2037,9 @@ sp_name: if (lex->copy_db_to(&db.str, &db.length)) MYSQL_YYABORT; $$= new sp_name(db, $1, false); - if ($$) - $$->init_qname(thd); + if ($$ == NULL) + MYSQL_YYABORT; + $$->init_qname(thd); } ; @@ -2256,6 +2276,7 @@ sp_decl: type sp_opt_default { + THD *thd= YYTHD; LEX *lex= Lex; sp_pcontext *pctx= lex->spcont; uint num_vars= pctx->context_var_count(); @@ -2264,7 +2285,9 @@ sp_decl: if (!dflt_value_item) { - dflt_value_item= new Item_null(); + dflt_value_item= new (thd->mem_root) Item_null(); + if (dflt_value_item == NULL) + MYSQL_YYABORT; /* QQ Set to the var_type with null_value? */ } @@ -2290,10 +2313,17 @@ sp_decl: /* The last instruction is responsible for freeing LEX. */ - lex->sphead->add_instr( - new sp_instr_set(lex->sphead->instructions(), pctx, var_idx, - dflt_value_item, var_type, lex, - (i == num_vars - 1))); + sp_instr_set *is= new sp_instr_set(lex->sphead->instructions(), + pctx, + var_idx, + dflt_value_item, + var_type, + lex, + (i == num_vars - 1)); + if (is == NULL) + MYSQL_YYABORT; + + lex->sphead->add_instr(is); } pctx->declare_var_boundary(0); @@ -2327,7 +2357,8 @@ sp_decl: sp_instr_hpush_jump *i= new sp_instr_hpush_jump(sp->instructions(), ctx, $2, ctx->current_var_count()); - + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); sp->push_backpatch(i, ctx->push_label((char *)"", 0)); } @@ -2343,12 +2374,15 @@ sp_decl: { i= new sp_instr_hreturn(sp->instructions(), ctx, ctx->current_var_count()); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); } else { /* EXIT or UNDO handler, just jump to the end of the block */ i= new sp_instr_hreturn(sp->instructions(), ctx, 0); - + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */ } @@ -2376,6 +2410,8 @@ sp_decl: } i= new sp_instr_cpush(sp->instructions(), ctx, $5, ctx->current_cursor_count()); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); ctx->push_cursor(&$2); $$.vars= $$.conds= $$.hndlrs= 0; @@ -2445,6 +2481,8 @@ sp_cond: ulong_num { /* mysql errno */ $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t)); + if ($$ == NULL) + MYSQL_YYABORT; $$->type= sp_cond_type_t::number; $$->mysqlerr= $1; } @@ -2456,6 +2494,8 @@ sp_cond: MYSQL_YYABORT; } $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t)); + if ($$ == NULL) + MYSQL_YYABORT; $$->type= sp_cond_type_t::state; memcpy($$->sqlstate, $3.str, 5); $$->sqlstate[5]= '\0'; @@ -2484,16 +2524,22 @@ sp_hcond: | SQLWARNING_SYM /* SQLSTATEs 01??? */ { $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t)); + if ($$ == NULL) + MYSQL_YYABORT; $$->type= sp_cond_type_t::warning; } | not FOUND_SYM /* SQLSTATEs 02??? */ { $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t)); + if ($$ == NULL) + MYSQL_YYABORT; $$->type= sp_cond_type_t::notfound; } | SQLEXCEPTION_SYM /* All other SQLSTATEs */ { $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t)); + if ($$ == NULL) + MYSQL_YYABORT; $$->type= sp_cond_type_t::exception; } ; @@ -2563,7 +2609,7 @@ sp_proc_stmt_statement: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; lex->sphead->reset_lex(thd); lex->sphead->m_tmp_query= lip->get_tok_start(); @@ -2572,7 +2618,7 @@ sp_proc_stmt_statement: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; sp_head *sp= lex->sphead; sp->m_flags|= sp_get_flags_for_command(lex); @@ -2592,6 +2638,8 @@ sp_proc_stmt_statement: { sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(), lex->spcont, lex); + if (i == NULL) + MYSQL_YYABORT; /* Extract the query statement from the tokenizer. The @@ -2630,6 +2678,8 @@ sp_proc_stmt_return: i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3, sp->m_return_field_def.sql_type, lex); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); sp->m_flags|= sp_head::HAS_RETURN; } @@ -2740,6 +2790,8 @@ sp_proc_stmt_iterate: sp->add_instr(cpop); } i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */ + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); } } @@ -2759,6 +2811,8 @@ sp_proc_stmt_open: MYSQL_YYABORT; } i= new sp_instr_copen(sp->instructions(), lex->spcont, offset); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); } ; @@ -2777,6 +2831,8 @@ sp_proc_stmt_fetch: MYSQL_YYABORT; } i= new sp_instr_cfetch(sp->instructions(), lex->spcont, offset); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); } sp_fetch_list @@ -2797,6 +2853,8 @@ sp_proc_stmt_close: MYSQL_YYABORT; } i= new sp_instr_cclose(sp->instructions(), lex->spcont, offset); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); } ; @@ -2860,6 +2918,8 @@ sp_if: uint ip= sp->instructions(); sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx, $2, lex); + if (i == NULL) + MYSQL_YYABORT; sp->push_backpatch(i, ctx->push_label((char *)"", 0)); sp->add_cont_backpatch(i); @@ -2872,6 +2932,8 @@ sp_if: sp_pcontext *ctx= Lex->spcont; uint ip= sp->instructions(); sp_instr_jump *i = new sp_instr_jump(ip, ctx); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); sp->backpatch(ctx->pop_label()); @@ -2995,6 +3057,8 @@ else_clause_opt: uint ip= sp->instructions(); sp_instr_error *i= new sp_instr_error(ip, lex->spcont, ER_SP_CASE_NOT_FOUND); + if (i == NULL) + MYSQL_YYABORT; sp->add_instr(i); } | ELSE sp_proc_stmts1 @@ -3103,14 +3167,23 @@ sp_block_content: LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; + sp_instr *i; sp->backpatch(ctx->last_label()); /* We always have a label */ if ($3.hndlrs) - sp->add_instr(new sp_instr_hpop(sp->instructions(), ctx, - $3.hndlrs)); + { + i= new sp_instr_hpop(sp->instructions(), ctx, $3.hndlrs); + if (i == NULL) + MYSQL_YYABORT; + sp->add_instr(i); + } if ($3.curs) - sp->add_instr(new sp_instr_cpop(sp->instructions(), ctx, - $3.curs)); + { + i= new sp_instr_cpop(sp->instructions(), ctx, $3.curs); + if (i == NULL) + MYSQL_YYABORT; + sp->add_instr(i); + } lex->spcont= ctx->pop_context(); } ; @@ -3123,7 +3196,8 @@ sp_unlabeled_control: uint ip= lex->sphead->instructions(); sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */ sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip); - + if (i == NULL) + MYSQL_YYABORT; lex->sphead->add_instr(i); } | WHILE_SYM @@ -3135,7 +3209,8 @@ sp_unlabeled_control: uint ip= sp->instructions(); sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont, $3, lex); - + if (i == NULL) + MYSQL_YYABORT; /* Jumping forward */ sp->push_backpatch(i, lex->spcont->last_label()); sp->new_cont_backpatch(i); @@ -3148,7 +3223,8 @@ sp_unlabeled_control: uint ip= lex->sphead->instructions(); sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */ sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip); - + if (i == NULL) + MYSQL_YYABORT; lex->sphead->add_instr(i); lex->sphead->do_cont_backpatch(); } @@ -3162,6 +3238,8 @@ sp_unlabeled_control: sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont, $5, lab->ip, lex); + if (i == NULL) + MYSQL_YYABORT; lex->sphead->add_instr(i); lex->sphead->restore_lex(YYTHD); /* We can shortcut the cont_backpatch here */ @@ -3378,6 +3456,8 @@ tablespace_name: { LEX *lex= Lex; lex->alter_tablespace_info= new st_alter_tablespace(); + if (lex->alter_tablespace_info == NULL) + MYSQL_YYABORT; lex->alter_tablespace_info->tablespace_name= $1.str; lex->sql_command= SQLCOM_ALTER_TABLESPACE; } @@ -3388,6 +3468,8 @@ logfile_group_name: { LEX *lex= Lex; lex->alter_tablespace_info= new st_alter_tablespace(); + if (lex->alter_tablespace_info == NULL) + MYSQL_YYABORT; lex->alter_tablespace_info->logfile_group_name= $1.str; lex->sql_command= SQLCOM_ALTER_TABLESPACE; } @@ -3582,20 +3664,30 @@ create2: | LIKE table_ident { THD *thd= YYTHD; + TABLE_LIST *src_table; LEX *lex= thd->lex; lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE; - if (!lex->select_lex.add_table_to_list(thd, $2, NULL, 0, TL_READ)) + src_table= lex->select_lex.add_table_to_list(thd, $2, NULL, 0, + TL_READ); + if (! src_table) MYSQL_YYABORT; + /* CREATE TABLE ... LIKE is not allowed for views. */ + src_table->required_type= FRMTYPE_TABLE; } | '(' LIKE table_ident ')' { THD *thd= YYTHD; + TABLE_LIST *src_table; LEX *lex= thd->lex; lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE; - if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0, TL_READ)) + src_table= lex->select_lex.add_table_to_list(thd, $3, NULL, 0, + TL_READ); + if (! src_table) MYSQL_YYABORT; + /* CREATE TABLE ... LIKE is not allowed for views. */ + src_table->required_type= FRMTYPE_TABLE; } ; @@ -3753,7 +3845,10 @@ part_func: uint expr_len= (uint)($4 - $2) - 1; lex->part_info->list_of_part_fields= FALSE; lex->part_info->part_expr= $3; - lex->part_info->part_func_string= (char* ) sql_memdup($2+1, expr_len); + char *func_string= (char*) sql_memdup($2+1, expr_len); + if (func_string == NULL) + MYSQL_YYABORT; + lex->part_info->part_func_string= func_string; lex->part_info->part_func_len= expr_len; } ; @@ -3765,7 +3860,10 @@ sub_part_func: uint expr_len= (uint)($4 - $2) - 1; lex->part_info->list_of_subpart_fields= FALSE; lex->part_info->subpart_expr= $3; - lex->part_info->subpart_func_string= (char* ) sql_memdup($2+1, expr_len); + char *func_string= (char*) sql_memdup($2+1, expr_len); + if (func_string == NULL) + MYSQL_YYABORT; + lex->part_info->subpart_func_string= func_string; lex->part_info->subpart_func_len= expr_len; } ; @@ -4557,6 +4655,8 @@ key_def: } Key *key= new Key($1, $2, &lex->key_create_info, 0, lex->col_list); + if (key == NULL) + MYSQL_YYABORT; lex->alter_info.key_list.push_back(key); lex->col_list.empty(); /* Alloced by sql_alloc */ } @@ -4567,6 +4667,8 @@ key_def: const char *key_name= $3 ? $3 : $1; Key *key= new Key($2, key_name, &lex->key_create_info, 0, lex->col_list); + if (key == NULL) + MYSQL_YYABORT; lex->alter_info.key_list.push_back(key); lex->col_list.empty(); /* Alloced by sql_alloc */ } @@ -4581,10 +4683,14 @@ key_def: lex->fk_delete_opt, lex->fk_update_opt, lex->fk_match_option); + if (key == NULL) + MYSQL_YYABORT; lex->alter_info.key_list.push_back(key); key= new Key(Key::MULTIPLE, key_name, &default_key_create_info, 1, lex->col_list); + if (key == NULL) + MYSQL_YYABORT; lex->alter_info.key_list.push_back(key); lex->col_list.empty(); /* Alloced by sql_alloc */ /* Only used for ALTER TABLE. Ignored otherwise. */ @@ -4642,7 +4748,7 @@ field_spec: ; type: - int_type opt_len field_options { $$=$1; } + int_type opt_field_length field_options { $$=$1; } | real_type opt_precision field_options { $$=$1; } | FLOAT_SYM float_options field_options { $$=MYSQL_TYPE_FLOAT; } | BIT_SYM @@ -4650,46 +4756,42 @@ type: Lex->length= (char*) "1"; $$=MYSQL_TYPE_BIT; } - | BIT_SYM '(' NUM ')' + | BIT_SYM field_length { - Lex->length= $3.str; $$=MYSQL_TYPE_BIT; } | BOOL_SYM { - Lex->length=(char*) "1"; + Lex->length= (char*) "1"; $$=MYSQL_TYPE_TINY; } | BOOLEAN_SYM { - Lex->length=(char*) "1"; + Lex->length= (char*) "1"; $$=MYSQL_TYPE_TINY; } - | char '(' NUM ')' opt_binary + | char field_length opt_binary { - Lex->length=$3.str; $$=MYSQL_TYPE_STRING; } | char opt_binary { - Lex->length=(char*) "1"; + Lex->length= (char*) "1"; $$=MYSQL_TYPE_STRING; } - | nchar '(' NUM ')' opt_bin_mod + | nchar field_length opt_bin_mod { - Lex->length=$3.str; $$=MYSQL_TYPE_STRING; Lex->charset=national_charset_info; } | nchar opt_bin_mod { - Lex->length=(char*) "1"; + Lex->length= (char*) "1"; $$=MYSQL_TYPE_STRING; Lex->charset=national_charset_info; } - | BINARY '(' NUM ')' + | BINARY field_length { - Lex->length=$3.str; Lex->charset=&my_charset_bin; $$=MYSQL_TYPE_STRING; } @@ -4699,30 +4801,27 @@ type: Lex->charset=&my_charset_bin; $$=MYSQL_TYPE_STRING; } - | varchar '(' NUM ')' opt_binary + | varchar field_length opt_binary { - Lex->length=$3.str; $$= MYSQL_TYPE_VARCHAR; } - | nvarchar '(' NUM ')' opt_bin_mod + | nvarchar field_length opt_bin_mod { - Lex->length=$3.str; $$= MYSQL_TYPE_VARCHAR; Lex->charset=national_charset_info; } - | VARBINARY '(' NUM ')' + | VARBINARY field_length { - Lex->length=$3.str; Lex->charset=&my_charset_bin; $$= MYSQL_TYPE_VARCHAR; } - | YEAR_SYM opt_len field_options + | YEAR_SYM opt_field_length field_options { $$=MYSQL_TYPE_YEAR; } | DATE_SYM { $$=MYSQL_TYPE_DATE; } | TIME_SYM { $$=MYSQL_TYPE_TIME; } - | TIMESTAMP opt_len + | TIMESTAMP opt_field_length { if (YYTHD->variables.sql_mode & MODE_MAXDB) $$=MYSQL_TYPE_DATETIME; @@ -4742,7 +4841,7 @@ type: Lex->charset=&my_charset_bin; $$=MYSQL_TYPE_TINY_BLOB; } - | BLOB_SYM opt_len + | BLOB_SYM opt_field_length { Lex->charset=&my_charset_bin; $$=MYSQL_TYPE_BLOB; @@ -4778,7 +4877,7 @@ type: { $$=MYSQL_TYPE_MEDIUM_BLOB; } | TINYTEXT opt_binary { $$=MYSQL_TYPE_TINY_BLOB; } - | TEXT_SYM opt_len opt_binary + | TEXT_SYM opt_field_length opt_binary { $$=MYSQL_TYPE_BLOB; } | MEDIUMTEXT opt_binary { $$=MYSQL_TYPE_MEDIUM_BLOB; } @@ -4868,8 +4967,8 @@ real_type: float_options: /* empty */ { Lex->dec=Lex->length= (char*)0; } - | '(' NUM ')' - { Lex->length=$2.str; Lex->dec= (char*)0; } + | field_length + { Lex->dec= (char*)0; } | precision {} ; @@ -4899,10 +4998,15 @@ field_option: | ZEROFILL { Lex->type|= UNSIGNED_FLAG | ZEROFILL_FLAG; } ; -opt_len: - /* empty */ { Lex->length=(char*) 0; /* use default length */ } - | '(' NUM ')' { Lex->length= $2.str; } - ; +field_length: + '(' LONG_NUM ')' { Lex->length= $2.str; } + | '(' ULONGLONG_NUM ')' { Lex->length= $2.str; } + | '(' DECIMAL_NUM ')' { Lex->length= $2.str; } + | '(' NUM ')' { Lex->length= $2.str; }; + +opt_field_length: + /* empty */ { Lex->length=(char*) 0; /* use default length */ } + | field_length { } opt_precision: /* empty */ {} @@ -4924,7 +5028,12 @@ attribute: | not NULL_SYM { Lex->type|= NOT_NULL_FLAG; } | DEFAULT now_or_signed_literal { Lex->default_value=$2; } | ON UPDATE_SYM NOW_SYM optional_braces - { Lex->on_update_value= new Item_func_now_local(); } + { + Item *item= new (YYTHD->mem_root) Item_func_now_local(); + if (item == NULL) + MYSQL_YYABORT; + Lex->on_update_value= item; + } | AUTO_INC { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; } | SERIAL_SYM DEFAULT VALUE_SYM { @@ -4968,7 +5077,11 @@ attribute: now_or_signed_literal: NOW_SYM optional_braces - { $$= new Item_func_now_local(); } + { + $$= new (YYTHD->mem_root) Item_func_now_local(); + if ($$ == NULL) + MYSQL_YYABORT; + } | signed_literal { $$=$1; } ; @@ -5105,8 +5218,20 @@ opt_ref_list: ; ref_list: - ref_list ',' ident { Lex->ref_list.push_back(new Key_part_spec($3.str)); } - | ident { Lex->ref_list.push_back(new Key_part_spec($1.str)); } + ref_list ',' ident + { + Key_part_spec *key= new Key_part_spec($3.str); + if (key == NULL) + MYSQL_YYABORT; + Lex->ref_list.push_back(key); + } + | ident + { + Key_part_spec *key= new Key_part_spec($1.str); + if (key == NULL) + MYSQL_YYABORT; + Lex->ref_list.push_back(key); + } ; opt_on_delete: @@ -5247,7 +5372,12 @@ key_list: ; key_part: - ident { $$=new Key_part_spec($1.str); } + ident + { + $$= new Key_part_spec($1.str); + if ($$ == NULL) + MYSQL_YYABORT; + } | ident '(' NUM ')' { int key_part_len= atoi($3.str); @@ -5255,7 +5385,9 @@ key_part: { my_error(ER_KEY_PART_0, MYF(0), $1.str); } - $$=new Key_part_spec($1.str,(uint) key_part_len); + $$= new Key_part_spec($1.str,(uint) key_part_len); + if ($$ == NULL) + MYSQL_YYABORT; } ; @@ -5398,10 +5530,6 @@ alter: view_tail {} | ALTER definer_opt 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 - */ { /* It is safe to use Lex->spname because @@ -5415,14 +5543,6 @@ alter: MYSQL_YYABORT; Lex->event_parse_data->identifier= $4; - /* - We have to turn off CLIENT_MULTI_QUERIES while parsing a - stored procedure, otherwise yylex will chop it into pieces - at each ';'. - */ - $<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; - YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES; - Lex->sql_command= SQLCOM_ALTER_EVENT; } ev_alter_on_schedule_completion @@ -5431,15 +5551,6 @@ alter: opt_ev_comment opt_ev_sql_stmt { - /* - $1 - ALTER - $2 - definer_opt - $3 - EVENT_SYM - $4 - sp_name - $5 - the block above - */ - YYTHD->client_capabilities |= $<ulong_num>5; - if (!($6 || $7 || $8 || $9 || $10)) { my_parse_error(ER(ER_SYNTAX_ERROR)); @@ -5544,6 +5655,7 @@ alter_commands: all_or_alt_part_name_list { LEX *lex= Lex; + lex->sql_command = SQLCOM_OPTIMIZE; lex->alter_info.flags|= ALTER_OPTIMIZE_PARTITION; lex->no_write_to_binlog= $3; lex->check_opt.init(); @@ -5553,6 +5665,7 @@ alter_commands: all_or_alt_part_name_list { LEX *lex= Lex; + lex->sql_command = SQLCOM_ANALYZE; lex->alter_info.flags|= ALTER_ANALYZE_PARTITION; lex->no_write_to_binlog= $3; lex->check_opt.init(); @@ -5560,6 +5673,7 @@ alter_commands: | CHECK_SYM PARTITION_SYM all_or_alt_part_name_list { LEX *lex= Lex; + lex->sql_command = SQLCOM_CHECK; lex->alter_info.flags|= ALTER_CHECK_PARTITION; lex->check_opt.init(); } @@ -5568,6 +5682,7 @@ alter_commands: all_or_alt_part_name_list { LEX *lex= Lex; + lex->sql_command = SQLCOM_REPAIR; lex->alter_info.flags|= ALTER_REPAIR_PARTITION; lex->no_write_to_binlog= $3; lex->check_opt.init(); @@ -5636,7 +5751,7 @@ reorg_partition_rule: lex->part_info= new partition_info(); if (!lex->part_info) { - mem_alloc_error(sizeof(partition_info)); + mem_alloc_error(sizeof(partition_info)); MYSQL_YYABORT; } lex->no_write_to_binlog= $3; @@ -5736,8 +5851,10 @@ alter_list_item: | DROP opt_column field_ident opt_restrict { LEX *lex=Lex; - lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::COLUMN, - $3.str)); + Alter_drop *ad= new Alter_drop(Alter_drop::COLUMN, $3.str); + if (ad == NULL) + MYSQL_YYABORT; + lex->alter_info.drop_list.push_back(ad); lex->alter_info.flags|= ALTER_DROP_COLUMN; } | DROP FOREIGN KEY_SYM opt_ident @@ -5747,15 +5864,19 @@ alter_list_item: | DROP PRIMARY_SYM KEY_SYM { LEX *lex=Lex; - lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY, - primary_key_name)); + Alter_drop *ad= new Alter_drop(Alter_drop::KEY, primary_key_name); + if (ad == NULL) + MYSQL_YYABORT; + lex->alter_info.drop_list.push_back(ad); lex->alter_info.flags|= ALTER_DROP_INDEX; } | DROP key_or_index field_ident { LEX *lex=Lex; - lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY, - $3.str)); + Alter_drop *ad= new Alter_drop(Alter_drop::KEY, $3.str); + if (ad == NULL) + MYSQL_YYABORT; + lex->alter_info.drop_list.push_back(ad); lex->alter_info.flags|= ALTER_DROP_INDEX; } | DISABLE_SYM KEYS @@ -5773,14 +5894,19 @@ alter_list_item: | ALTER opt_column field_ident SET DEFAULT signed_literal { LEX *lex=Lex; - lex->alter_info.alter_list.push_back(new Alter_column($3.str,$6)); + Alter_column *ac= new Alter_column($3.str,$6); + if (ac == NULL) + MYSQL_YYABORT; + lex->alter_info.alter_list.push_back(ac); lex->alter_info.flags|= ALTER_CHANGE_COLUMN_DEFAULT; } | ALTER opt_column field_ident DROP DEFAULT { LEX *lex=Lex; - lex->alter_info.alter_list.push_back(new Alter_column($3.str, - (Item*) 0)); + Alter_column *ac= new Alter_column($3.str, (Item*) 0); + if (ac == NULL) + MYSQL_YYABORT; + lex->alter_info.alter_list.push_back(ac); lex->alter_info.flags|= ALTER_CHANGE_COLUMN_DEFAULT; } | RENAME opt_to table_ident @@ -6010,6 +6136,7 @@ repair: lex->sql_command = SQLCOM_REPAIR; lex->no_write_to_binlog= $2; lex->check_opt.init(); + lex->alter_info.reset(); } table_list opt_mi_repair_type {} @@ -6038,6 +6165,7 @@ analyze: lex->sql_command = SQLCOM_ANALYZE; lex->no_write_to_binlog= $2; lex->check_opt.init(); + lex->alter_info.reset(); } table_list {} @@ -6063,6 +6191,7 @@ check: } lex->sql_command = SQLCOM_CHECK; lex->check_opt.init(); + lex->alter_info.reset(); } table_list opt_mi_check_type {} @@ -6094,6 +6223,7 @@ optimize: lex->sql_command = SQLCOM_OPTIMIZE; lex->no_write_to_binlog= $2; lex->check_opt.init(); + lex->alter_info.reset(); } table_list {} @@ -6420,10 +6550,12 @@ select_item_list: | '*' { THD *thd= YYTHD; - if (add_item_to_list(thd, - new Item_field(&thd->lex->current_select-> - context, - NULL, NULL, "*"))) + Item *item= new (thd->mem_root) + Item_field(&thd->lex->current_select->context, + NULL, NULL, "*"); + if (item == NULL) + MYSQL_YYABORT; + if (add_item_to_list(thd, item)) MYSQL_YYABORT; (thd->lex->current_select->with_wild)++; } @@ -6457,17 +6589,13 @@ select_item: remember_name: { - THD *thd= YYTHD; - Lex_input_stream *lip= thd->m_lip; - $$= (char*) lip->get_cpp_tok_start(); + $$= (char*) YYLIP->get_cpp_tok_start(); } ; remember_end: { - THD *thd= YYTHD; - Lex_input_stream *lip= thd->m_lip; - $$= (char*) lip->get_cpp_tok_end(); + $$= (char*) YYLIP->get_cpp_tok_end(); } ; @@ -6538,12 +6666,16 @@ expr: { /* X OR Y */ $$ = new (YYTHD->mem_root) Item_cond_or($1, $3); + if ($$ == NULL) + MYSQL_YYABORT; } } | expr XOR expr %prec XOR { /* XOR is a proprietary extension */ $$ = new (YYTHD->mem_root) Item_cond_xor($1, $3); + if ($$ == NULL) + MYSQL_YYABORT; } | expr and expr %prec AND_SYM { @@ -6584,36 +6716,86 @@ expr: { /* X AND Y */ $$ = new (YYTHD->mem_root) Item_cond_and($1, $3); + if ($$ == NULL) + MYSQL_YYABORT; } } | NOT_SYM expr %prec NOT_SYM - { $$= negate_expression(YYTHD, $2); } + { + $$= negate_expression(YYTHD, $2); + if ($$ == NULL) + MYSQL_YYABORT; + } | bool_pri IS TRUE_SYM %prec IS - { $$= new (YYTHD->mem_root) Item_func_istrue($1); } + { + $$= new (YYTHD->mem_root) Item_func_istrue($1); + if ($$ == NULL) + MYSQL_YYABORT; + } | bool_pri IS not TRUE_SYM %prec IS - { $$= new (YYTHD->mem_root) Item_func_isnottrue($1); } + { + $$= new (YYTHD->mem_root) Item_func_isnottrue($1); + if ($$ == NULL) + MYSQL_YYABORT; + } | bool_pri IS FALSE_SYM %prec IS - { $$= new (YYTHD->mem_root) Item_func_isfalse($1); } + { + $$= new (YYTHD->mem_root) Item_func_isfalse($1); + if ($$ == NULL) + MYSQL_YYABORT; + } | bool_pri IS not FALSE_SYM %prec IS - { $$= new (YYTHD->mem_root) Item_func_isnotfalse($1); } + { + $$= new (YYTHD->mem_root) Item_func_isnotfalse($1); + if ($$ == NULL) + MYSQL_YYABORT; + } | bool_pri IS UNKNOWN_SYM %prec IS - { $$= new Item_func_isnull($1); } + { + $$= new (YYTHD->mem_root) Item_func_isnull($1); + if ($$ == NULL) + MYSQL_YYABORT; + } | bool_pri IS not UNKNOWN_SYM %prec IS - { $$= new Item_func_isnotnull($1); } + { + $$= new (YYTHD->mem_root) Item_func_isnotnull($1); + if ($$ == NULL) + MYSQL_YYABORT; + } | bool_pri ; bool_pri: bool_pri IS NULL_SYM %prec IS - { $$= new Item_func_isnull($1); } + { + $$= new (YYTHD->mem_root) Item_func_isnull($1); + if ($$ == NULL) + MYSQL_YYABORT; + } | bool_pri IS not NULL_SYM %prec IS - { $$= new Item_func_isnotnull($1); } + { + $$= new (YYTHD->mem_root) Item_func_isnotnull($1); + if ($$ == NULL) + MYSQL_YYABORT; + } | bool_pri EQUAL_SYM predicate %prec EQUAL_SYM - { $$= new Item_func_equal($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_equal($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bool_pri comp_op predicate %prec EQ - { $$= (*$2)(0)->create($1,$3); } + { + $$= (*$2)(0)->create($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bool_pri comp_op all_or_any '(' subselect ')' %prec EQ - { $$= all_any_subquery_creator($1, $2, $3, $5); } + { + $$= all_any_subquery_creator($1, $2, $3, $5); + if ($$ == NULL) + MYSQL_YYABORT; + } | predicate ; @@ -6621,87 +6803,193 @@ predicate: bit_expr IN_SYM '(' subselect ')' { $$= new (YYTHD->mem_root) Item_in_subselect($1, $4); + if ($$ == NULL) + MYSQL_YYABORT; } | bit_expr not IN_SYM '(' subselect ')' { THD *thd= YYTHD; Item *item= new (thd->mem_root) Item_in_subselect($1, $5); + if (item == NULL) + MYSQL_YYABORT; $$= negate_expression(thd, item); + if ($$ == NULL) + MYSQL_YYABORT; } | bit_expr IN_SYM '(' expr ')' { $$= handle_sql2003_note184_exception(YYTHD, $1, true, $4); + if ($$ == NULL) + MYSQL_YYABORT; } | bit_expr IN_SYM '(' expr ',' expr_list ')' { $6->push_front($4); $6->push_front($1); $$= new (YYTHD->mem_root) Item_func_in(*$6); + if ($$ == NULL) + MYSQL_YYABORT; } | bit_expr not IN_SYM '(' expr ')' { $$= handle_sql2003_note184_exception(YYTHD, $1, false, $5); + if ($$ == NULL) + MYSQL_YYABORT; } | bit_expr not IN_SYM '(' expr ',' expr_list ')' { $7->push_front($5); $7->push_front($1); Item_func_in *item = new (YYTHD->mem_root) Item_func_in(*$7); + if (item == NULL) + MYSQL_YYABORT; item->negate(); $$= item; } | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate - { $$= new Item_func_between($1,$3,$5); } + { + $$= new (YYTHD->mem_root) Item_func_between($1,$3,$5); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate { - Item_func_between *item= new Item_func_between($1,$4,$6); + Item_func_between *item; + item= new (YYTHD->mem_root) Item_func_between($1,$4,$6); + if (item == NULL) + MYSQL_YYABORT; item->negate(); $$= item; } | bit_expr SOUNDS_SYM LIKE bit_expr { - $$= new Item_func_eq(new Item_func_soundex($1), - new Item_func_soundex($4)); + Item *item1= new (YYTHD->mem_root) Item_func_soundex($1); + Item *item4= new (YYTHD->mem_root) Item_func_soundex($4); + if ((item1 == NULL) || (item4 == NULL)) + MYSQL_YYABORT; + $$= new (YYTHD->mem_root) Item_func_eq(item1, item4); + if ($$ == NULL) + MYSQL_YYABORT; } | bit_expr LIKE simple_expr opt_escape - { $$= new Item_func_like($1,$3,$4,Lex->escape_used); } + { + $$= new (YYTHD->mem_root) Item_func_like($1,$3,$4,Lex->escape_used); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr not LIKE simple_expr opt_escape - { $$= new Item_func_not(new Item_func_like($1,$4,$5, Lex->escape_used)); } - | bit_expr REGEXP bit_expr { $$= new Item_func_regex($1,$3); } + { + Item *item= new (YYTHD->mem_root) Item_func_like($1,$4,$5, + Lex->escape_used); + if (item == NULL) + MYSQL_YYABORT; + $$= new (YYTHD->mem_root) Item_func_not(item); + if ($$ == NULL) + MYSQL_YYABORT; + } + | bit_expr REGEXP bit_expr + { + $$= new (YYTHD->mem_root) Item_func_regex($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr not REGEXP bit_expr - { $$= negate_expression(YYTHD, new Item_func_regex($1,$4)); } + { + Item *item= new (YYTHD->mem_root) Item_func_regex($1,$4); + if (item == NULL) + MYSQL_YYABORT; + $$= negate_expression(YYTHD, item); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr ; bit_expr: bit_expr '|' bit_expr %prec '|' - { $$= new Item_func_bit_or($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_bit_or($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr '&' bit_expr %prec '&' - { $$= new Item_func_bit_and($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_bit_and($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr SHIFT_LEFT bit_expr %prec SHIFT_LEFT - { $$= new Item_func_shift_left($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_shift_left($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr SHIFT_RIGHT bit_expr %prec SHIFT_RIGHT - { $$= new Item_func_shift_right($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_shift_right($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr '+' bit_expr %prec '+' - { $$= new Item_func_plus($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_plus($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr '-' bit_expr %prec '-' - { $$= new Item_func_minus($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_minus($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr '+' INTERVAL_SYM expr interval %prec '+' - { $$= new Item_date_add_interval($1,$4,$5,0); } + { + $$= new (YYTHD->mem_root) Item_date_add_interval($1,$4,$5,0); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr '-' INTERVAL_SYM expr interval %prec '-' - { $$= new Item_date_add_interval($1,$4,$5,1); } + { + $$= new (YYTHD->mem_root) Item_date_add_interval($1,$4,$5,1); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr '*' bit_expr %prec '*' - { $$= new Item_func_mul($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_mul($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr '/' bit_expr %prec '/' - { $$= new Item_func_div($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_div($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr '%' bit_expr %prec '%' - { $$= new Item_func_mod($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_mod($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr DIV_SYM bit_expr %prec DIV_SYM - { $$= new Item_func_int_div($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_int_div($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr MOD_SYM bit_expr %prec MOD_SYM - { $$= new Item_func_mod($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_mod($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | bit_expr '^' bit_expr - { $$= new Item_func_bit_xor($1,$3); } + { + $$= new (YYTHD->mem_root) Item_func_bit_xor($1,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | simple_expr ; @@ -6751,45 +7039,80 @@ simple_expr: Item *i1= new (thd->mem_root) Item_string($3.str, $3.length, thd->charset()); + if (i1 == NULL) + MYSQL_YYABORT; $$= new (thd->mem_root) Item_func_set_collation($1, i1); + if ($$ == NULL) + MYSQL_YYABORT; } | literal | param_marker | variable | sum_expr | simple_expr OR_OR_SYM simple_expr - { $$= new (YYTHD->mem_root) Item_func_concat($1, $3); } - | '+' simple_expr %prec NEG { $$= $2; } + { + $$= new (YYTHD->mem_root) Item_func_concat($1, $3); + if ($$ == NULL) + MYSQL_YYABORT; + } + | '+' simple_expr %prec NEG + { + $$= $2; + } | '-' simple_expr %prec NEG - { $$= new (YYTHD->mem_root) Item_func_neg($2); } + { + $$= new (YYTHD->mem_root) Item_func_neg($2); + if ($$ == NULL) + MYSQL_YYABORT; + } | '~' simple_expr %prec NEG - { $$= new (YYTHD->mem_root) Item_func_bit_neg($2); } + { + $$= new (YYTHD->mem_root) Item_func_bit_neg($2); + if ($$ == NULL) + MYSQL_YYABORT; + } | not2 simple_expr %prec NEG - { $$= negate_expression(YYTHD, $2); } + { + $$= negate_expression(YYTHD, $2); + if ($$ == NULL) + MYSQL_YYABORT; + } | '(' subselect ')' { - $$= new (YYTHD->mem_root) Item_singlerow_subselect($2); + $$= new (YYTHD->mem_root) Item_singlerow_subselect($2); + if ($$ == NULL) + MYSQL_YYABORT; } - | '(' expr ')' { $$= $2; } + | '(' expr ')' + { $$= $2; } | '(' expr ',' expr_list ')' { $4->push_front($2); $$= new (YYTHD->mem_root) Item_row(*$4); + if ($$ == NULL) + MYSQL_YYABORT; } | ROW_SYM '(' expr ',' expr_list ')' { $5->push_front($3); $$= new (YYTHD->mem_root) Item_row(*$5); + if ($$ == NULL) + MYSQL_YYABORT; } | EXISTS '(' subselect ')' { - $$= new (YYTHD->mem_root) Item_exists_subselect($3); + $$= new (YYTHD->mem_root) Item_exists_subselect($3); + if ($$ == NULL) + MYSQL_YYABORT; } - | '{' ident expr '}' { $$= $3; } + | '{' ident expr '}' + { $$= $3; } | MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')' { $2->push_front($5); Item_func_match *i1= new (YYTHD->mem_root) Item_func_match(*$2, $6); + if (i1 == NULL) + MYSQL_YYABORT; Select->add_ftfunc_to_list(i1); $$= i1; } @@ -6797,26 +7120,36 @@ simple_expr: { $$= create_func_cast(YYTHD, $2, ITEM_CAST_CHAR, NULL, NULL, &my_charset_bin); + if ($$ == NULL) + MYSQL_YYABORT; } | CAST_SYM '(' expr AS cast_type ')' { LEX *lex= Lex; $$= create_func_cast(YYTHD, $3, $5, lex->length, lex->dec, lex->charset); - if (!$$) + if ($$ == NULL) MYSQL_YYABORT; } | CASE_SYM opt_expr when_list opt_else END - { $$= new (YYTHD->mem_root) Item_func_case(* $3, $2, $4 ); } + { + $$= new (YYTHD->mem_root) Item_func_case(* $3, $2, $4 ); + if ($$ == NULL) + MYSQL_YYABORT; + } | CONVERT_SYM '(' expr ',' cast_type ')' { $$= create_func_cast(YYTHD, $3, $5, Lex->length, Lex->dec, Lex->charset); - if (!$$) + if ($$ == NULL) MYSQL_YYABORT; } | CONVERT_SYM '(' expr USING charset_name ')' - { $$= new (YYTHD->mem_root) Item_func_conv_charset($3,$5); } + { + $$= new (YYTHD->mem_root) Item_func_conv_charset($3,$5); + if ($$ == NULL) + MYSQL_YYABORT; + } | DEFAULT '(' simple_ident ')' { if ($3->is_splocal()) @@ -6828,15 +7161,23 @@ simple_expr: } $$= new (YYTHD->mem_root) Item_default_value(Lex->current_context(), $3); + if ($$ == NULL) + MYSQL_YYABORT; } | VALUES '(' simple_ident_nospvar ')' { $$= new (YYTHD->mem_root) Item_insert_value(Lex->current_context(), $3); + if ($$ == NULL) + MYSQL_YYABORT; } | INTERVAL_SYM expr interval '+' expr %prec INTERVAL_SYM /* we cannot put interval before - */ - { $$= new (YYTHD->mem_root) Item_date_add_interval($5,$2,$3,0); } + { + $$= new (YYTHD->mem_root) Item_date_add_interval($5,$2,$3,0); + if ($$ == NULL) + MYSQL_YYABORT; + } ; /* @@ -6847,31 +7188,63 @@ simple_expr: */ function_call_keyword: CHAR_SYM '(' expr_list ')' - { $$= new (YYTHD->mem_root) Item_func_char(*$3); } + { + $$= new (YYTHD->mem_root) Item_func_char(*$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | CHAR_SYM '(' expr_list USING charset_name ')' - { $$= new (YYTHD->mem_root) Item_func_char(*$3, $5); } + { + $$= new (YYTHD->mem_root) Item_func_char(*$3, $5); + if ($$ == NULL) + MYSQL_YYABORT; + } | CURRENT_USER optional_braces { $$= new (YYTHD->mem_root) Item_func_current_user(Lex->current_context()); + if ($$ == NULL) + MYSQL_YYABORT; Lex->set_stmt_unsafe(); Lex->safe_to_cache_query= 0; } | DATE_SYM '(' expr ')' - { $$= new (YYTHD->mem_root) Item_date_typecast($3); } + { + $$= new (YYTHD->mem_root) Item_date_typecast($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | DAY_SYM '(' expr ')' - { $$= new (YYTHD->mem_root) Item_func_dayofmonth($3); } + { + $$= new (YYTHD->mem_root) Item_func_dayofmonth($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | HOUR_SYM '(' expr ')' - { $$= new (YYTHD->mem_root) Item_func_hour($3); } + { + $$= new (YYTHD->mem_root) Item_func_hour($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | INSERT '(' expr ',' expr ',' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_insert($3,$5,$7,$9); } + { + $$= new (YYTHD->mem_root) Item_func_insert($3,$5,$7,$9); + if ($$ == NULL) + MYSQL_YYABORT; + } | INTERVAL_SYM '(' expr ',' expr ')' %prec INTERVAL_SYM { THD *thd= YYTHD; List<Item> *list= new (thd->mem_root) List<Item>; + if (list == NULL) + MYSQL_YYABORT; list->push_front($5); list->push_front($3); Item_row *item= new (thd->mem_root) Item_row(*list); + if (item == NULL) + MYSQL_YYABORT; $$= new (thd->mem_root) Item_func_interval(item); + if ($$ == NULL) + MYSQL_YYABORT; } | INTERVAL_SYM '(' expr ',' expr ',' expr_list ')' %prec INTERVAL_SYM { @@ -6879,48 +7252,122 @@ function_call_keyword: $7->push_front($5); $7->push_front($3); Item_row *item= new (thd->mem_root) Item_row(*$7); + if (item == NULL) + MYSQL_YYABORT; $$= new (thd->mem_root) Item_func_interval(item); + if ($$ == NULL) + MYSQL_YYABORT; } | LEFT '(' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_left($3,$5); } + { + $$= new (YYTHD->mem_root) Item_func_left($3,$5); + if ($$ == NULL) + MYSQL_YYABORT; + } | MINUTE_SYM '(' expr ')' - { $$= new (YYTHD->mem_root) Item_func_minute($3); } + { + $$= new (YYTHD->mem_root) Item_func_minute($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | MONTH_SYM '(' expr ')' - { $$= new (YYTHD->mem_root) Item_func_month($3); } + { + $$= new (YYTHD->mem_root) Item_func_month($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | RIGHT '(' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_right($3,$5); } + { + $$= new (YYTHD->mem_root) Item_func_right($3,$5); + if ($$ == NULL) + MYSQL_YYABORT; + } | SECOND_SYM '(' expr ')' - { $$= new (YYTHD->mem_root) Item_func_second($3); } + { + $$= new (YYTHD->mem_root) Item_func_second($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | TIME_SYM '(' expr ')' - { $$= new (YYTHD->mem_root) Item_time_typecast($3); } + { + $$= new (YYTHD->mem_root) Item_time_typecast($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | TIMESTAMP '(' expr ')' - { $$= new (YYTHD->mem_root) Item_datetime_typecast($3); } + { + $$= new (YYTHD->mem_root) Item_datetime_typecast($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | TIMESTAMP '(' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_add_time($3, $5, 1, 0); } + { + $$= new (YYTHD->mem_root) Item_func_add_time($3, $5, 1, 0); + if ($$ == NULL) + MYSQL_YYABORT; + } | TRIM '(' expr ')' - { $$= new (YYTHD->mem_root) Item_func_trim($3); } + { + $$= new (YYTHD->mem_root) Item_func_trim($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | TRIM '(' LEADING expr FROM expr ')' - { $$= new (YYTHD->mem_root) Item_func_ltrim($6,$4); } + { + $$= new (YYTHD->mem_root) Item_func_ltrim($6,$4); + if ($$ == NULL) + MYSQL_YYABORT; + } | TRIM '(' TRAILING expr FROM expr ')' - { $$= new (YYTHD->mem_root) Item_func_rtrim($6,$4); } + { + $$= new (YYTHD->mem_root) Item_func_rtrim($6,$4); + if ($$ == NULL) + MYSQL_YYABORT; + } | TRIM '(' BOTH expr FROM expr ')' - { $$= new (YYTHD->mem_root) Item_func_trim($6,$4); } + { + $$= new (YYTHD->mem_root) Item_func_trim($6,$4); + if ($$ == NULL) + MYSQL_YYABORT; + } | TRIM '(' LEADING FROM expr ')' - { $$= new (YYTHD->mem_root) Item_func_ltrim($5); } + { + $$= new (YYTHD->mem_root) Item_func_ltrim($5); + if ($$ == NULL) + MYSQL_YYABORT; + } | TRIM '(' TRAILING FROM expr ')' - { $$= new (YYTHD->mem_root) Item_func_rtrim($5); } + { + $$= new (YYTHD->mem_root) Item_func_rtrim($5); + if ($$ == NULL) + MYSQL_YYABORT; + } | TRIM '(' BOTH FROM expr ')' - { $$= new (YYTHD->mem_root) Item_func_trim($5); } + { + $$= new (YYTHD->mem_root) Item_func_trim($5); + if ($$ == NULL) + MYSQL_YYABORT; + } | TRIM '(' expr FROM expr ')' - { $$= new (YYTHD->mem_root) Item_func_trim($5,$3); } + { + $$= new (YYTHD->mem_root) Item_func_trim($5,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | USER '(' ')' { $$= new (YYTHD->mem_root) Item_func_user(); + if ($$ == NULL) + MYSQL_YYABORT; Lex->set_stmt_unsafe(); Lex->safe_to_cache_query=0; } | YEAR_SYM '(' expr ')' - { $$= new (YYTHD->mem_root) Item_func_year($3); } + { + $$= new (YYTHD->mem_root) Item_func_year($3); + if ($$ == NULL) + MYSQL_YYABORT; + } ; /* @@ -6940,65 +7387,127 @@ function_call_nonkeyword: { $$= new (YYTHD->mem_root) Item_date_add_interval($3, $5, INTERVAL_DAY, 0); + if ($$ == NULL) + MYSQL_YYABORT; } | ADDDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')' - { $$= new (YYTHD->mem_root) Item_date_add_interval($3, $6, $7, 0); } + { + $$= new (YYTHD->mem_root) Item_date_add_interval($3, $6, $7, 0); + if ($$ == NULL) + MYSQL_YYABORT; + } | CURDATE optional_braces { $$= new (YYTHD->mem_root) Item_func_curdate_local(); + if ($$ == NULL) + MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | CURTIME optional_braces { $$= new (YYTHD->mem_root) Item_func_curtime_local(); + if ($$ == NULL) + MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | CURTIME '(' expr ')' { $$= new (YYTHD->mem_root) Item_func_curtime_local($3); + if ($$ == NULL) + MYSQL_YYABORT; Lex->safe_to_cache_query=0; } - | DATE_ADD_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')' %prec INTERVAL_SYM - { $$= new (YYTHD->mem_root) Item_date_add_interval($3,$6,$7,0); } - | DATE_SUB_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')' %prec INTERVAL_SYM - { $$= new (YYTHD->mem_root) Item_date_add_interval($3,$6,$7,1); } + | DATE_ADD_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')' + %prec INTERVAL_SYM + { + $$= new (YYTHD->mem_root) Item_date_add_interval($3,$6,$7,0); + if ($$ == NULL) + MYSQL_YYABORT; + } + | DATE_SUB_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')' + %prec INTERVAL_SYM + { + $$= new (YYTHD->mem_root) Item_date_add_interval($3,$6,$7,1); + if ($$ == NULL) + MYSQL_YYABORT; + } | EXTRACT_SYM '(' interval FROM expr ')' - { $$=new (YYTHD->mem_root) Item_extract( $3, $5); } + { + $$=new (YYTHD->mem_root) Item_extract( $3, $5); + if ($$ == NULL) + MYSQL_YYABORT; + } | GET_FORMAT '(' date_time_type ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_get_format($3, $5); } + { + $$= new (YYTHD->mem_root) Item_func_get_format($3, $5); + if ($$ == NULL) + MYSQL_YYABORT; + } | NOW_SYM optional_braces { $$= new (YYTHD->mem_root) Item_func_now_local(); + if ($$ == NULL) + MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | NOW_SYM '(' expr ')' { $$= new (YYTHD->mem_root) Item_func_now_local($3); + if ($$ == NULL) + MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | POSITION_SYM '(' bit_expr IN_SYM expr ')' - { $$ = new (YYTHD->mem_root) Item_func_locate($5,$3); } + { + $$ = new (YYTHD->mem_root) Item_func_locate($5,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | SUBDATE_SYM '(' expr ',' expr ')' { $$= new (YYTHD->mem_root) Item_date_add_interval($3, $5, INTERVAL_DAY, 1); + if ($$ == NULL) + MYSQL_YYABORT; } | SUBDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')' - { $$= new (YYTHD->mem_root) Item_date_add_interval($3, $6, $7, 1); } + { + $$= new (YYTHD->mem_root) Item_date_add_interval($3, $6, $7, 1); + if ($$ == NULL) + MYSQL_YYABORT; + } | SUBSTRING '(' expr ',' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_substr($3,$5,$7); } + { + $$= new (YYTHD->mem_root) Item_func_substr($3,$5,$7); + if ($$ == NULL) + MYSQL_YYABORT; + } | SUBSTRING '(' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_substr($3,$5); } + { + $$= new (YYTHD->mem_root) Item_func_substr($3,$5); + if ($$ == NULL) + MYSQL_YYABORT; + } | SUBSTRING '(' expr FROM expr FOR_SYM expr ')' - { $$= new (YYTHD->mem_root) Item_func_substr($3,$5,$7); } + { + $$= new (YYTHD->mem_root) Item_func_substr($3,$5,$7); + if ($$ == NULL) + MYSQL_YYABORT; + } | SUBSTRING '(' expr FROM expr ')' - { $$= new (YYTHD->mem_root) Item_func_substr($3,$5); } + { + $$= new (YYTHD->mem_root) Item_func_substr($3,$5); + if ($$ == NULL) + MYSQL_YYABORT; + } | SYSDATE optional_braces { if (global_system_variables.sysdate_is_now == 0) $$= new (YYTHD->mem_root) Item_func_sysdate_local(); else $$= new (YYTHD->mem_root) Item_func_now_local(); + if ($$ == NULL) + MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | SYSDATE '(' expr ')' @@ -7007,25 +7516,41 @@ function_call_nonkeyword: $$= new (YYTHD->mem_root) Item_func_sysdate_local($3); else $$= new (YYTHD->mem_root) Item_func_now_local($3); + if ($$ == NULL) + MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | TIMESTAMP_ADD '(' interval_time_stamp ',' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_date_add_interval($7,$5,$3,0); } + { + $$= new (YYTHD->mem_root) Item_date_add_interval($7,$5,$3,0); + if ($$ == NULL) + MYSQL_YYABORT; + } | TIMESTAMP_DIFF '(' interval_time_stamp ',' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_timestamp_diff($5,$7,$3); } + { + $$= new (YYTHD->mem_root) Item_func_timestamp_diff($5,$7,$3); + if ($$ == NULL) + MYSQL_YYABORT; + } | UTC_DATE_SYM optional_braces { $$= new (YYTHD->mem_root) Item_func_curdate_utc(); + if ($$ == NULL) + MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | UTC_TIME_SYM optional_braces { $$= new (YYTHD->mem_root) Item_func_curtime_utc(); + if ($$ == NULL) + MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | UTC_TIMESTAMP_SYM optional_braces { $$= new (YYTHD->mem_root) Item_func_now_utc(); + if ($$ == NULL) + MYSQL_YYABORT; Lex->safe_to_cache_query=0; } ; @@ -7037,26 +7562,60 @@ function_call_nonkeyword: */ function_call_conflict: ASCII_SYM '(' expr ')' - { $$= new (YYTHD->mem_root) Item_func_ascii($3); } + { + $$= new (YYTHD->mem_root) Item_func_ascii($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | CHARSET '(' expr ')' - { $$= new (YYTHD->mem_root) Item_func_charset($3); } + { + $$= new (YYTHD->mem_root) Item_func_charset($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | COALESCE '(' expr_list ')' - { $$= new (YYTHD->mem_root) Item_func_coalesce(* $3); } + { + $$= new (YYTHD->mem_root) Item_func_coalesce(* $3); + if ($$ == NULL) + MYSQL_YYABORT; + } | COLLATION_SYM '(' expr ')' - { $$= new (YYTHD->mem_root) Item_func_collation($3); } + { + $$= new (YYTHD->mem_root) Item_func_collation($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | DATABASE '(' ')' { $$= new (YYTHD->mem_root) Item_func_database(); + if ($$ == NULL) + MYSQL_YYABORT; Lex->safe_to_cache_query=0; } | IF '(' expr ',' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_if($3,$5,$7); } + { + $$= new (YYTHD->mem_root) Item_func_if($3,$5,$7); + if ($$ == NULL) + MYSQL_YYABORT; + } | MICROSECOND_SYM '(' expr ')' - { $$= new (YYTHD->mem_root) Item_func_microsecond($3); } + { + $$= new (YYTHD->mem_root) Item_func_microsecond($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | MOD_SYM '(' expr ',' expr ')' - { $$ = new (YYTHD->mem_root) Item_func_mod( $3, $5); } + { + $$ = new (YYTHD->mem_root) Item_func_mod($3, $5); + if ($$ == NULL) + MYSQL_YYABORT; + } | OLD_PASSWORD '(' expr ')' - { $$= new (YYTHD->mem_root) Item_func_old_password($3); } + { + $$= new (YYTHD->mem_root) Item_func_old_password($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | PASSWORD '(' expr ')' { THD *thd= YYTHD; @@ -7065,31 +7624,59 @@ function_call_conflict: i1= new (thd->mem_root) Item_func_old_password($3); else i1= new (thd->mem_root) Item_func_password($3); + if (i1 == NULL) + MYSQL_YYABORT; $$= i1; } | QUARTER_SYM '(' expr ')' - { $$ = new (YYTHD->mem_root) Item_func_quarter($3); } + { + $$ = new (YYTHD->mem_root) Item_func_quarter($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | REPEAT_SYM '(' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_repeat($3,$5); } + { + $$= new (YYTHD->mem_root) Item_func_repeat($3,$5); + if ($$ == NULL) + MYSQL_YYABORT; + } | REPLACE '(' expr ',' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_replace($3,$5,$7); } + { + $$= new (YYTHD->mem_root) Item_func_replace($3,$5,$7); + if ($$ == NULL) + MYSQL_YYABORT; + } | TRUNCATE_SYM '(' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_round($3,$5,1); } + { + $$= new (YYTHD->mem_root) Item_func_round($3,$5,1); + if ($$ == NULL) + MYSQL_YYABORT; + } | WEEK_SYM '(' expr ')' { THD *thd= YYTHD; Item *i1= new (thd->mem_root) Item_int((char*) "0", thd->variables.default_week_format, 1); - + if (i1 == NULL) + MYSQL_YYABORT; $$= new (thd->mem_root) Item_func_week($3, i1); + if ($$ == NULL) + MYSQL_YYABORT; } | WEEK_SYM '(' expr ',' expr ')' - { $$= new (YYTHD->mem_root) Item_func_week($3,$5); } + { + $$= new (YYTHD->mem_root) Item_func_week($3,$5); + if ($$ == NULL) + MYSQL_YYABORT; + } | geometry_function { #ifdef HAVE_SPATIAL $$= $1; + /* $1 may be NULL, GEOM_NEW not tested for out of memory */ + if ($$ == NULL) + MYSQL_YYABORT; #else my_error(ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, sym_group_geom.needed_define); @@ -7141,7 +7728,9 @@ geometry_function: Geometry::wkb_polygon)); } | POINT_SYM '(' expr ',' expr ')' - { $$= GEOM_NEW(YYTHD, Item_func_point($3,$5)); } + { + $$= GEOM_NEW(YYTHD, Item_func_point($3,$5)); + } | POLYGON '(' expr_list ')' { $$= GEOM_NEW(YYTHD, @@ -7286,6 +7875,8 @@ udf_expr_list: udf_expr { $$= new (YYTHD->mem_root) List<Item>; + if ($$ == NULL) + MYSQL_YYABORT; $$->push_back($1); } | udf_expr_list ',' udf_expr @@ -7317,50 +7908,125 @@ udf_expr: sum_expr: AVG_SYM '(' in_sum_expr ')' - { $$=new Item_sum_avg($3); } + { + $$= new (YYTHD->mem_root) Item_sum_avg($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | AVG_SYM '(' DISTINCT in_sum_expr ')' - { $$=new Item_sum_avg_distinct($4); } + { + $$= new (YYTHD->mem_root) Item_sum_avg_distinct($4); + if ($$ == NULL) + MYSQL_YYABORT; + } | BIT_AND '(' in_sum_expr ')' - { $$=new Item_sum_and($3); } + { + $$= new (YYTHD->mem_root) Item_sum_and($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | BIT_OR '(' in_sum_expr ')' - { $$=new Item_sum_or($3); } + { + $$= new (YYTHD->mem_root) Item_sum_or($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | BIT_XOR '(' in_sum_expr ')' - { $$=new Item_sum_xor($3); } + { + $$= new (YYTHD->mem_root) Item_sum_xor($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | COUNT_SYM '(' opt_all '*' ')' - { $$=new Item_sum_count(new Item_int((int32) 0L,1)); } + { + Item *item= new (YYTHD->mem_root) Item_int((int32) 0L,1); + if (item == NULL) + MYSQL_YYABORT; + $$= new (YYTHD->mem_root) Item_sum_count(item); + if ($$ == NULL) + MYSQL_YYABORT; + } | COUNT_SYM '(' in_sum_expr ')' - { $$=new Item_sum_count($3); } + { + $$= new (YYTHD->mem_root) Item_sum_count($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | COUNT_SYM '(' DISTINCT { Select->in_sum_expr++; } expr_list { Select->in_sum_expr--; } ')' - { $$=new Item_sum_count_distinct(* $5); } + { + $$= new (YYTHD->mem_root) Item_sum_count_distinct(* $5); + if ($$ == NULL) + MYSQL_YYABORT; + } | MIN_SYM '(' in_sum_expr ')' - { $$=new Item_sum_min($3); } + { + $$= new (YYTHD->mem_root) Item_sum_min($3); + if ($$ == NULL) + MYSQL_YYABORT; + } /* According to ANSI SQL, DISTINCT is allowed and has no sense inside MIN and MAX grouping functions; so MIN|MAX(DISTINCT ...) is processed like an ordinary MIN | MAX() */ | MIN_SYM '(' DISTINCT in_sum_expr ')' - { $$=new Item_sum_min($4); } + { + $$= new (YYTHD->mem_root) Item_sum_min($4); + if ($$ == NULL) + MYSQL_YYABORT; + } | MAX_SYM '(' in_sum_expr ')' - { $$=new Item_sum_max($3); } + { + $$= new (YYTHD->mem_root) Item_sum_max($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | MAX_SYM '(' DISTINCT in_sum_expr ')' - { $$=new Item_sum_max($4); } + { + $$= new (YYTHD->mem_root) Item_sum_max($4); + if ($$ == NULL) + MYSQL_YYABORT; + } | STD_SYM '(' in_sum_expr ')' - { $$=new Item_sum_std($3, 0); } + { + $$= new (YYTHD->mem_root) Item_sum_std($3, 0); + if ($$ == NULL) + MYSQL_YYABORT; + } | VARIANCE_SYM '(' in_sum_expr ')' - { $$=new Item_sum_variance($3, 0); } + { + $$= new (YYTHD->mem_root) Item_sum_variance($3, 0); + if ($$ == NULL) + MYSQL_YYABORT; + } | STDDEV_SAMP_SYM '(' in_sum_expr ')' - { $$=new Item_sum_std($3, 1); } + { + $$= new (YYTHD->mem_root) Item_sum_std($3, 1); + if ($$ == NULL) + MYSQL_YYABORT; + } | VAR_SAMP_SYM '(' in_sum_expr ')' - { $$=new Item_sum_variance($3, 1); } + { + $$= new (YYTHD->mem_root) Item_sum_variance($3, 1); + if ($$ == NULL) + MYSQL_YYABORT; + } | SUM_SYM '(' in_sum_expr ')' - { $$=new Item_sum_sum($3); } + { + $$= new (YYTHD->mem_root) Item_sum_sum($3); + if ($$ == NULL) + MYSQL_YYABORT; + } | SUM_SYM '(' DISTINCT in_sum_expr ')' - { $$=new Item_sum_sum_distinct($4); } + { + $$= new (YYTHD->mem_root) Item_sum_sum_distinct($4); + if ($$ == NULL) + MYSQL_YYABORT; + } | GROUP_CONCAT_SYM '(' opt_distinct { Select->in_sum_expr++; } expr_list opt_gorder_clause @@ -7369,8 +8035,11 @@ sum_expr: { SELECT_LEX *sel= Select; sel->in_sum_expr--; - $$=new Item_func_group_concat(Lex->current_context(), $3, $5, - sel->gorder_list, $7); + $$= new (YYTHD->mem_root) + Item_func_group_concat(Lex->current_context(), $3, $5, + sel->gorder_list, $7); + if ($$ == NULL) + MYSQL_YYABORT; $5->empty(); } ; @@ -7393,13 +8062,17 @@ variable: variable_aux: ident_or_text SET_VAR expr { - $$= new Item_func_set_user_var($1, $3); + $$= new (YYTHD->mem_root) Item_func_set_user_var($1, $3); + if ($$ == NULL) + MYSQL_YYABORT; LEX *lex= Lex; lex->uncacheable(UNCACHEABLE_RAND); } | ident_or_text { - $$= new Item_func_get_user_var($1); + $$= new (YYTHD->mem_root) Item_func_get_user_var($1); + if ($$ == NULL) + MYSQL_YYABORT; LEX *lex= Lex; lex->uncacheable(UNCACHEABLE_RAND); } @@ -7425,9 +8098,11 @@ opt_distinct: opt_gconcat_separator: /* empty */ - { - $$= new (YYTHD->mem_root) String(",", 1, &my_charset_latin1); - } + { + $$= new (YYTHD->mem_root) String(",", 1, &my_charset_latin1); + if ($$ == NULL) + MYSQL_YYABORT; + } | SEPARATOR_SYM text_string { $$ = $2; } ; @@ -7442,6 +8117,8 @@ opt_gorder_clause: select->gorder_list= (SQL_LIST*) sql_memdup((char*) &select->order_list, sizeof(st_sql_list)); + if (select->gorder_list == NULL) + MYSQL_YYABORT; select->order_list.empty(); } ; @@ -7464,11 +8141,11 @@ in_sum_expr: ; cast_type: - BINARY opt_len + BINARY opt_field_length { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; Lex->dec= 0; } - | CHAR_SYM opt_len opt_binary + | CHAR_SYM opt_field_length opt_binary { $$=ITEM_CAST_CHAR; Lex->dec= 0; } - | NCHAR_SYM opt_len + | NCHAR_SYM opt_field_length { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; } | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } @@ -7497,6 +8174,8 @@ expr_list: expr { $$= new (YYTHD->mem_root) List<Item>; + if ($$ == NULL) + MYSQL_YYABORT; $$->push_back($1); } | expr_list ',' expr @@ -7515,6 +8194,8 @@ ident_list: simple_ident { $$= new (YYTHD->mem_root) List<Item>; + if ($$ == NULL) + MYSQL_YYABORT; $$->push_back($1); } | ident_list ',' simple_ident @@ -7538,6 +8219,8 @@ when_list: WHEN_SYM expr THEN_SYM expr { $$= new List<Item>; + if ($$ == NULL) + MYSQL_YYABORT; $$->push_back($2); $$->push_back($4); } @@ -7789,8 +8472,11 @@ table_factor: SELECT_LEX *sel= lex->current_select; SELECT_LEX_UNIT *unit= sel->master_unit(); lex->current_select= sel= unit->outer_select(); + Table_ident *ti= new Table_ident(unit); + if (ti == NULL) + MYSQL_YYABORT; if (!($$= sel->add_table_to_list(lex->thd, - new Table_ident(unit), $6, 0, + ti, $6, 0, TL_READ))) MYSQL_YYABORT; @@ -7957,15 +8643,21 @@ using_list: { if (!($$= new List<String>)) MYSQL_YYABORT; - $$->push_back(new (YYTHD->mem_root) - String((const char *) $1.str, $1.length, - system_charset_info)); + String *s= new (YYTHD->mem_root) String((const char *) $1.str, + $1.length, + system_charset_info); + if (s == NULL) + MYSQL_YYABORT; + $$->push_back(s); } | using_list ',' ident { - $1->push_back(new (YYTHD->mem_root) - String((const char *) $3.str, $3.length, - system_charset_info)); + String *s= new (YYTHD->mem_root) String((const char *) $3.str, + $3.length, + system_charset_info); + if (s == NULL) + MYSQL_YYABORT; + $1->push_back(s); $$= $1; } ; @@ -8033,7 +8725,11 @@ table_alias: opt_table_alias: /* empty */ { $$=0; } | table_alias ident - { $$= (LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING)); } + { + $$= (LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING)); + if ($$ == NULL) + MYSQL_YYABORT; + } ; opt_all: @@ -8081,10 +8777,13 @@ opt_escape: } | /* empty */ { + THD *thd= YYTHD; Lex->escape_used= FALSE; - $$= ((YYTHD->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ? - new Item_string("", 0, &my_charset_latin1) : - new Item_string("\\", 1, &my_charset_latin1)); + $$= ((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ? + new (thd->mem_root) Item_string("", 0, &my_charset_latin1) : + new (thd->mem_root) Item_string("\\", 1, &my_charset_latin1)); + if ($$ == NULL) + MYSQL_YYABORT; } ; @@ -8261,9 +8960,24 @@ limit_option: { ((Item_param *) $1)->limit_clause_param= TRUE; } - | ULONGLONG_NUM { $$= new Item_uint($1.str, $1.length); } - | LONG_NUM { $$= new Item_uint($1.str, $1.length); } - | NUM { $$= new Item_uint($1.str, $1.length); } + | ULONGLONG_NUM + { + $$= new (YYTHD->mem_root) Item_uint($1.str, $1.length); + if ($$ == NULL) + MYSQL_YYABORT; + } + | LONG_NUM + { + $$= new (YYTHD->mem_root) Item_uint($1.str, $1.length); + if ($$ == NULL) + MYSQL_YYABORT; + } + | NUM + { + $$= new (YYTHD->mem_root) Item_uint($1.str, $1.length); + if ($$ == NULL) + MYSQL_YYABORT; + } ; delete_limit_clause: @@ -8347,10 +9061,12 @@ procedure_clause: lex->proc_list.elements=0; lex->proc_list.first=0; lex->proc_list.next= (uchar**) &lex->proc_list.first; - if (add_proc_to_list(lex->thd, new Item_field(&lex-> - current_select-> - context, - NULL,NULL,$2.str))) + Item_field *item= new (YYTHD->mem_root) + Item_field(&lex->current_select->context, + NULL, NULL, $2.str); + if (item == NULL) + MYSQL_YYABORT; + if (add_proc_to_list(lex->thd, item)) MYSQL_YYABORT; Lex->uncacheable(UNCACHEABLE_SIDEEFFECT); } @@ -8382,7 +9098,8 @@ procedure_item: select_var_list_init: { LEX *lex=Lex; - if (!lex->describe && (!(lex->result= new select_dumpvar()))) + if (!lex->describe && + (!(lex->result= new select_dumpvar(lex->nest_level)))) MYSQL_YYABORT; } select_var_list @@ -8399,13 +9116,20 @@ select_var_ident: { LEX *lex=Lex; if (lex->result) - ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($2,0,0,(enum_field_types)0)); + { + my_var *var= new my_var($2,0,0,(enum_field_types)0); + if (var == NULL) + MYSQL_YYABORT; + ((select_dumpvar *)lex->result)->var_list.push_back(var); + } else + { /* The parser won't create select_result instance only if it's an EXPLAIN. */ DBUG_ASSERT(lex->describe); + } } | ident_or_text { @@ -8419,12 +9143,12 @@ select_var_ident: } if (lex->result) { - my_var *var; - ((select_dumpvar *)lex->result)-> - var_list.push_back(var= new my_var($1,1,t->offset,t->type)); + my_var *var= new my_var($1,1,t->offset,t->type); + if (var == NULL) + MYSQL_YYABORT; + ((select_dumpvar *)lex->result)->var_list.push_back(var); #ifndef DBUG_OFF - if (var) - var->sp= lex->sphead; + var->sp= lex->sphead; #endif } else @@ -8456,7 +9180,7 @@ into_destination: LEX *lex= Lex; lex->uncacheable(UNCACHEABLE_SIDEEFFECT); if (!(lex->exchange= new sql_exchange($2.str, 0)) || - !(lex->result= new select_export(lex->exchange))) + !(lex->result= new select_export(lex->exchange, lex->nest_level))) MYSQL_YYABORT; } opt_field_term opt_line_term @@ -8468,7 +9192,7 @@ into_destination: lex->uncacheable(UNCACHEABLE_SIDEEFFECT); if (!(lex->exchange= new sql_exchange($2.str,1))) MYSQL_YYABORT; - if (!(lex->result= new select_dump(lex->exchange))) + if (!(lex->result= new select_dump(lex->exchange, lex->nest_level))) MYSQL_YYABORT; } } @@ -8510,11 +9234,13 @@ drop: | DROP INDEX_SYM ident ON table_ident {} { LEX *lex=Lex; + Alter_drop *ad= new Alter_drop(Alter_drop::KEY, $3.str); + if (ad == NULL) + MYSQL_YYABORT; lex->sql_command= SQLCOM_DROP_INDEX; lex->alter_info.reset(); lex->alter_info.flags= ALTER_DROP_INDEX; - lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY, - $3.str)); + lex->alter_info.drop_list.push_back(ad); if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL, TL_OPTION_UPDATING)) MYSQL_YYABORT; @@ -8539,6 +9265,8 @@ drop: lex->sql_command = SQLCOM_DROP_FUNCTION; lex->drop_if_exists= $3; spname= new sp_name($4, $6, true); + if (spname == NULL) + MYSQL_YYABORT; spname->init_qname(thd); lex->spname= spname; } @@ -8558,6 +9286,8 @@ drop: lex->sql_command = SQLCOM_DROP_FUNCTION; lex->drop_if_exists= $3; spname= new sp_name(db, $4, false); + if (spname == NULL) + MYSQL_YYABORT; spname->init_qname(thd); lex->spname= spname; } @@ -8825,7 +9555,12 @@ values: expr_or_default: expr { $$= $1;} - | DEFAULT {$$= new Item_default_value(Lex->current_context()); } + | DEFAULT + { + $$= new (YYTHD->mem_root) Item_default_value(Lex->current_context()); + if ($$ == NULL) + MYSQL_YYABORT; + } ; opt_insert_update: @@ -8949,7 +9684,11 @@ table_wild_list: table_wild_one: ident opt_wild opt_table_alias { - if (!Select->add_table_to_list(YYTHD, new Table_ident($1), + Table_ident *ti= new Table_ident($1); + if (ti == NULL) + MYSQL_YYABORT; + if (!Select->add_table_to_list(YYTHD, + ti, $3, TL_OPTION_UPDATING | TL_OPTION_ALIAS, Lex->lock_option)) @@ -8957,8 +9696,11 @@ table_wild_one: } | ident '.' ident opt_wild opt_table_alias { + Table_ident *ti= new Table_ident(YYTHD, $1, $3, 0); + if (ti == NULL) + MYSQL_YYABORT; if (!Select->add_table_to_list(YYTHD, - new Table_ident(YYTHD, $1, $3, 0), + ti, $5, TL_OPTION_UPDATING | TL_OPTION_ALIAS, Lex->lock_option)) @@ -9363,8 +10105,6 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_STATUS_PROC; - if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ)) - MYSQL_YYABORT; if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES)) MYSQL_YYABORT; } @@ -9372,8 +10112,6 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_STATUS_FUNC; - if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ)) - MYSQL_YYABORT; if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES)) MYSQL_YYABORT; } @@ -9454,6 +10192,8 @@ wild_and_where: { Lex->wild= new (YYTHD->mem_root) String($2.str, $2.length, system_charset_info); + if (Lex->wild == NULL) + MYSQL_YYABORT; } | WHERE expr { @@ -9506,6 +10246,8 @@ opt_describe_column: Lex->wild= new (YYTHD->mem_root) String((const char*) $1.str, $1.length, system_charset_info); + if (Lex->wild == NULL) + MYSQL_YYABORT; } ; @@ -9646,7 +10388,7 @@ load: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; if (lex->sphead) { @@ -9687,10 +10429,7 @@ load_data: } opt_duplicate INTO { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - lex->fname_end= lip->get_ptr(); + Lex->fname_end= YYLIP->get_ptr(); } TABLE_SYM table_ident { @@ -9827,7 +10566,11 @@ fields_or_vars: field_or_var: simple_ident_nospvar {$$= $1;} | '@' ident_or_text - { $$= new Item_user_var_as_out_param($2); } + { + $$= new (YYTHD->mem_root) Item_user_var_as_out_param($2); + if ($$ == NULL) + MYSQL_YYABORT; + } ; opt_load_data_set_spec: @@ -9852,21 +10595,34 @@ text_literal: my_charset_is_ascii_based(cs_con))) tmp= $1; else - thd->convert_string(&tmp, cs_con, $1.str, $1.length, cs_cli); - $$= new Item_string(tmp.str, tmp.length, cs_con, - DERIVATION_COERCIBLE, repertoire); + { + if (thd->convert_string(&tmp, cs_con, $1.str, $1.length, cs_cli)) + MYSQL_YYABORT; + } + $$= new (thd->mem_root) Item_string(tmp.str, tmp.length, cs_con, + DERIVATION_COERCIBLE, + repertoire); + if ($$ == NULL) + MYSQL_YYABORT; } | NCHAR_STRING { uint repertoire= Lex->text_string_is_7bit ? MY_REPERTOIRE_ASCII : MY_REPERTOIRE_UNICODE30; DBUG_ASSERT(my_charset_is_ascii_based(national_charset_info)); - $$= new Item_string($1.str, $1.length, national_charset_info, - DERIVATION_COERCIBLE, repertoire); + $$= new (YYTHD->mem_root) Item_string($1.str, $1.length, + national_charset_info, + DERIVATION_COERCIBLE, + repertoire); + if ($$ == NULL) + MYSQL_YYABORT; } | UNDERSCORE_CHARSET TEXT_STRING { - Item_string *str= new Item_string($2.str, $2.length, $1); + Item_string *str= new (YYTHD->mem_root) Item_string($2.str, + $2.length, $1); + if (str == NULL) + MYSQL_YYABORT; str->set_repertoire_from_value(); str->set_cs_specified(TRUE); @@ -9896,27 +10652,32 @@ text_string: $$= new (YYTHD->mem_root) String($1.str, $1.length, YYTHD->variables.collation_connection); + if ($$ == NULL) + MYSQL_YYABORT; } | HEX_NUM { - Item *tmp= new Item_hex_string($1.str, $1.length); + Item *tmp= new (YYTHD->mem_root) Item_hex_string($1.str, $1.length); + if (tmp == NULL) + MYSQL_YYABORT; /* it is OK only emulate fix_fields, because we need only value of constant */ - $$= tmp ? - tmp->quick_fix_field(), tmp->val_str((String*) 0) : - (String*) 0; + tmp->quick_fix_field(); + $$= tmp->val_str((String*) 0); } | BIN_NUM { - Item *tmp= new Item_bin_string($1.str, $1.length); + Item *tmp= new (YYTHD->mem_root) Item_bin_string($1.str, $1.length); + if (tmp == NULL) + MYSQL_YYABORT; /* it is OK only emulate fix_fields, because we need only value of constant */ - $$= tmp ? tmp->quick_fix_field(), tmp->val_str((String*) 0) : - (String*) 0; + tmp->quick_fix_field(); + $$= tmp->val_str((String*) 0); } ; @@ -9925,14 +10686,14 @@ param_marker: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; Item_param *item; if (! lex->parsing_options.allows_variable) { my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); MYSQL_YYABORT; } - item= new Item_param((uint) (lip->get_tok_start() - thd->query)); + item= new (thd->mem_root) Item_param((uint) (lip->get_tok_start() - thd->query)); if (!($$= item) || lex->param_list.push_back(item)) { my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); @@ -9956,29 +10717,53 @@ literal: | NUM_literal { $$ = $1; } | NULL_SYM { - $$ = new Item_null(); - YYTHD->m_lip->next_state=MY_LEX_OPERATOR_OR_IDENT; + $$ = new (YYTHD->mem_root) Item_null(); + if ($$ == NULL) + MYSQL_YYABORT; + YYLIP->next_state= MY_LEX_OPERATOR_OR_IDENT; + } + | FALSE_SYM + { + $$= new (YYTHD->mem_root) Item_int((char*) "FALSE",0,1); + if ($$ == NULL) + MYSQL_YYABORT; + } + | TRUE_SYM + { + $$= new (YYTHD->mem_root) Item_int((char*) "TRUE",1,1); + if ($$ == NULL) + MYSQL_YYABORT; + } + | HEX_NUM + { + $$ = new (YYTHD->mem_root) Item_hex_string($1.str, $1.length); + if ($$ == NULL) + MYSQL_YYABORT; + } + | BIN_NUM + { + $$= new (YYTHD->mem_root) Item_bin_string($1.str, $1.length); + if ($$ == NULL) + MYSQL_YYABORT; } - | FALSE_SYM { $$= new Item_int((char*) "FALSE",0,1); } - | TRUE_SYM { $$= new Item_int((char*) "TRUE",1,1); } - | HEX_NUM { $$ = new Item_hex_string($1.str, $1.length);} - | BIN_NUM { $$= new Item_bin_string($1.str, $1.length); } | UNDERSCORE_CHARSET HEX_NUM { - Item *tmp= new Item_hex_string($2.str, $2.length); + Item *tmp= new (YYTHD->mem_root) Item_hex_string($2.str, $2.length); + if (tmp == NULL) + MYSQL_YYABORT; /* it is OK only emulate fix_fieds, because we need only value of constant */ - String *str= tmp ? - tmp->quick_fix_field(), tmp->val_str((String*) 0) : - (String*) 0; - - Item_string *item_str= - new Item_string(NULL, /* name will be set in select_item */ - str ? str->ptr() : "", - str ? str->length() : 0, - $1); + tmp->quick_fix_field(); + String *str= tmp->val_str((String*) 0); + + Item_string *item_str; + item_str= new (YYTHD->mem_root) + Item_string(NULL, /* name will be set in select_item */ + str ? str->ptr() : "", + str ? str->length() : 0, + $1); if (!item_str || !item_str->check_well_formed_result(&item_str->str_value, TRUE)) { @@ -9992,20 +10777,22 @@ literal: } | UNDERSCORE_CHARSET BIN_NUM { - Item *tmp= new Item_bin_string($2.str, $2.length); + Item *tmp= new (YYTHD->mem_root) Item_bin_string($2.str, $2.length); + if (tmp == NULL) + MYSQL_YYABORT; /* it is OK only emulate fix_fieds, because we need only value of constant */ - String *str= tmp ? - tmp->quick_fix_field(), tmp->val_str((String*) 0) : - (String*) 0; - - Item_string *item_str= - new Item_string(NULL, /* name will be set in select_item */ - str ? str->ptr() : "", - str ? str->length() : 0, - $1); + tmp->quick_fix_field(); + String *str= tmp->val_str((String*) 0); + + Item_string *item_str; + item_str= new (YYTHD->mem_root) + Item_string(NULL, /* name will be set in select_item */ + str ? str->ptr() : "", + str ? str->length() : 0, + $1); if (!item_str || !item_str->check_well_formed_result(&item_str->str_value, TRUE)) { @@ -10025,27 +10812,42 @@ NUM_literal: NUM { int error; - $$ = new Item_int($1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); + $$= new (YYTHD->mem_root) + Item_int($1.str, + (longlong) my_strtoll10($1.str, NULL, &error), + $1.length); + if ($$ == NULL) + MYSQL_YYABORT; } | LONG_NUM { int error; - $$ = new Item_int($1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); + $$= new (YYTHD->mem_root) + Item_int($1.str, + (longlong) my_strtoll10($1.str, NULL, &error), + $1.length); + if ($$ == NULL) + MYSQL_YYABORT; } | ULONGLONG_NUM - { $$ = new Item_uint($1.str, $1.length); } + { + $$= new (YYTHD->mem_root) Item_uint($1.str, $1.length); + if ($$ == NULL) + MYSQL_YYABORT; + } | DECIMAL_NUM { - $$= new Item_decimal($1.str, $1.length, YYTHD->charset()); - if (YYTHD->is_error()) + $$= new (YYTHD->mem_root) Item_decimal($1.str, $1.length, + YYTHD->charset()); + if (($$ == NULL) || (YYTHD->is_error())) { MYSQL_YYABORT; } } | FLOAT_NUM { - $$ = new Item_float($1.str, $1.length); - if (YYTHD->is_error()) + $$= new (YYTHD->mem_root) Item_float($1.str, $1.length); + if (($$ == NULL) || (YYTHD->is_error())) { MYSQL_YYABORT; } @@ -10065,15 +10867,23 @@ table_wild: ident '.' '*' { SELECT_LEX *sel= Select; - $$ = new Item_field(Lex->current_context(), NullS, $1.str, "*"); + $$= new (YYTHD->mem_root) Item_field(Lex->current_context(), + NullS, $1.str, "*"); + if ($$ == NULL) + MYSQL_YYABORT; sel->with_wild++; } | ident '.' ident '.' '*' { + THD *thd= YYTHD; SELECT_LEX *sel= Select; - $$ = new Item_field(Lex->current_context(), (YYTHD->client_capabilities & - CLIENT_NO_SCHEMA ? NullS : $1.str), - $3.str,"*"); + const char* schema= thd->client_capabilities & CLIENT_NO_SCHEMA ? + NullS : $1.str; + $$= new (thd->mem_root) Item_field(Lex->current_context(), + schema, + $3.str,"*"); + if ($$ == NULL) + MYSQL_YYABORT; sel->with_wild++; } ; @@ -10087,7 +10897,7 @@ simple_ident: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; sp_variable_t *spv; sp_pcontext *spc = lex->spcont; if (spc && (spv = spc->find_variable(&$1))) @@ -10100,24 +10910,34 @@ simple_ident: } Item_splocal *splocal; - splocal= new Item_splocal($1, spv->offset, spv->type, - lip->get_tok_start_prev() - - lex->sphead->m_tmp_query, - lip->get_tok_end() - lip->get_tok_start_prev()); + splocal= new (thd->mem_root) + Item_splocal($1, spv->offset, spv->type, + lip->get_tok_start_prev() - lex->sphead->m_tmp_query, + lip->get_tok_end() - lip->get_tok_start_prev()); + if (splocal == NULL) + MYSQL_YYABORT; #ifndef DBUG_OFF - if (splocal) - splocal->m_sp= lex->sphead; + splocal->m_sp= lex->sphead; #endif - $$ = (Item*) splocal; + $$= splocal; lex->safe_to_cache_query=0; } else { SELECT_LEX *sel=Select; - $$= (sel->parsing_place != IN_HAVING || - sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(Lex->current_context(), NullS, NullS, $1.str) : - (Item*) new Item_ref(Lex->current_context(), NullS, NullS, $1.str); + if ((sel->parsing_place != IN_HAVING) || + (sel->get_in_sum_expr() > 0)) + { + $$= new (thd->mem_root) Item_field(Lex->current_context(), + NullS, NullS, $1.str); + } + else + { + $$= new (thd->mem_root) Item_ref(Lex->current_context(), + NullS, NullS, $1.str); + } + if ($$ == NULL) + MYSQL_YYABORT; } } | simple_ident_q { $$= $1; } @@ -10126,11 +10946,21 @@ simple_ident: simple_ident_nospvar: ident { + THD *thd= YYTHD; SELECT_LEX *sel=Select; - $$= (sel->parsing_place != IN_HAVING || - sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(Lex->current_context(), NullS, NullS, $1.str) : - (Item*) new Item_ref(Lex->current_context(), NullS, NullS, $1.str); + if ((sel->parsing_place != IN_HAVING) || + (sel->get_in_sum_expr() > 0)) + { + $$= new (thd->mem_root) Item_field(Lex->current_context(), + NullS, NullS, $1.str); + } + else + { + $$= new (thd->mem_root) Item_ref(Lex->current_context(), + NullS, NullS, $1.str); + } + if ($$ == NULL) + MYSQL_YYABORT; } | simple_ident_q { $$= $1; } ; @@ -10172,13 +11002,15 @@ simple_ident_q: lex->trg_chistics.event == TRG_EVENT_UPDATE)); const bool read_only= !(new_row && lex->trg_chistics.action_time == TRG_ACTION_BEFORE); - if (!(trg_fld= new Item_trigger_field(Lex->current_context(), - new_row ? - Item_trigger_field::NEW_ROW: - Item_trigger_field::OLD_ROW, - $3.str, - SELECT_ACL, - read_only))) + trg_fld= new (thd->mem_root) + Item_trigger_field(Lex->current_context(), + new_row ? + Item_trigger_field::NEW_ROW: + Item_trigger_field::OLD_ROW, + $3.str, + SELECT_ACL, + read_only); + if (trg_fld == NULL) MYSQL_YYABORT; /* @@ -10188,7 +11020,7 @@ simple_ident_q: lex->trg_table_fields.link_in_list((uchar*) trg_fld, (uchar**) &trg_fld->next_trg_field); - $$= (Item *)trg_fld; + $$= trg_fld; } else { @@ -10198,10 +11030,19 @@ simple_ident_q: my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), $1.str, thd->where); } - $$= (sel->parsing_place != IN_HAVING || - sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(Lex->current_context(), NullS, $1.str, $3.str) : - (Item*) new Item_ref(Lex->current_context(), NullS, $1.str, $3.str); + if ((sel->parsing_place != IN_HAVING) || + (sel->get_in_sum_expr() > 0)) + { + $$= new (thd->mem_root) Item_field(Lex->current_context(), + NullS, $1.str, $3.str); + } + else + { + $$= new (thd->mem_root) Item_ref(Lex->current_context(), + NullS, $1.str, $3.str); + } + if ($$ == NULL) + MYSQL_YYABORT; } } | '.' ident '.' ident @@ -10214,31 +11055,48 @@ simple_ident_q: my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), $2.str, thd->where); } - $$= (sel->parsing_place != IN_HAVING || - sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(Lex->current_context(), NullS, $2.str, $4.str) : - (Item*) new Item_ref(Lex->current_context(), NullS, $2.str, $4.str); + if ((sel->parsing_place != IN_HAVING) || + (sel->get_in_sum_expr() > 0)) + { + $$= new (thd->mem_root) Item_field(Lex->current_context(), + NullS, $2.str, $4.str); + + } + else + { + $$= new (thd->mem_root) Item_ref(Lex->current_context(), + NullS, $2.str, $4.str); + } + if ($$ == NULL) + MYSQL_YYABORT; } | ident '.' ident '.' ident { THD *thd= YYTHD; LEX *lex= thd->lex; SELECT_LEX *sel= lex->current_select; + const char* schema= (thd->client_capabilities & CLIENT_NO_SCHEMA ? + NullS : $1.str); if (sel->no_table_names_allowed) { my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), $3.str, thd->where); } - $$= (sel->parsing_place != IN_HAVING || - sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(Lex->current_context(), - (YYTHD->client_capabilities & - CLIENT_NO_SCHEMA ? NullS : $1.str), - $3.str, $5.str) : - (Item*) new Item_ref(Lex->current_context(), - (YYTHD->client_capabilities & - CLIENT_NO_SCHEMA ? NullS : $1.str), - $3.str, $5.str); + if ((sel->parsing_place != IN_HAVING) || + (sel->get_in_sum_expr() > 0)) + { + $$= new (thd->mem_root) Item_field(Lex->current_context(), + schema, + $3.str, $5.str); + } + else + { + $$= new (thd->mem_root) Item_ref(Lex->current_context(), + schema, + $3.str, $5.str); + } + if ($$ == NULL) + MYSQL_YYABORT; } ; @@ -10274,16 +11132,34 @@ field_ident: ; table_ident: - ident { $$=new Table_ident($1); } - | ident '.' ident { $$=new Table_ident(YYTHD, $1,$3,0);} - | '.' ident { $$=new Table_ident($2);} /* For Delphi */ + ident + { + $$= new Table_ident($1); + if ($$ == NULL) + MYSQL_YYABORT; + } + | ident '.' ident + { + $$= new Table_ident(YYTHD, $1,$3,0); + if ($$ == NULL) + MYSQL_YYABORT; + } + | '.' ident + { + /* For Delphi */ + $$= new Table_ident($2); + if ($$ == NULL) + MYSQL_YYABORT; + } ; table_ident_nodb: ident { LEX_STRING db={(char*) any_db,3}; - $$=new Table_ident(YYTHD, db,$1,0); + $$= new Table_ident(YYTHD, db,$1,0); + if ($$ == NULL) + MYSQL_YYABORT; } ; @@ -10309,8 +11185,11 @@ IDENT_sys: $$= $1; } else - thd->convert_string(&$$, system_charset_info, - $1.str, $1.length, thd->charset()); + { + if (thd->convert_string(&$$, system_charset_info, + $1.str, $1.length, thd->charset())) + MYSQL_YYABORT; + } } ; @@ -10322,8 +11201,11 @@ TEXT_STRING_sys: if (thd->charset_is_system_charset) $$= $1; else - thd->convert_string(&$$, system_charset_info, - $1.str, $1.length, thd->charset()); + { + if (thd->convert_string(&$$, system_charset_info, + $1.str, $1.length, thd->charset())) + MYSQL_YYABORT; + } } ; @@ -10335,8 +11217,11 @@ TEXT_STRING_literal: if (thd->charset_is_collation_connection) $$= $1; else - thd->convert_string(&$$, thd->variables.collation_connection, - $1.str, $1.length, thd->charset()); + { + if (thd->convert_string(&$$, thd->variables.collation_connection, + $1.str, $1.length, thd->charset())) + MYSQL_YYABORT; + } } ; @@ -10348,8 +11233,12 @@ TEXT_STRING_filesystem: if (thd->charset_is_character_set_filesystem) $$= $1; else - thd->convert_string(&$$, thd->variables.character_set_filesystem, - $1.str, $1.length, thd->charset()); + { + if (thd->convert_string(&$$, + thd->variables.character_set_filesystem, + $1.str, $1.length, thd->charset())) + MYSQL_YYABORT; + } } ; @@ -10359,6 +11248,8 @@ ident: { THD *thd= YYTHD; $$.str= thd->strmake($1.str, $1.length); + if ($$.str == NULL) + MYSQL_YYABORT; $$.length= $1.length; } ; @@ -10369,6 +11260,8 @@ label_ident: { THD *thd= YYTHD; $$.str= thd->strmake($1.str, $1.length); + if ($$.str == NULL) + MYSQL_YYABORT; $$.length= $1.length; } ; @@ -10777,7 +11670,7 @@ option_type_value: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; if (lex->sphead) { @@ -10808,7 +11701,7 @@ option_type_value: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; if (lex->sphead) { @@ -10887,6 +11780,7 @@ ext_option_value: sys_option_value: option_type internal_variable_name equal set_expr_or_default { + THD *thd= YYTHD; LEX *lex=Lex; if ($2.var == trg_new_row_fake_var) @@ -10912,15 +11806,21 @@ sys_option_value: DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE && (lex->trg_chistics.event == TRG_EVENT_INSERT || lex->trg_chistics.event == TRG_EVENT_UPDATE)); - if (!(trg_fld= new Item_trigger_field(Lex->current_context(), - Item_trigger_field::NEW_ROW, - $2.base_name.str, - UPDATE_ACL, FALSE)) || - !(sp_fld= new sp_instr_set_trigger_field(lex->sphead-> - instructions(), - lex->spcont, - trg_fld, - it, lex))) + + trg_fld= new (thd->mem_root) + Item_trigger_field(Lex->current_context(), + Item_trigger_field::NEW_ROW, + $2.base_name.str, + UPDATE_ACL, FALSE); + if (trg_fld == NULL) + MYSQL_YYABORT; + + sp_fld= new sp_instr_set_trigger_field(lex->sphead-> + instructions(), + lex->spcont, + trg_fld, + it, lex); + if (sp_fld == NULL) MYSQL_YYABORT; /* @@ -10937,8 +11837,11 @@ sys_option_value: { /* System variable */ if ($1) lex->option_type= $1; - lex->var_list.push_back(new set_var(lex->option_type, $2.var, - &$2.base_name, $4)); + set_var *var= new set_var(lex->option_type, $2.var, + &$2.base_name, $4); + if (var == NULL) + MYSQL_YYABORT; + lex->var_list.push_back(var); } else { @@ -10960,39 +11863,69 @@ sys_option_value: else if (spv->dflt) it= spv->dflt; else - it= new Item_null(); + { + it= new (thd->mem_root) Item_null(); + if (it == NULL) + MYSQL_YYABORT; + } sp_set= new sp_instr_set(lex->sphead->instructions(), ctx, spv->offset, it, spv->type, lex, TRUE); + if (sp_set == NULL) + MYSQL_YYABORT; lex->sphead->add_instr(sp_set); } } | option_type TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types { + THD *thd= YYTHD; LEX *lex=Lex; lex->option_type= $1; - lex->var_list.push_back(new set_var(lex->option_type, - find_sys_var(YYTHD, "tx_isolation"), - &null_lex_str, - new Item_int((int32) $5))); + Item *item= new (thd->mem_root) Item_int((int32) $5); + if (item == NULL) + MYSQL_YYABORT; + set_var *var= new set_var(lex->option_type, + find_sys_var(thd, "tx_isolation"), + &null_lex_str, + item); + if (var == NULL) + MYSQL_YYABORT; + lex->var_list.push_back(var); } ; option_value: '@' ident_or_text equal expr { - Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4))); + Item_func_set_user_var *item; + item= new (YYTHD->mem_root) Item_func_set_user_var($2, $4); + if (item == NULL) + MYSQL_YYABORT; + set_var_user *var= new set_var_user(item); + if (var == NULL) + MYSQL_YYABORT; + Lex->var_list.push_back(var); } | '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default { LEX *lex=Lex; - lex->var_list.push_back(new set_var($3, $4.var, &$4.base_name, $6)); + set_var *var= new set_var($3, $4.var, &$4.base_name, $6); + if (var == NULL) + MYSQL_YYABORT; + lex->var_list.push_back(var); } | charset old_or_new_charset_name_or_default { THD *thd= YYTHD; 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)); + CHARSET_INFO *cs2; + cs2= $2 ? $2: global_system_variables.character_set_client; + set_var_collation_client *var; + var= new set_var_collation_client(cs2, + thd->variables.collation_database, + cs2); + if (var == NULL) + MYSQL_YYABORT; + lex->var_list.push_back(var); } | NAMES_SYM equal expr { @@ -11012,15 +11945,21 @@ option_value: | NAMES_SYM charset_name_or_default opt_collate { LEX *lex= Lex; - $2= $2 ? $2 : global_system_variables.character_set_client; - $3= $3 ? $3 : $2; - if (!my_charset_same($2,$3)) + CHARSET_INFO *cs2; + CHARSET_INFO *cs3; + cs2= $2 ? $2 : global_system_variables.character_set_client; + cs3= $3 ? $3 : cs2; + if (!my_charset_same(cs2, cs3)) { my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), - $3->name, $2->csname); + cs3->name, cs2->csname); MYSQL_YYABORT; } - lex->var_list.push_back(new set_var_collation_client($3,$3,$3)); + set_var_collation_client *var; + var= new set_var_collation_client(cs3, cs3, cs3); + if (var == NULL) + MYSQL_YYABORT; + lex->var_list.push_back(var); } | PASSWORD equal text_or_password { @@ -11041,14 +11980,20 @@ option_value: 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)); + set_var_password *var= new set_var_password(user, $3); + if (var == NULL) + MYSQL_YYABORT; + thd->lex->var_list.push_back(var); thd->lex->autocommit= TRUE; if (lex->sphead) lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; } | PASSWORD FOR_SYM user equal text_or_password { - Lex->var_list.push_back(new set_var_password($3,$5)); + set_var_password *var= new set_var_password($3,$5); + if (var == NULL) + MYSQL_YYABORT; + Lex->var_list.push_back(var); Lex->autocommit= TRUE; if (Lex->sphead) Lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; @@ -11159,11 +12104,15 @@ text_or_password: Item_func_old_password::alloc(YYTHD, $3.str) : Item_func_password::alloc(YYTHD, $3.str) : $3.str; + if ($$ == NULL) + MYSQL_YYABORT; } | OLD_PASSWORD '(' TEXT_STRING ')' { $$= $3.length ? Item_func_old_password::alloc(YYTHD, $3.str) : $3.str; + if ($$ == NULL) + MYSQL_YYABORT; } ; @@ -11171,9 +12120,24 @@ text_or_password: set_expr_or_default: expr { $$=$1; } | DEFAULT { $$=0; } - | ON { $$=new Item_string("ON", 2, system_charset_info); } - | ALL { $$=new Item_string("ALL", 3, system_charset_info); } - | BINARY { $$=new Item_string("binary", 6, system_charset_info); } + | ON + { + $$=new (YYTHD->mem_root) Item_string("ON", 2, system_charset_info); + if ($$ == NULL) + MYSQL_YYABORT; + } + | ALL + { + $$=new (YYTHD->mem_root) Item_string("ALL", 3, system_charset_info); + if ($$ == NULL) + MYSQL_YYABORT; + } + | BINARY + { + $$=new (YYTHD->mem_root) Item_string("binary", 6, system_charset_info); + if ($$ == NULL) + MYSQL_YYABORT; + } ; /* Lock function */ @@ -11285,7 +12249,10 @@ handler: lex->expr_allows_subselect= FALSE; lex->sql_command = SQLCOM_HA_READ; lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */ - lex->current_select->select_limit= new Item_int((int32) 1); + Item *one= new (YYTHD->mem_root) Item_int((int32) 1); + if (one == NULL) + MYSQL_YYABORT; + lex->current_select->select_limit= one; lex->current_select->offset_limit= 0; if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) MYSQL_YYABORT; @@ -11608,8 +12575,9 @@ grant_user: { char *buff= (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); - if (buff) - make_scrambled_password_323(buff, $4.str); + if (buff == NULL) + MYSQL_YYABORT; + make_scrambled_password_323(buff, $4.str); $1->password.str= buff; $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; } @@ -11617,8 +12585,9 @@ grant_user: { char *buff= (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); - if (buff) - make_scrambled_password(buff, $4.str); + if (buff == NULL) + MYSQL_YYABORT; + make_scrambled_password(buff, $4.str); $1->password.str= buff; $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH; } @@ -11648,6 +12617,8 @@ column_list_id: ident { String *new_str = new (YYTHD->mem_root) String((const char*) $1.str,$1.length,system_charset_info); + if (new_str == NULL) + MYSQL_YYABORT; List_iterator <LEX_COLUMN> iter(Lex->columns); class LEX_COLUMN *point; LEX *lex=Lex; @@ -11661,7 +12632,12 @@ column_list_id: if (point) point->rights |= lex->which_columns; else - lex->columns.push_back(new LEX_COLUMN (*new_str,lex->which_columns)); + { + LEX_COLUMN *col= new LEX_COLUMN (*new_str,lex->which_columns); + if (col == NULL) + MYSQL_YYABORT; + lex->columns.push_back(col); + } } ; @@ -11816,12 +12792,18 @@ union_list: UNION_SYM union_option { LEX *lex=Lex; - if (lex->result) - { - /* Only the last SELECT can have INTO...... */ - my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO"); - MYSQL_YYABORT; - } + if (lex->result && + (lex->result->get_nest_level() == -1 || + lex->result->get_nest_level() == lex->nest_level)) + { + /* + Only the last SELECT can have INTO unless the INTO and UNION + are at different nest levels. In version 5.1 and above, INTO + will onle be allowed at top level. + */ + my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO"); + MYSQL_YYABORT; + } if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) { my_parse_error(ER(ER_SYNTAX_ERROR)); @@ -12079,21 +13061,18 @@ view_list: view_select: { - THD *thd= YYTHD; LEX *lex= Lex; - Lex_input_stream *lip= thd->m_lip; lex->parsing_options.allows_variable= FALSE; lex->parsing_options.allows_select_into= FALSE; lex->parsing_options.allows_select_procedure= FALSE; lex->parsing_options.allows_derived= FALSE; - lex->create_view_select.str= (char *) lip->get_cpp_ptr(); + lex->create_view_select.str= (char *) YYLIP->get_cpp_ptr(); } view_select_aux view_check_option { THD *thd= YYTHD; LEX *lex= Lex; - Lex_input_stream *lip= thd->m_lip; - uint len= lip->get_cpp_ptr() - lex->create_view_select.str; + uint len= YYLIP->get_cpp_ptr() - lex->create_view_select.str; void *create_view_select= thd->memdup(lex->create_view_select.str, len); lex->create_view_select.length= len; lex->create_view_select.str= (char *) create_view_select; @@ -12136,26 +13115,20 @@ trigger_tail: ON remember_name /* $7 */ { /* $8 */ - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - lex->raw_trg_on_table_name_begin= lip->get_tok_start(); + Lex->raw_trg_on_table_name_begin= YYLIP->get_tok_start(); } table_ident /* $9 */ FOR_SYM remember_name /* $11 */ { /* $12 */ - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - lex->raw_trg_on_table_name_end= lip->get_tok_start(); + Lex->raw_trg_on_table_name_end= YYLIP->get_tok_start(); } EACH_SYM ROW_SYM { /* $15 */ THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; sp_head *sp; if (lex->sphead) @@ -12176,13 +13149,6 @@ trigger_tail: lex->sphead= sp; lex->spname= $3; - /* - We have to turn of CLIENT_MULTI_QUERIES while parsing a - stored procedure, otherwise yylex will chop it into pieces - at each ';'. - */ - $<ulong_num>$= thd->client_capabilities & CLIENT_MULTI_QUERIES; - thd->client_capabilities &= ~CLIENT_MULTI_QUERIES; bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); lex->sphead->m_chistics= &lex->sp_chistics; @@ -12195,9 +13161,6 @@ trigger_tail: lex->sql_command= SQLCOM_CREATE_TRIGGER; sp->set_stmt_end(YYTHD); - /* Restore flag if it was cleared above */ - - YYTHD->client_capabilities |= $<ulong_num>15; sp->restore_thd_mem_root(YYTHD); if (sp->is_not_allowed_in_function("trigger")) @@ -12269,7 +13232,7 @@ sf_tail: { /* $5 */ THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; sp_head *sp; const char* tmp_param_begin; @@ -12283,19 +13246,14 @@ sf_tail: } /* Order is important here: new - reset - init */ sp= new sp_head(); + if (sp == NULL) + MYSQL_YYABORT; sp->reset_thd_mem_root(thd); sp->init(lex); sp->init_sp_name(thd, lex->spname); sp->m_type= TYPE_ENUM_FUNCTION; lex->sphead= sp; - /* - We have to turn off CLIENT_MULTI_QUERIES while parsing a - stored procedure, otherwise yylex will chop it into pieces - at each ';'. - */ - $<ulong_num>$= thd->client_capabilities & CLIENT_MULTI_QUERIES; - thd->client_capabilities &= ~CLIENT_MULTI_QUERIES; tmp_param_begin= lip->get_cpp_tok_start(); tmp_param_begin++; @@ -12304,11 +13262,7 @@ sf_tail: sp_fdparam_list /* $6 */ ')' /* $7 */ { /* $8 */ - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - - lex->sphead->m_param_end= lip->get_cpp_tok_start(); + Lex->sphead->m_param_end= YYLIP->get_cpp_tok_start(); } RETURNS_SYM /* $9 */ { /* $10 */ @@ -12345,7 +13299,7 @@ sf_tail: { /* $14 */ THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; lex->sphead->m_chistics= &lex->sp_chistics; lex->sphead->set_body_start(thd, lip->get_cpp_tok_start()); @@ -12401,8 +13355,6 @@ sf_tail: ER(ER_NATIVE_FCT_NAME_COLLISION), sp->m_name.str); } - /* Restore flag if it was cleared above */ - thd->client_capabilities |= $<ulong_num>5; sp->restore_thd_mem_root(thd); } ; @@ -12423,49 +13375,39 @@ sp_tail: /* Order is important here: new - reset - init */ sp= new sp_head(); + if (sp == NULL) + MYSQL_YYABORT; sp->reset_thd_mem_root(YYTHD); sp->init(lex); sp->m_type= TYPE_ENUM_PROCEDURE; sp->init_sp_name(YYTHD, $3); lex->sphead= sp; - /* - * We have to turn of CLIENT_MULTI_QUERIES while parsing a - * stored procedure, otherwise yylex will chop it into pieces - * at each ';'. - */ - $<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; - YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES); } '(' { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; const char* tmp_param_begin; - tmp_param_begin= lip->get_cpp_tok_start(); + tmp_param_begin= YYLIP->get_cpp_tok_start(); tmp_param_begin++; - lex->sphead->m_param_begin= tmp_param_begin; + Lex->sphead->m_param_begin= tmp_param_begin; } sp_pdparam_list ')' { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - lex->sphead->m_param_end= lip->get_cpp_tok_start(); + lex->sphead->m_param_end= YYLIP->get_cpp_tok_start(); bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); } sp_c_chistics { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; lex->sphead->m_chistics= &lex->sp_chistics; - lex->sphead->set_body_start(thd, lip->get_cpp_tok_start()); + lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start()); } sp_proc_stmt { @@ -12474,12 +13416,6 @@ sp_tail: sp->set_stmt_end(YYTHD); lex->sql_command= SQLCOM_CREATE_PROCEDURE; - /* - Restore flag if it was cleared above - Be careful with counting. the block where we save the value - is $4. - */ - YYTHD->client_capabilities |= $<ulong_num>4; sp->restore_thd_mem_root(YYTHD); } ; diff --git a/sql/stacktrace.c b/sql/stacktrace.c deleted file mode 100644 index 5c3411aa8b1..00000000000 --- a/sql/stacktrace.c +++ /dev/null @@ -1,575 +0,0 @@ -/* Copyright (C) 2000 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 */ - -/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/ -#define DONT_DEFINE_VOID 1 - -#include <my_global.h> -#include "stacktrace.h" - -#ifndef __WIN__ -#include <signal.h> -#include <my_pthread.h> -#include <m_string.h> -#ifdef HAVE_STACKTRACE -#include <unistd.h> -#include <strings.h> - -#if HAVE_EXECINFO_H -#include <execinfo.h> -#endif - -#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end) - -char *heap_start; - -void safe_print_str(const char* name, const char* val, int max_len) -{ - char *heap_end= (char*) sbrk(0); - fprintf(stderr, "%s at %p ", name, val); - - if (!PTR_SANE(val)) - { - fprintf(stderr, " is invalid pointer\n"); - return; - } - - fprintf(stderr, "= "); - for (; max_len && PTR_SANE(val) && *val; --max_len) - fputc(*val++, stderr); - fputc('\n', stderr); -} - -#ifdef TARGET_OS_LINUX - -#ifdef __i386__ -#define SIGRETURN_FRAME_OFFSET 17 -#endif - -#ifdef __x86_64__ -#define SIGRETURN_FRAME_OFFSET 23 -#endif - -#if defined(__alpha__) && defined(__GNUC__) -/* - The only way to backtrace without a symbol table on alpha - is to find stq fp,N(sp), and the first byte - of the instruction opcode will give us the value of N. From this - we can find where the old value of fp is stored -*/ - -#define MAX_INSTR_IN_FUNC 10000 - -inline uchar** find_prev_fp(uint32* pc, uchar** fp) -{ - int i; - for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc) - { - uchar* p = (uchar*)pc; - if (p[2] == 222 && p[3] == 35) - { - return (uchar**)((uchar*)fp - *(short int*)p); - } - } - return 0; -} - -inline uint32* find_prev_pc(uint32* pc, uchar** fp) -{ - int i; - for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc) - { - char* p = (char*)pc; - if (p[1] == 0 && p[2] == 94 && p[3] == -73) - { - uint32* prev_pc = (uint32*)*((fp+p[0]/sizeof(fp))); - return prev_pc; - } - } - return 0; -} -#endif /* defined(__alpha__) && defined(__GNUC__) */ - -#if BACKTRACE_DEMANGLE -static void my_demangle_symbols(char **addrs, int n) -{ - int status, i; - char *begin, *end, *demangled; - - for (i= 0; i < n; i++) - { - demangled= NULL; - begin= strchr(addrs[i], '('); - end= begin ? strchr(begin, '+') : NULL; - - if (begin && end) - { - *begin++= *end++= '\0'; - demangled= my_demangle(begin, &status); - if (!demangled || status) - { - demangled= NULL; - begin[-1]= '('; - end[-1]= '+'; - } - } - - if (demangled) - fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end); - else - fprintf(stderr, "%s\n", addrs[i]); - } -} -#endif - - -#if HAVE_BACKTRACE -static void backtrace_current_thread(void) -{ - void *addrs[128]; - char **strings= NULL; - int n = backtrace(addrs, array_elements(addrs)); -#if BACKTRACE_DEMANGLE - if ((strings= backtrace_symbols(addrs, n))) - { - my_demangle_symbols(strings, n); - free(strings); - } -#endif -#if HAVE_BACKTRACE_SYMBOLS_FD - if (!strings) - { - backtrace_symbols_fd(addrs, n, fileno(stderr)); - } -#endif -} -#endif - - -void print_stacktrace(uchar* stack_bottom, ulong thread_stack) -{ -#if HAVE_BACKTRACE - backtrace_current_thread(); - return; -#endif - uchar** fp; - uint frame_count = 0, sigreturn_frame_count; -#if defined(__alpha__) && defined(__GNUC__) - uint32* pc; -#endif - LINT_INIT(fp); - - -#ifdef __i386__ - __asm __volatile__ ("movl %%ebp,%0" - :"=r"(fp) - :"r"(fp)); -#endif -#ifdef __x86_64__ - __asm __volatile__ ("movq %%rbp,%0" - :"=r"(fp) - :"r"(fp)); -#endif -#if defined(__alpha__) && defined(__GNUC__) - __asm __volatile__ ("mov $30,%0" - :"=r"(fp) - :"r"(fp)); -#endif - if (!fp) - { - fprintf(stderr, "frame pointer is NULL, did you compile with\n\ --fomit-frame-pointer? Aborting backtrace!\n"); - return; - } - - if (!stack_bottom || (uchar*) stack_bottom > (uchar*) &fp) - { - ulong tmp= min(0x10000,thread_stack); - /* Assume that the stack starts at the previous even 65K */ - stack_bottom= (uchar*) (((ulong) &fp + tmp) & - ~(ulong) 0xFFFF); - fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp); - } - if (fp > (uchar**) stack_bottom || - fp < (uchar**) stack_bottom - thread_stack) - { - fprintf(stderr, "Bogus stack limit or frame pointer,\ - fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n", - fp, stack_bottom, thread_stack); - return; - } - - fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n"); -#if defined(__alpha__) && defined(__GNUC__) - fprintf(stderr, "Warning: Alpha stacks are difficult -\ - will be taking some wild guesses, stack trace may be incorrect or \ - terminate abruptly\n"); - /* On Alpha, we need to get pc */ - __asm __volatile__ ("bsr %0, do_next; do_next: " - :"=r"(pc) - :"r"(pc)); -#endif /* __alpha__ */ - - /* We are 1 frame above signal frame with NPTL and 2 frames above with LT */ - sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1; - - while (fp < (uchar**) stack_bottom) - { -#if defined(__i386__) || defined(__x86_64__) - uchar** new_fp = (uchar**)*fp; - fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ? - *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1)); -#endif /* defined(__386__) || defined(__x86_64__) */ - -#if defined(__alpha__) && defined(__GNUC__) - uchar** new_fp = find_prev_fp(pc, fp); - if (frame_count == sigreturn_frame_count - 1) - { - new_fp += 90; - } - - if (fp && pc) - { - pc = find_prev_pc(pc, fp); - if (pc) - fprintf(stderr, "%p\n", pc); - else - { - fprintf(stderr, "Not smart enough to deal with the rest\ - of this stack\n"); - goto end; - } - } - else - { - fprintf(stderr, "Not smart enough to deal with the rest of this stack\n"); - goto end; - } -#endif /* defined(__alpha__) && defined(__GNUC__) */ - if (new_fp <= fp ) - { - fprintf(stderr, "New value of fp=%p failed sanity check,\ - terminating stack trace!\n", new_fp); - goto end; - } - fp = new_fp; - ++frame_count; - } - - fprintf(stderr, "Stack trace seems successful - bottom reached\n"); - -end: - fprintf(stderr, - "Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" - "and follow instructions on how to resolve the stack trace.\n" - "Resolved stack trace is much more helpful in diagnosing the\n" - "problem, so please do resolve it\n"); -} -#endif /* TARGET_OS_LINUX */ -#endif /* HAVE_STACKTRACE */ - -/* Produce a core for the thread */ - -#ifdef NOT_USED /* HAVE_LINUXTHREADS */ -void write_core(int sig) -{ - signal(sig, SIG_DFL); - if (fork() != 0) exit(1); /* Abort main program */ - /* Core will be written at exit */ -} -#else -void write_core(int sig) -{ - signal(sig, SIG_DFL); -#ifdef HAVE_gcov - /* - For GCOV build, crashing will prevent the writing of code coverage - information from this process, causing gcov output to be incomplete. - So we force the writing of coverage information here before terminating. - */ - extern void __gcov_flush(void); - __gcov_flush(); -#endif - pthread_kill(pthread_self(), sig); -#if defined(P_MYID) && !defined(SCO) - /* On Solaris, the above kill is not enough */ - sigsend(P_PID,P_MYID,sig); -#endif -} -#endif -#else /* __WIN__*/ - -#include <dbghelp.h> - -/* - Stack tracing on Windows is implemented using Debug Helper library(dbghelp.dll) - We do not redistribute dbghelp and the one comes with older OS (up to Windows 2000) - is missing some important functions like functions StackWalk64 or MinidumpWriteDump. - Hence, we have to load functions at runtime using LoadLibrary/GetProcAddress. -*/ - -typedef DWORD (WINAPI *SymSetOptions_FctType)(DWORD dwOptions); -typedef BOOL (WINAPI *SymGetModuleInfo64_FctType) - (HANDLE,DWORD64,PIMAGEHLP_MODULE64) ; -typedef BOOL (WINAPI *SymGetSymFromAddr64_FctType) - (HANDLE,DWORD64,PDWORD64,PIMAGEHLP_SYMBOL64) ; -typedef BOOL (WINAPI *SymGetLineFromAddr64_FctType) - (HANDLE,DWORD64,PDWORD,PIMAGEHLP_LINE64); -typedef BOOL (WINAPI *SymInitialize_FctType) - (HANDLE,PSTR,BOOL); -typedef BOOL (WINAPI *StackWalk64_FctType) - (DWORD,HANDLE,HANDLE,LPSTACKFRAME64,PVOID,PREAD_PROCESS_MEMORY_ROUTINE64, - PFUNCTION_TABLE_ACCESS_ROUTINE64,PGET_MODULE_BASE_ROUTINE64 , - PTRANSLATE_ADDRESS_ROUTINE64); -typedef BOOL (WINAPI *MiniDumpWriteDump_FctType)( - IN HANDLE hProcess, - IN DWORD ProcessId, - IN HANDLE hFile, - IN MINIDUMP_TYPE DumpType, - IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL - IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL - IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL - ); - -static SymSetOptions_FctType pSymSetOptions; -static SymGetModuleInfo64_FctType pSymGetModuleInfo64; -static SymGetSymFromAddr64_FctType pSymGetSymFromAddr64; -static SymInitialize_FctType pSymInitialize; -static StackWalk64_FctType pStackWalk64; -static SymGetLineFromAddr64_FctType pSymGetLineFromAddr64; -static MiniDumpWriteDump_FctType pMiniDumpWriteDump; - -static EXCEPTION_POINTERS *exception_ptrs; - -#define MODULE64_SIZE_WINXP 576 -#define STACKWALK_MAX_FRAMES 64 - -/* - Dynamically load dbghelp functions -*/ -BOOL init_dbghelp_functions() -{ - static BOOL first_time= TRUE; - static BOOL rc; - HMODULE hDbghlp; - - if(first_time) - { - first_time= FALSE; - hDbghlp= LoadLibrary("dbghelp"); - if(!hDbghlp) - { - rc= FALSE; - return rc; - } - pSymSetOptions= (SymSetOptions_FctType) - GetProcAddress(hDbghlp,"SymSetOptions"); - pSymInitialize= (SymInitialize_FctType) - GetProcAddress(hDbghlp,"SymInitialize"); - pSymGetModuleInfo64= (SymGetModuleInfo64_FctType) - GetProcAddress(hDbghlp,"SymGetModuleInfo64"); - pSymGetLineFromAddr64= (SymGetLineFromAddr64_FctType) - GetProcAddress(hDbghlp,"SymGetLineFromAddr64"); - pSymGetSymFromAddr64=(SymGetSymFromAddr64_FctType) - GetProcAddress(hDbghlp,"SymGetSymFromAddr64"); - pStackWalk64= (StackWalk64_FctType) - GetProcAddress(hDbghlp,"StackWalk64"); - pMiniDumpWriteDump = (MiniDumpWriteDump_FctType) - GetProcAddress(hDbghlp,"MiniDumpWriteDump"); - - rc = (BOOL)(pSymSetOptions && pSymInitialize && pSymGetModuleInfo64 - && pSymGetLineFromAddr64 && pSymGetSymFromAddr64 && pStackWalk64); - } - return rc; -} - -void set_exception_pointers(EXCEPTION_POINTERS *ep) -{ - exception_ptrs = ep; -} - -/* Platform SDK in VS2003 does not have definition for SYMOPT_NO_PROMPTS*/ -#ifndef SYMOPT_NO_PROMPTS -#define SYMOPT_NO_PROMPTS 0 -#endif - -void print_stacktrace(uchar* unused1, ulong unused2) -{ - HANDLE hProcess= GetCurrentProcess(); - HANDLE hThread= GetCurrentThread(); - static IMAGEHLP_MODULE64 module= {sizeof(module)}; - static IMAGEHLP_SYMBOL64_PACKAGE package; - DWORD64 addr; - DWORD machine; - int i; - CONTEXT context; - STACKFRAME64 frame={0}; - - if(!exception_ptrs || !init_dbghelp_functions()) - return; - - /* Copy context, as stackwalking on original will unwind the stack */ - context = *(exception_ptrs->ContextRecord); - /*Initialize symbols.*/ - pSymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_NO_PROMPTS|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG); - pSymInitialize(hProcess,NULL,TRUE); - - /*Prepare stackframe for the first StackWalk64 call*/ - frame.AddrFrame.Mode= frame.AddrPC.Mode= frame.AddrStack.Mode= AddrModeFlat; -#if (defined _M_IX86) - machine= IMAGE_FILE_MACHINE_I386; - frame.AddrFrame.Offset= context.Ebp; - frame.AddrPC.Offset= context.Eip; - frame.AddrStack.Offset= context.Esp; -#elif (defined _M_X64) - machine = IMAGE_FILE_MACHINE_AMD64; - frame.AddrFrame.Offset= context.Rbp; - frame.AddrPC.Offset= context.Rip; - frame.AddrStack.Offset= context.Rsp; -#else - /*There is currently no need to support IA64*/ -#pragma error ("unsupported architecture") -#endif - - package.sym.SizeOfStruct= sizeof(package.sym); - package.sym.MaxNameLength= sizeof(package.name); - - /*Walk the stack, output useful information*/ - for(i= 0; i< STACKWALK_MAX_FRAMES;i++) - { - DWORD64 function_offset= 0; - DWORD line_offset= 0; - IMAGEHLP_LINE64 line= {sizeof(line)}; - BOOL have_module= FALSE; - BOOL have_symbol= FALSE; - BOOL have_source= FALSE; - - if(!pStackWalk64(machine, hProcess, hThread, &frame, &context, 0, 0, 0 ,0)) - break; - addr= frame.AddrPC.Offset; - - have_module= pSymGetModuleInfo64(hProcess,addr,&module); -#ifdef _M_IX86 - if(!have_module) - { - /* - ModuleInfo structure has been "compatibly" extended in releases after XP, - and its size was increased. To make XP dbghelp.dll function - happy, pretend passing the old structure. - */ - module.SizeOfStruct= MODULE64_SIZE_WINXP; - have_module= pSymGetModuleInfo64(hProcess, addr, &module); - } -#endif - - have_symbol= pSymGetSymFromAddr64(hProcess, addr, &function_offset, - &(package.sym)); - have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line); - - fprintf(stderr, "%p ", addr); - if(have_module) - { - char *base_image_name= strrchr(module.ImageName, '\\'); - if(base_image_name) - base_image_name++; - else - base_image_name= module.ImageName; - fprintf(stderr, "%s!", base_image_name); - } - if(have_symbol) - fprintf(stderr, "%s()", package.sym.Name); - else if(have_module) - fprintf(stderr, "???"); - - if(have_source) - { - char *base_file_name= strrchr(line.FileName, '\\'); - if(base_file_name) - base_file_name++; - else - base_file_name= line.FileName; - fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber); - } - fprintf(stderr, "\n"); - } - fflush(stderr); -} - - -/* - Write dump. The dump is created in current directory, - file name is constructed from executable name plus - ".dmp" extension -*/ -void write_core(int unused) -{ - char path[MAX_PATH]; - char dump_fname[MAX_PATH]= "core.dmp"; - MINIDUMP_EXCEPTION_INFORMATION info; - HANDLE hFile; - - if(!exception_ptrs || !init_dbghelp_functions() || !pMiniDumpWriteDump) - return; - - info.ExceptionPointers= exception_ptrs; - info.ClientPointers= FALSE; - info.ThreadId= GetCurrentThreadId(); - - if(GetModuleFileName(NULL, path, sizeof(path))) - { - _splitpath(path, NULL, NULL,dump_fname,NULL); - strncat(dump_fname, ".dmp", sizeof(dump_fname)); - } - - hFile= CreateFile(dump_fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, 0); - if(hFile) - { - /* Create minidump */ - if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), - hFile, MiniDumpNormal, &info, 0, 0)) - { - fprintf(stderr, "Minidump written to %s\n", - _fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname); - } - else - { - fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n", - GetLastError()); - } - CloseHandle(hFile); - } - else - { - fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname, - GetLastError()); - } - fflush(stderr); -} - - -void safe_print_str(const char *name, const char *val, int len) -{ - fprintf(stderr,"%s at %p", name, val); - __try - { - fprintf(stderr,"=%.*s\n", len, val); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - fprintf(stderr,"is an invalid string pointer\n"); - } -} -#endif /*__WIN__*/ diff --git a/sql/stacktrace.h b/sql/stacktrace.h deleted file mode 100644 index 498f4f197fc..00000000000 --- a/sql/stacktrace.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (C) 2000 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 */ - -#ifdef __cplusplus -extern "C" { -#endif - -#if HAVE_BACKTRACE && HAVE_BACKTRACE_SYMBOLS && HAVE_CXXABI_H && HAVE_ABI_CXA_DEMANGLE -#define BACKTRACE_DEMANGLE 1 -#endif - -#if BACKTRACE_DEMANGLE -char *my_demangle(const char *mangled_name, int *status); -#endif - -#ifdef TARGET_OS_LINUX -#if defined(HAVE_STACKTRACE) || (defined (__x86_64__) || defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) -#undef HAVE_STACKTRACE -#define HAVE_STACKTRACE - -extern char* __bss_start; -extern char* heap_start; - -#define init_stacktrace() do { \ - heap_start = (char*) &__bss_start; \ - } while(0); -void check_thread_lib(void); -#endif /* defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */ -#elif defined (__WIN__) -#define HAVE_STACKTRACE -extern void set_exception_pointers(EXCEPTION_POINTERS *ep); -#define init_stacktrace() {} -#endif - -#ifdef HAVE_STACKTRACE -void print_stacktrace(uchar* stack_bottom, ulong thread_stack); -void safe_print_str(const char* name, const char* val, int max_len); -#else -/* Define empty prototypes for functions that are not implemented */ -#define init_stacktrace() {} -#define print_stacktrace(A,B) {} -#define safe_print_str(A,B,C) {} -#endif /* HAVE_STACKTRACE */ - - -#if !defined(__NETWARE__) -#define HAVE_WRITE_CORE -#endif - -#ifdef HAVE_WRITE_CORE -void write_core(int sig); -#endif - - -#ifdef __cplusplus -} -#endif diff --git a/sql/structs.h b/sql/structs.h index 809175fdde4..0a20eee0e9a 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -314,31 +314,22 @@ private: */ Discrete_interval *current; uint elements; // number of elements - - /* helper function for copy construct and assignment operator */ - void copy_(const Discrete_intervals_list& from) - { - for (Discrete_interval *i= from.head; i; i= i->next) - { - Discrete_interval j= *i; - append(&j); - } + void set_members(Discrete_interval *h, Discrete_interval *t, + Discrete_interval *c, uint el) + { + head= h; + tail= t; + current= c; + elements= el; } + void operator=(Discrete_intervals_list &); /* prevent use of these */ + Discrete_intervals_list(const Discrete_intervals_list &); + public: Discrete_intervals_list() : head(NULL), current(NULL), elements(0) {}; - Discrete_intervals_list(const Discrete_intervals_list& from) - { - copy_(from); - } - void operator=(const Discrete_intervals_list& from) - { - empty(); - copy_(from); - } void empty_no_free() { - head= current= NULL; - elements= 0; + set_members(NULL, NULL, NULL, 0); } void empty() { @@ -350,7 +341,24 @@ public: } empty_no_free(); } - + void copy_shallow(const Discrete_intervals_list * dli) + { + head= dli->get_head(); + tail= dli->get_tail(); + current= dli->get_current(); + elements= dli->nb_elements(); + } + void swap (Discrete_intervals_list * dli) + { + Discrete_interval *h, *t, *c; + uint el; + h= dli->get_head(); + t= dli->get_tail(); + c= dli->get_current(); + el= dli->nb_elements(); + dli->copy_shallow(this); + set_members(h, t, c, el); + } const Discrete_interval* get_next() { Discrete_interval *tmp= current; @@ -364,4 +372,7 @@ public: ulonglong minimum() const { return (head ? head->minimum() : 0); }; ulonglong maximum() const { return (head ? tail->maximum() : 0); }; uint nb_elements() const { return elements; } + Discrete_interval* get_head() const { return head; }; + Discrete_interval* get_tail() const { return tail; }; + Discrete_interval* get_current() const { return current; }; }; diff --git a/sql/table.cc b/sql/table.cc index 7f1e0412103..91a6c145610 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1998,6 +1998,28 @@ void free_blobs(register TABLE *table) } +/** + Reclaim temporary blob storage which is bigger than + a threshold. + + @param table A handle to the TABLE object containing blob fields + @param size The threshold value. + +*/ + +void free_field_buffers_larger_than(TABLE *table, uint32 size) +{ + uint *ptr, *end; + for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ; + ptr != end ; + ptr++) + { + Field_blob *blob= (Field_blob*) table->field[*ptr]; + if (blob->get_field_buffer_size() > size) + blob->free(); + } +} + /* Find where a form starts */ /* if formname is NullS then only formnames is read */ @@ -2972,16 +2994,27 @@ void TABLE_LIST::calc_md5(char *buffer) } -/* - set underlying TABLE for table place holder of VIEW +/** + @brief Set underlying table for table place holder of view. - DESCRIPTION - Replace all views that only uses one table with the table itself. - This allows us to treat the view as a simple table and even update - it (it is a kind of optimisation) + @details - SYNOPSIS - TABLE_LIST::set_underlying_merge() + Replace all views that only use one table with the table itself. This + allows us to treat the view as a simple table and even update it (it is a + kind of optimization). + + @note + + This optimization is potentially dangerous as it makes views + masquerade as base tables: Views don't have the pointer TABLE_LIST::table + set to non-@c NULL. + + We may have the case where a view accesses tables not normally accessible + in the current Security_context (only in the definer's + Security_context). According to the table's GRANT_INFO (TABLE::grant), + access is fulfilled, but this is implicitly meant in the definer's security + context. Hence we must never look at only a TABLE's GRANT_INFO without + looking at the one of the referring TABLE_LIST. */ void TABLE_LIST::set_underlying_merge() @@ -4061,7 +4094,7 @@ void Field_iterator_table_ref::next() } -const char *Field_iterator_table_ref::table_name() +const char *Field_iterator_table_ref::get_table_name() { if (table_ref->view) return table_ref->view_name.str; @@ -4074,7 +4107,7 @@ const char *Field_iterator_table_ref::table_name() } -const char *Field_iterator_table_ref::db_name() +const char *Field_iterator_table_ref::get_db_name() { if (table_ref->view) return table_ref->view_db.str; diff --git a/sql/table.h b/sql/table.h index 0e0a35b022d..d21a9eefae8 100644 --- a/sql/table.h +++ b/sql/table.h @@ -66,13 +66,63 @@ typedef struct st_order { table_map used, depend_map; } ORDER; +/** + @brief The current state of the privilege checking process for the current + user, SQL statement and SQL object. + + @details The privilege checking process is divided into phases depending on + the level of the privilege to be checked and the type of object to be + accessed. Due to the mentioned scattering of privilege checking + functionality, it is necessary to keep track of the state of the + process. This information is stored in privilege, want_privilege, and + orig_want_privilege. + + A GRANT_INFO also serves as a cache of the privilege hash tables. Relevant + members are grant_table and version. + */ typedef struct st_grant_info { + /** + @brief A copy of the privilege information regarding the current host, + database, object and user. + + @details The version of this copy is found in GRANT_INFO::version. + */ GRANT_TABLE *grant_table; + /** + @brief Used for cache invalidation when caching privilege information. + + @details The privilege information is stored on disk, with dedicated + caches residing in memory: table-level and column-level privileges, + respectively, have their own dedicated caches. + + The GRANT_INFO works as a level 1 cache with this member updated to the + current value of the global variable @c grant_version (@c static variable + in sql_acl.cc). It is updated Whenever the GRANT_INFO is refreshed from + the level 2 cache. The level 2 cache is the @c column_priv_hash structure + (@c static variable in sql_acl.cc) + + @see grant_version + */ uint version; + /** + @brief The set of privileges that the current user has fulfilled for a + certain host, database, and object. + + @details This field is continually updated throughout the access checking + process. In each step the "wanted privilege" is checked against the + fulfilled privileges. When/if the intersection of these sets is empty, + access is granted. + + The set is implemented as a bitmap, with the bits defined in sql_acl.h. + */ ulong privilege; + /** + @brief the set of privileges that the current user needs to fulfil in + order to carry out the requested operation. + */ ulong want_privilege; - /* + /** Stores the requested access acl of top level tables list. Is used to check access rights to the underlying tables of a view. */ @@ -438,6 +488,105 @@ typedef struct st_table_share return table_map_id; } + /** + Convert unrelated members of TABLE_SHARE to one enum + representing its type. + + @todo perhaps we need to have a member instead of a function. + */ + enum enum_table_ref_type get_table_ref_type() const + { + if (is_view) + return TABLE_REF_VIEW; + switch (tmp_table) { + case NO_TMP_TABLE: + return TABLE_REF_BASE_TABLE; + case SYSTEM_TMP_TABLE: + return TABLE_REF_I_S_TABLE; + default: + return TABLE_REF_TMP_TABLE; + } + } + /** + Return a table metadata version. + * for base tables, we return table_map_id. + It is assigned from a global counter incremented for each + new table loaded into the table definition cache (TDC). + * for temporary tables it's table_map_id again. But for + temporary tables table_map_id is assigned from + thd->query_id. The latter is assigned from a thread local + counter incremented for every new SQL statement. Since + temporary tables are thread-local, each temporary table + gets a unique id. + * for everything else (views, information schema tables), + the version id is zero. + + This choice of version id is a large compromise + to have a working prepared statement validation in 5.1. In + future version ids will be persistent, as described in WL#4180. + + Let's try to explain why and how this limited solution allows + to validate prepared statements. + + Firstly, sets (in mathematical sense) of version numbers + never intersect for different table types. Therefore, + version id of a temporary table is never compared with + a version id of a view, and vice versa. + + Secondly, for base tables, we know that each DDL flushes the + respective share from the TDC. This ensures that whenever + a table is altered or dropped and recreated, it gets a new + version id. + Unfortunately, since elements of the TDC are also flushed on + LRU basis, this choice of version ids leads to false positives. + E.g. when the TDC size is too small, we may have a SELECT + * FROM INFORMATION_SCHEMA.TABLES flush all its elements, which + in turn will lead to a validation error and a subsequent + reprepare of all prepared statements. This is + considered acceptable, since as long as prepared statements are + automatically reprepared, spurious invalidation is only + a performance hit. Besides, no better simple solution exists. + + For temporary tables, using thd->query_id ensures that if + a temporary table was altered or recreated, a new version id is + assigned. This suits validation needs very well and will perhaps + never change. + + Metadata of information schema tables never changes. + Thus we can safely assume 0 for a good enough version id. + + Views are a special and tricky case. A view is always inlined + into the parse tree of a prepared statement at prepare. + Thus, when we execute a prepared statement, the parse tree + will not get modified even if the view is replaced with another + view. Therefore, we can safely choose 0 for version id of + views and effectively never invalidate a prepared statement + when a view definition is altered. Note, that this leads to + wrong binary log in statement-based replication, since we log + prepared statement execution in form Query_log_events + containing conventional statements. But since there is no + metadata locking for views, the very same problem exists for + conventional statements alone, as reported in Bug#25144. The only + difference between prepared and conventional execution is, + effectively, that for prepared statements the race condition + window is much wider. + In 6.0 we plan to support view metadata locking (WL#3726) and + extend table definition cache to cache views (WL#4298). + When this is done, views will be handled in the same fashion + as the base tables. + + Finally, by taking into account table type, we always + track that a change has taken place when a view is replaced + with a base table, a base table is replaced with a temporary + table and so on. + + @sa TABLE_LIST::is_table_ref_id_equal() + */ + ulong get_table_ref_version() const + { + return (tmp_table == SYSTEM_TMP_TABLE || is_view) ? 0 : table_map_id; + } + } TABLE_SHARE; @@ -836,6 +985,9 @@ typedef struct st_schema_table #define VIEW_CHECK_ERROR 1 #define VIEW_CHECK_SKIP 2 +/** The threshold size a blob field buffer before it is freed */ +#define MAX_TDC_BLOB_SIZE 65536 + struct st_lex; class select_union; class TMP_TABLE_PARAM; @@ -1002,6 +1154,27 @@ struct TABLE_LIST can see this lists can't be merged) */ TABLE_LIST *correspondent_table; + /** + @brief Normally, this field is non-null for anonymous derived tables only. + + @details This field is set to non-null for + + - Anonymous derived tables, In this case it points to the SELECT_LEX_UNIT + representing the derived table. E.g. for a query + + @verbatim SELECT * FROM (SELECT a FROM t1) b @endverbatim + + For the @c TABLE_LIST representing the derived table @c b, @c derived + points to the SELECT_LEX_UNIT representing the result of the query within + parenteses. + + - Views. This is set for views with @verbatim ALGORITHM = TEMPTABLE + @endverbatim by mysql_make_view(). + + @note Inside views, a subquery in the @c FROM clause is not allowed. + @note Do not use this field to separate views/base tables/anonymous + derived tables. Use TABLE_LIST::is_anonymous_derived_table(). + */ 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; @@ -1067,7 +1240,15 @@ struct TABLE_LIST ulonglong file_version; /* version of file's field set */ ulonglong updatable_view; /* VIEW can be updated */ ulonglong revision; /* revision control number */ - ulonglong algorithm; /* 0 any, 1 tmp tables , 2 merging */ + /** + @brief The declared algorithm, if this is a view. + @details One of + - VIEW_ALGORITHM_UNDEFINED + - VIEW_ALGORITHM_TMPTABLE + - VIEW_ALGORITHM_MERGE + @to do Replace with an enum + */ + ulonglong algorithm; ulonglong view_suid; /* view is suid (TRUE dy default) */ ulonglong with_check; /* WITH CHECK OPTION */ /* @@ -1075,7 +1256,15 @@ struct TABLE_LIST algorithm) */ uint8 effective_with_check; - uint8 effective_algorithm; /* which algorithm was really used */ + /** + @brief The view algorithm that is actually used, if this is a view. + @details One of + - VIEW_ALGORITHM_UNDEFINED + - VIEW_ALGORITHM_TMPTABLE + - VIEW_ALGORITHM_MERGE + @to do Replace with an enum + */ + uint8 effective_algorithm; GRANT_INFO grant; /* data need by some engines in query cache*/ ulonglong engine_data; @@ -1233,6 +1422,53 @@ struct TABLE_LIST child_def_version= ~0UL; } + /** + Compare the version of metadata from the previous execution + (if any) with values obtained from the current table + definition cache element. + + @sa check_and_update_table_version() + */ + inline + bool is_table_ref_id_equal(TABLE_SHARE *s) const + { + return (m_table_ref_type == s->get_table_ref_type() && + m_table_ref_version == s->get_table_ref_version()); + } + + /** + Record the value of metadata version of the corresponding + table definition cache element in this parse tree node. + + @sa check_and_update_table_version() + */ + inline + void set_table_ref_id(TABLE_SHARE *s) + { + m_table_ref_type= s->get_table_ref_type(); + m_table_ref_version= s->get_table_ref_version(); + } + + /** + @brief True if this TABLE_LIST represents an anonymous derived table, + i.e. the result of a subquery. + */ + bool is_anonymous_derived_table() const { return derived && !view; } + + /** + @brief Returns the name of the database that the referenced table belongs + to. + */ + char *get_db_name() { return view != NULL ? view_db.str : db; } + + /** + @brief Returns the name of the table that this TABLE_LIST represents. + + @details The unqualified table name or view name for a table or view, + respectively. + */ + char *get_table_name() { return view != NULL ? view_name.str : table_name; } + private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); @@ -1243,6 +1479,10 @@ private: /* Remembered MERGE child def version. See top comment in ha_myisammrg.cc */ ulong child_def_version; + /** See comments for set_metadata_id() */ + enum enum_table_ref_type m_table_ref_type; + /** See comments for set_metadata_id() */ + ulong m_table_ref_version; }; class Item; @@ -1358,8 +1598,8 @@ public: bool end_of_fields() { return (table_ref == last_leaf && field_it->end_of_fields()); } const char *name() { return field_it->name(); } - const char *table_name(); - const char *db_name(); + const char *get_table_name(); + const char *get_db_name(); GRANT_INFO *grant(); Item *create_item(THD *thd) { return field_it->create_item(thd); } Field *field() { return field_it->field(); } diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc index ddf35002880..6bf43b51df0 100644 --- a/sql/thr_malloc.cc +++ b/sql/thr_malloc.cc @@ -21,10 +21,34 @@ extern "C" { void sql_alloc_error_handler(void) { - THD *thd=current_thd; - if (thd) // QQ; To be removed - thd->fatal_error(); /* purecov: inspected */ sql_print_error(ER(ER_OUT_OF_RESOURCES)); + + THD *thd= current_thd; + if (thd) + { + if (! thd->is_error()) + { + /* + This thread is Out Of Memory. + An OOM condition is a fatal error. + It should not be caught by error handlers in stored procedures. + Also, recording that SQL condition in the condition area could + cause more memory allocations, which in turn could raise more + OOM conditions, causing recursion in the error handling code itself. + As a result, my_error() should not be invoked, and the + thread diagnostics area is set to an error status directly. + Note that Diagnostics_area::set_error_status() is safe, + since it does not call any memory allocation routines. + The visible result for a client application will be: + - a query fails with an ER_OUT_OF_RESOURCES error, + returned in the error packet. + - SHOW ERROR/SHOW WARNINGS may be empty. + */ + thd->main_da.set_error_status(thd, + ER_OUT_OF_RESOURCES, + ER(ER_OUT_OF_RESOURCES)); + } + } } } diff --git a/sql/tztime.cc b/sql/tztime.cc index f080c61e243..1028cfb7c1b 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1034,7 +1034,7 @@ public: return lowest possible my_time_t in case of ambiguity or if we provide time corresponding to the time-gap. - You should call init_time() function before using this function. + You should call my_init_time() function before using this function. RETURN VALUE Corresponding my_time_t value or 0 in case of error @@ -2663,7 +2663,7 @@ main(int argc, char **argv) } printf("gmt_sec_to_TIME = localtime for time_t in [1000000000,1100000000) range\n"); - init_time(); + my_init_time(); /* Be careful here! my_system_gmt_sec doesn't fully handle unnormalized diff --git a/sql/unireg.h b/sql/unireg.h index 18c3ab16f6a..6f9c44d98f9 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -63,6 +63,7 @@ #define MAX_MBWIDTH 3 /* Max multibyte sequence */ #define MAX_FIELD_CHARLENGTH 255 #define MAX_FIELD_VARCHARLENGTH 65535 +#define MAX_FIELD_BLOBLENGTH UINT_MAX32 /* cf field_blob::get_length() */ #define CONVERT_IF_BIGGER_TO_BLOB 512 /* Used for CREATE ... SELECT */ /* Max column width +1 */ |