diff options
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 116 |
1 files changed, 82 insertions, 34 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3ca0c78d96a..7e58b36a939 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1238,6 +1238,7 @@ pthread_handler_t handle_bootstrap(void *arg) THD *thd=(THD*) arg; FILE *file=bootstrap_file; char *buff; + const char* found_semicolon= NULL; /* The following must be called before DBUG_ENTER */ thd->thread_stack= (char*) &thd; @@ -1314,7 +1315,7 @@ pthread_handler_t handle_bootstrap(void *arg) */ thd->query_id=next_query_id(); thd->set_time(); - mysql_parse(thd,thd->query,length); + mysql_parse(thd, thd->query, length, & found_semicolon); close_thread_tables(thd); // Free tables if (thd->is_fatal_error) @@ -1793,17 +1794,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd, char *packet_end= thd->query + thd->query_length; /* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */ const char *format= "%.*b"; + const char* found_semicolon= NULL; + mysql_log.write(thd,command, format, thd->query_length, thd->query); DBUG_PRINT("query",("%-.4096s",thd->query)); if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); - mysql_parse(thd,thd->query, thd->query_length); + mysql_parse(thd, thd->query, thd->query_length, & found_semicolon); - while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error) + while (!thd->killed && found_semicolon && !thd->net.report_error) { - char *next_packet= thd->lex->found_semicolon; + char *next_packet= (char*) found_semicolon; net->no_send_error= 0; /* Multiple queries exits, execute them individually @@ -1828,7 +1831,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->set_time(); /* Reset the query start time. */ /* TODO: set thd->lex->sql_command to SQLCOM_END here */ VOID(pthread_mutex_unlock(&LOCK_thread_count)); - mysql_parse(thd, next_packet, length); + mysql_parse(thd, next_packet, length, & found_semicolon); } if (!(specialflag & SPECIAL_NO_PRIOR)) @@ -1849,7 +1852,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, LEX_STRING conv_name; /* used as fields initializator */ - lex_start(thd, 0, 0); + lex_start(thd); statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS], &LOCK_status); @@ -1886,7 +1889,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; /* init structures for VIEW processing */ table_list.select_lex= &(thd->lex->select_lex); - mysql_init_query(thd, (uchar*)"", 0); + + lex_start(thd); + mysql_reset_thd_for_next_command(thd); + thd->lex-> select_lex.table_list.link_in_list((byte*) &table_list, (byte**) &table_list.next_local); @@ -3008,7 +3014,13 @@ mysql_execute_command(THD *thd) select_lex->options|= SELECT_NO_UNLOCK; unit->set_limit(select_lex); - if (!(res= open_and_lock_tables(thd, select_tables))) + if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) + { + lex->link_first_table_back(create_table, link_to_local); + create_table->create= TRUE; + } + + if (!(res= open_and_lock_tables(thd, lex->query_tables))) { /* Is table which we are changing used somewhere in other parts @@ -3017,6 +3029,7 @@ mysql_execute_command(THD *thd) if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE)) { TABLE_LIST *duplicate; + create_table= lex->unlink_first_table(&link_to_local); if ((duplicate= unique_table(thd, create_table, select_tables, 0))) { update_non_unique_table_error(create_table, "CREATE", duplicate); @@ -3060,6 +3073,9 @@ mysql_execute_command(THD *thd) delete sel_result; } } + else if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) + create_table= lex->unlink_first_table(&link_to_local); + } else { @@ -5775,20 +5791,6 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize) } -/**************************************************************************** - Initialize global thd variables needed for query -****************************************************************************/ - -void -mysql_init_query(THD *thd, uchar *buf, uint length) -{ - DBUG_ENTER("mysql_init_query"); - lex_start(thd, buf, length); - mysql_reset_thd_for_next_command(thd); - DBUG_VOID_RETURN; -} - - /* Reset THD part responsible for command processing state. @@ -5975,21 +5977,55 @@ void mysql_init_multi_delete(LEX *lex) mysql_test_parse_for_slave() in this same file. */ -void mysql_parse(THD *thd, char *inBuf, uint length) +/** + Parse a query. + @param thd Current thread + @param inBuf Begining of the query text + @param length Length of the query text + @param [out] semicolon For multi queries, position of the character of + the next query in the query text. +*/ + +void mysql_parse(THD *thd, const char *inBuf, uint length, + const char ** found_semicolon) { DBUG_ENTER("mysql_parse"); DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on();); - mysql_init_query(thd, (uchar*) inBuf, length); - if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) + /* + Warning. + The purpose of query_cache_send_result_to_client() is to lookup the + query in the query cache first, to avoid parsing and executing it. + So, the natural implementation would be to: + - first, call query_cache_send_result_to_client, + - second, if caching failed, initialise the lexical and syntactic parser. + The problem is that the query cache depends on a clean initialization + of (among others) lex->safe_to_cache_query and thd->server_status, + which are reset respectively in + - lex_start() + - mysql_reset_thd_for_next_command() + So, initializing the lexical analyser *before* using the query cache + is required for the cache to work properly. + FIXME: cleanup the dependencies in the code to simplify this. + */ + lex_start(thd); + mysql_reset_thd_for_next_command(thd); + + if (query_cache_send_result_to_client(thd, (char*) inBuf, length) <= 0) { LEX *lex= thd->lex; - + sp_cache_flush_obsolete(&thd->sp_proc_cache); sp_cache_flush_obsolete(&thd->sp_func_cache); - - if (!MYSQLparse((void *)thd) && ! thd->is_fatal_error) + + Lex_input_stream lip(thd, inBuf, length); + thd->m_lip= &lip; + + int err= MYSQLparse(thd); + *found_semicolon= lip.found_semicolon; + + if (!err && ! thd->is_fatal_error) { #ifndef NO_EMBEDDED_ACCESS_CHECKS if (mqh_used && thd->user_connect && @@ -6012,8 +6048,8 @@ void mysql_parse(THD *thd, char *inBuf, uint length) PROCESSLIST. Note that we don't need LOCK_thread_count to modify query_length. */ - if (lex->found_semicolon && - (thd->query_length= (ulong)(lex->found_semicolon - thd->query))) + if (lip.found_semicolon && + (thd->query_length= (ulong)(lip.found_semicolon - thd->query))) thd->query_length--; /* Actually execute the query */ mysql_execute_command(thd); @@ -6040,6 +6076,12 @@ void mysql_parse(THD *thd, char *inBuf, uint length) thd->cleanup_after_query(); DBUG_ASSERT(thd->change_list.is_empty()); } + else + { + /* There are no multi queries in the cache. */ + *found_semicolon= NULL; + } + DBUG_VOID_RETURN; } @@ -6060,8 +6102,13 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length) bool error= 0; DBUG_ENTER("mysql_test_parse_for_slave"); - mysql_init_query(thd, (uchar*) inBuf, length); - if (!MYSQLparse((void*) thd) && ! thd->is_fatal_error && + Lex_input_stream lip(thd, inBuf, length); + thd->m_lip= &lip; + lex_start(thd); + mysql_reset_thd_for_next_command(thd); + int err= MYSQLparse((void*) thd); + + if (!err && ! thd->is_fatal_error && all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first)) error= 1; /* Ignore question */ thd->end_statement(); @@ -7120,8 +7167,9 @@ bool check_simple_select() if (lex->current_select != &lex->select_lex) { char command[80]; - strmake(command, lex->yylval->symbol.str, - min(lex->yylval->symbol.length, sizeof(command)-1)); + Lex_input_stream *lip= thd->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); return 1; } |