diff options
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 624 |
1 files changed, 32 insertions, 592 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 505e6038978..5d669de3110 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -50,6 +50,8 @@ // mysql_backup_table, // mysql_restore_table #include "sql_truncate.h" // mysql_truncate_table +#include "sql_reload.h" // reload_acl_and_cache +#include "sql_admin.h" // mysql_assign_to_keycache #include "sql_connect.h" // check_user, // decrease_user_connections, // thd_init_client_charset, check_mqh, @@ -658,8 +660,7 @@ end: every child. Set 'db' for every child if not present. */ #ifndef NO_EMBEDDED_ACCESS_CHECKS -static bool check_merge_table_access(THD *thd, char *db, - TABLE_LIST *table_list) +bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list) { int error= 0; @@ -1627,140 +1628,6 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, /** - Implementation of FLUSH TABLES <table_list> WITH READ LOCK. - - In brief: take exclusive locks, expel tables from the table - cache, reopen the tables, enter the 'LOCKED TABLES' mode, - downgrade the locks. - Note: the function is written to be called from - mysql_execute_command(), it is not reusable in arbitrary - execution context. - - Required privileges - ------------------- - Since the statement implicitly enters LOCK TABLES mode, - it requires LOCK TABLES privilege on every table. - But since the rest of FLUSH commands require - the global RELOAD_ACL, it also requires RELOAD_ACL. - - Compatibility with the global read lock - --------------------------------------- - We don't wait for the GRL, since neither the - 5.1 combination that this new statement is intended to - replace (LOCK TABLE <list> WRITE; FLUSH TABLES;), - nor FLUSH TABLES WITH READ LOCK do. - @todo: this is not implemented, Dmitry disagrees. - Currently we wait for GRL in another connection, - but are compatible with a GRL in our own connection. - - Behaviour under LOCK TABLES - --------------------------- - Bail out: i.e. don't perform an implicit UNLOCK TABLES. - This is not consistent with LOCK TABLES statement, but is - in line with behaviour of FLUSH TABLES WITH READ LOCK, and we - try to not introduce any new statements with implicit - semantics. - - Compatibility with parallel updates - ----------------------------------- - As a result, we will wait for all open transactions - against the tables to complete. After the lock downgrade, - new transactions will be able to read the tables, but not - write to them. - - Differences from FLUSH TABLES <list> - ------------------------------------- - - you can't flush WITH READ LOCK a non-existent table - - you can't flush WITH READ LOCK under LOCK TABLES - - currently incompatible with the GRL (@todo: fix) - - Effect on views and temporary tables. - ------------------------------------ - You can only apply this command to existing base tables. - If a view with such name exists, ER_WRONG_OBJECT is returned. - If a temporary table with such name exists, it's ignored: - if there is a base table, it's used, otherwise ER_NO_SUCH_TABLE - is returned. -*/ - -static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables) -{ - Lock_tables_prelocking_strategy lock_tables_prelocking_strategy; - TABLE_LIST *table_list; - - /* - This is called from SQLCOM_FLUSH, the transaction has - been committed implicitly. - */ - - /* RELOAD_ACL is checked by the caller. Check table-level privileges. */ - if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, - FALSE, UINT_MAX, FALSE)) - goto error; - - if (thd->locked_tables_mode) - { - my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); - goto error; - } - - /* - @todo: Since lock_table_names() acquires a global IX - lock, this actually waits for a GRL in another connection. - We are thus introducing an incompatibility. - Do nothing for now, since not taking a global IX violates - current internal MDL asserts, fix after discussing with - Dmitry. - */ - if (lock_table_names(thd, all_tables, 0, thd->variables.lock_wait_timeout, - MYSQL_OPEN_SKIP_TEMPORARY)) - goto error; - - for (table_list= all_tables; table_list; - table_list= table_list->next_global) - { - /* Remove the table from cache. */ - mysql_mutex_lock(&LOCK_open); - tdc_remove_table(thd, TDC_RT_REMOVE_ALL, - table_list->db, - table_list->table_name); - mysql_mutex_unlock(&LOCK_open); - - /* Skip views and temporary tables. */ - table_list->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */ - table_list->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */ - } - - if (open_and_lock_tables(thd, all_tables, FALSE, - MYSQL_OPEN_HAS_MDL_LOCK, - &lock_tables_prelocking_strategy) || - thd->locked_tables_list.init_locked_tables(thd)) - { - goto error; - } - thd->variables.option_bits|= OPTION_TABLE_LOCK; - - /* - Downgrade the exclusive locks. - Use MDL_SHARED_NO_WRITE as the intended - post effect of this call is identical - to LOCK TABLES <...> READ, and we didn't use - thd->in_lock_talbes and thd->sql_command= SQLCOM_LOCK_TABLES - hacks to enter the LTM. - @todo: release the global IX lock here!!! - */ - for (table_list= all_tables; table_list; - table_list= table_list->next_global) - table_list->mdl_request.ticket->downgrade_exclusive_lock(MDL_SHARED_NO_WRITE); - - return FALSE; - -error: - return TRUE; -} - - -/** Read query from packet and store in thd->query. Used in COM_QUERY and COM_STMT_PREPARE. @@ -2521,13 +2388,7 @@ case SQLCOM_PREPARE: } #endif - /* Set strategies: reset default or 'prepared' values. */ - create_table->open_strategy= TABLE_LIST::OPEN_IF_EXISTS; - create_table->lock_strategy= TABLE_LIST::OTLS_DOWNGRADE_IF_EXISTS; - - /* - Close any open handlers for the table - */ + /* Close any open handlers for the table. */ mysql_ha_rm_tables(thd, create_table); if (select_lex->item_list.elements) // With select @@ -2587,44 +2448,25 @@ case SQLCOM_PREPARE: goto end_with_restore_list; } - if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE)) - { - /* Base table and temporary table are not in the same name space. */ - create_table->open_type= OT_BASE_ONLY; - } - if (!(res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0))) { - /* - Is table which we are changing used somewhere in other parts - of query - */ - if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE)) + /* The table already exists */ + if (create_table->table) { - TABLE_LIST *duplicate; - if ((duplicate= unique_table(thd, create_table, select_tables, 0))) + if (create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS) { - update_non_unique_table_error(create_table, "CREATE", duplicate); - res= 1; - goto end_with_restore_list; + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR, + ER(ER_TABLE_EXISTS_ERROR), + create_info.alias); + my_ok(thd); } - } - /* If we create merge table, we have to test tables in merge, too */ - if (create_info.used_fields & HA_CREATE_USED_UNION) - { - TABLE_LIST *tab; - for (tab= create_info.merge_list.first; - tab; - tab= tab->next_local) + else { - TABLE_LIST *duplicate; - if ((duplicate= unique_table(thd, tab, select_tables, 0))) - { - update_non_unique_table_error(tab, "CREATE", duplicate); - res= 1; - goto end_with_restore_list; - } + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_info.alias); + res= 1; } + goto end_with_restore_list; } /* @@ -2657,7 +2499,7 @@ case SQLCOM_PREPARE: res= handle_select(thd, lex, result, 0); delete result; } - + lex->link_first_table_back(create_table, link_to_local); } } @@ -2762,77 +2604,6 @@ end_with_restore_list: } #endif /* HAVE_REPLICATION */ - case SQLCOM_ALTER_TABLE: - DBUG_ASSERT(first_table == all_tables && first_table != 0); - { - ulong priv=0; - ulong priv_needed= ALTER_ACL; - /* - Code in mysql_alter_table() may modify its HA_CREATE_INFO argument, - so we have to use a copy of this structure to make execution - prepared statement- safe. A shallow copy is enough as no memory - referenced from this structure will be modified. - */ - HA_CREATE_INFO create_info(lex->create_info); - Alter_info alter_info(lex->alter_info, thd->mem_root); - - if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */ - goto error; - /* - We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well - as for RENAME TO, as being done by SQLCOM_RENAME_TABLE - */ - if (alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME)) - priv_needed|= DROP_ACL; - - /* Must be set in the parser */ - DBUG_ASSERT(select_lex->db); - if (check_access(thd, priv_needed, first_table->db, - &first_table->grant.privilege, - &first_table->grant.m_internal, - 0, 0) || - check_access(thd, INSERT_ACL | CREATE_ACL, select_lex->db, - &priv, - NULL, /* Do not use first_table->grant with select_lex->db */ - 0, 0) || - check_merge_table_access(thd, first_table->db, - create_info.merge_list.first)) - goto error; /* purecov: inspected */ - if (check_grant(thd, priv_needed, all_tables, FALSE, UINT_MAX, FALSE)) - goto error; - if (lex->name.str && !test_all_bits(priv,INSERT_ACL | CREATE_ACL)) - { // Rename of table - TABLE_LIST tmp_table; - bzero((char*) &tmp_table,sizeof(tmp_table)); - tmp_table.table_name= lex->name.str; - tmp_table.db=select_lex->db; - tmp_table.grant.privilege=priv; - if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, FALSE, - UINT_MAX, FALSE)) - goto error; - } - - /* Don't yet allow changing of symlinks with ALTER TABLE */ - if (create_info.data_file_name) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED), - "DATA DIRECTORY"); - if (create_info.index_file_name) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED), - "INDEX DIRECTORY"); - create_info.data_file_name= create_info.index_file_name= NULL; - - thd->enable_slow_log= opt_log_slow_admin_statements; - res= mysql_alter_table(thd, select_lex->db, lex->name.str, - &create_info, - first_table, - &alter_info, - select_lex->order_list.elements, - select_lex->order_list.first, - lex->ignore); - break; - } case SQLCOM_RENAME_TABLE: { DBUG_ASSERT(first_table == all_tables && first_table != 0); @@ -2952,81 +2723,6 @@ end_with_restore_list: res = mysql_checksum_table(thd, first_table, &lex->check_opt); break; } - case SQLCOM_REPAIR: - { - DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, - FALSE, UINT_MAX, FALSE)) - goto error; /* purecov: inspected */ - thd->enable_slow_log= opt_log_slow_admin_statements; - res= mysql_repair_table(thd, first_table, &lex->check_opt); - /* ! we write after unlocking the table */ - if (!res && !lex->no_write_to_binlog) - { - /* - Presumably, REPAIR and binlog writing doesn't require synchronization - */ - res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); - } - select_lex->table_list.first= first_table; - lex->query_tables=all_tables; - break; - } - case SQLCOM_CHECK: - { - DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL, all_tables, - TRUE, UINT_MAX, FALSE)) - goto error; /* purecov: inspected */ - thd->enable_slow_log= opt_log_slow_admin_statements; - res = mysql_check_table(thd, first_table, &lex->check_opt); - select_lex->table_list.first= first_table; - lex->query_tables=all_tables; - break; - } - case SQLCOM_ANALYZE: - { - DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, - FALSE, UINT_MAX, FALSE)) - goto error; /* purecov: inspected */ - thd->enable_slow_log= opt_log_slow_admin_statements; - res= mysql_analyze_table(thd, first_table, &lex->check_opt); - /* ! we write after unlocking the table */ - if (!res && !lex->no_write_to_binlog) - { - /* - Presumably, ANALYZE and binlog writing doesn't require synchronization - */ - res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); - } - select_lex->table_list.first= first_table; - lex->query_tables=all_tables; - break; - } - - case SQLCOM_OPTIMIZE: - { - DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, - FALSE, UINT_MAX, FALSE)) - goto error; /* purecov: inspected */ - thd->enable_slow_log= opt_log_slow_admin_statements; - res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ? - mysql_recreate_table(thd, first_table) : - mysql_optimize_table(thd, first_table, &lex->check_opt); - /* ! we write after unlocking the table */ - if (!res && !lex->no_write_to_binlog) - { - /* - Presumably, OPTIMIZE and binlog writing doesn't require synchronization - */ - res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); - } - select_lex->table_list.first= first_table; - lex->query_tables=all_tables; - break; - } case SQLCOM_UPDATE: { ha_rows found= 0, updated= 0; @@ -3247,23 +2943,6 @@ end_with_restore_list: break; } - case SQLCOM_TRUNCATE: - DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_one_table_access(thd, DROP_ACL, all_tables)) - goto error; - /* - Don't allow this within a transaction because we want to use - re-generate table - */ - if (thd->in_active_multi_stmt_transaction()) - { - my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, - ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); - goto error; - } - if (! (res= mysql_truncate_table(thd, first_table))) - my_ok(thd); - break; case SQLCOM_DELETE: { DBUG_ASSERT(first_table == all_tables && first_table != 0); @@ -3345,7 +3024,7 @@ end_with_restore_list: /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ thd->variables.option_bits|= OPTION_KEEP_LOG; } - /* DDL and binlog write order protected by LOCK_open */ + /* DDL and binlog write order are protected by metadata locks. */ res= mysql_rm_table(thd, first_table, lex->drop_if_exists, lex->drop_temporary); } @@ -3898,6 +3577,10 @@ end_with_restore_list: if (first_table && lex->type & REFRESH_READ_LOCK) { + /* Check table-level privileges. */ + if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, + FALSE, UINT_MAX, FALSE)) + goto error; if (flush_tables_with_read_lock(thd, all_tables)) goto error; my_ok(thd); @@ -4657,6 +4340,14 @@ create_sp_error: my_ok(thd, 1); break; } + case SQLCOM_ANALYZE: + case SQLCOM_CHECK: + case SQLCOM_OPTIMIZE: + case SQLCOM_REPAIR: + case SQLCOM_TRUNCATE: + case SQLCOM_ALTER_TABLE: + DBUG_ASSERT(first_table == all_tables && first_table != 0); + /* fall through */ case SQLCOM_SIGNAL: case SQLCOM_RESIGNAL: DBUG_ASSERT(lex->m_stmt != NULL); @@ -6638,258 +6329,6 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields, /** - Reload/resets privileges and the different caches. - - @param thd Thread handler (can be NULL!) - @param options What should be reset/reloaded (tables, privileges, slave...) - @param tables Tables to flush (if any) - @param write_to_binlog True if we can write to the binlog. - - @note Depending on 'options', it may be very bad to write the - query to the binlog (e.g. FLUSH SLAVE); this is a - pointer where reload_acl_and_cache() will put 0 if - it thinks we really should not write to the binlog. - Otherwise it will put 1. - - @return Error status code - @retval 0 Ok - @retval !=0 Error; thd->killed is set or thd->is_error() is true -*/ - -bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, - bool *write_to_binlog) -{ - bool result=0; - select_errors=0; /* Write if more errors */ - bool tmp_write_to_binlog= 1; - - DBUG_ASSERT(!thd || !thd->in_sub_stmt); - -#ifndef NO_EMBEDDED_ACCESS_CHECKS - if (options & REFRESH_GRANT) - { - THD *tmp_thd= 0; - /* - If reload_acl_and_cache() is called from SIGHUP handler we have to - allocate temporary THD for execution of acl_reload()/grant_reload(). - */ - if (!thd && (thd= (tmp_thd= new THD))) - { - thd->thread_stack= (char*) &tmp_thd; - thd->store_globals(); - } - - if (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; - /* - 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; - /* Remember that we don't have a THD */ - my_pthread_setspecific_ptr(THR_THD, 0); - thd= 0; - } - reset_mqh((LEX_USER *)NULL, TRUE); - } -#endif - if (options & REFRESH_LOG) - { - /* - Flush the normal query log, the update log, the binary log, - the slow query log, the relay log (if it exists) and the log - tables. - */ - - options|= REFRESH_BINARY_LOG; - options|= REFRESH_RELAY_LOG; - options|= REFRESH_SLOW_LOG; - options|= REFRESH_GENERAL_LOG; - options|= REFRESH_ENGINE_LOG; - options|= REFRESH_ERROR_LOG; - } - - if (options & REFRESH_ERROR_LOG) - if (flush_error_log()) - result= 1; - - if ((options & REFRESH_SLOW_LOG) && opt_slow_log) - logger.flush_slow_log(); - - if ((options & REFRESH_GENERAL_LOG) && opt_log) - logger.flush_general_log(); - - if (options & REFRESH_ENGINE_LOG) - if (ha_flush_logs(NULL)) - result= 1; - - if (options & REFRESH_BINARY_LOG) - { - /* - Writing this command to the binlog may result in infinite loops - when doing mysqlbinlog|mysql, and anyway it does not really make - sense to log it automatically (would cause more trouble to users - than it would help them) - */ - tmp_write_to_binlog= 0; - if (mysql_bin_log.is_open()) - mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); - } - if (options & REFRESH_RELAY_LOG) - { -#ifdef HAVE_REPLICATION - mysql_mutex_lock(&LOCK_active_mi); - rotate_relay_log(active_mi); - mysql_mutex_unlock(&LOCK_active_mi); -#endif - } -#ifdef HAVE_QUERY_CACHE - if (options & REFRESH_QUERY_CACHE_FREE) - { - query_cache.pack(); // FLUSH QUERY CACHE - options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory - } - if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE)) - { - query_cache.flush(); // RESET QUERY CACHE - } -#endif /*HAVE_QUERY_CACHE*/ - - DBUG_ASSERT(!thd || thd->locked_tables_mode || - !thd->mdl_context.has_locks() || - thd->handler_tables_hash.records || - thd->global_read_lock.is_acquired()); - - /* - Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too - (see sql_yacc.yy) - */ - if (options & (REFRESH_TABLES | REFRESH_READ_LOCK)) - { - if ((options & REFRESH_READ_LOCK) && thd) - { - /* - On the first hand we need write lock on the tables to be flushed, - on the other hand we must not try to aspire a global read lock - if we have a write locked table as this would lead to a deadlock - when trying to reopen (and re-lock) the table after the flush. - */ - if (thd->locked_tables_mode) - { - my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); - return 1; - } - /* - Writing to the binlog could cause deadlocks, as we don't log - UNLOCK TABLES - */ - tmp_write_to_binlog= 0; - if (thd->global_read_lock.lock_global_read_lock(thd)) - return 1; // Killed - if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ? - FALSE : TRUE)) - result= 1; - - if (thd->global_read_lock.make_global_read_lock_block_commit(thd)) // Killed - { - /* Don't leave things in a half-locked state */ - thd->global_read_lock.unlock_global_read_lock(thd); - return 1; - } - } - else - { - if (thd && thd->locked_tables_mode) - { - /* - If we are under LOCK TABLES we should have a write - lock on tables which we are going to flush. - */ - if (tables) - { - for (TABLE_LIST *t= tables; t; t= t->next_local) - if (!find_table_for_mdl_upgrade(thd->open_tables, t->db, - t->table_name, FALSE)) - return 1; - } - else - { - for (TABLE *tab= thd->open_tables; tab; tab= tab->next) - { - if (! tab->mdl_ticket->is_upgradable_or_exclusive()) - { - my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), - tab->s->table_name.str); - return 1; - } - } - } - } - - if (close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ? - FALSE : TRUE)) - result= 1; - } - my_dbopt_cleanup(); - } - if (options & REFRESH_HOSTS) - hostname_cache_refresh(); - if (thd && (options & REFRESH_STATUS)) - refresh_status(thd); - if (options & REFRESH_THREADS) - flush_thread_cache(); -#ifdef HAVE_REPLICATION - if (options & REFRESH_MASTER) - { - DBUG_ASSERT(thd); - tmp_write_to_binlog= 0; - if (reset_master(thd)) - { - result=1; - } - } -#endif -#ifdef OPENSSL - if (options & REFRESH_DES_KEY_FILE) - { - if (des_key_file && load_des_key_file(des_key_file)) - result= 1; - } -#endif -#ifdef HAVE_REPLICATION - if (options & REFRESH_SLAVE) - { - tmp_write_to_binlog= 0; - mysql_mutex_lock(&LOCK_active_mi); - if (reset_slave(thd, active_mi)) - result=1; - mysql_mutex_unlock(&LOCK_active_mi); - } -#endif - if (options & REFRESH_USER_RESOURCES) - reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */ - *write_to_binlog= tmp_write_to_binlog; - /* - If the query was killed then this function must fail. - */ - return result || (thd ? thd->killed : 0); -} - - -/** kill on thread. @param thd Thread class @@ -7420,7 +6859,7 @@ void create_table_set_open_action_and_adjust_tables(LEX *lex) if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) create_table->open_type= OT_TEMPORARY_ONLY; - else if (!lex->select_lex.item_list.elements) + else create_table->open_type= OT_BASE_ONLY; if (!lex->select_lex.item_list.elements) @@ -7800,6 +7239,7 @@ bool parse_sql(THD *thd, { bool ret_value; DBUG_ASSERT(thd->m_parser_state == NULL); + DBUG_ASSERT(thd->lex->m_stmt == NULL); MYSQL_QUERY_PARSE_START(thd->query()); /* Backup creation context. */ |