mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge with 5.2.
no_error handling for select (used by INSERT ... SELECT) still needs to be fixed, but I will do that in a separate commit
This commit is contained in:
357
sql/sql_show.cc
357
sql/sql_show.cc
@ -739,12 +739,30 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Return CREATE command for table or view
|
||||
|
||||
@param thd Thread handler
|
||||
@param table_list Table / view
|
||||
|
||||
@return
|
||||
@retval 0 OK
|
||||
@retval 1 Error
|
||||
|
||||
@notes
|
||||
table_list->db and table_list->table_name are kept unchanged to
|
||||
not cause problems with SP.
|
||||
*/
|
||||
|
||||
bool
|
||||
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
||||
{
|
||||
Protocol *protocol= thd->protocol;
|
||||
char buff[2048];
|
||||
String buffer(buff, sizeof(buff), system_charset_info);
|
||||
char *save_db, *save_table_name;
|
||||
bool retval= TRUE; // Assume error
|
||||
List<Item> field_list;
|
||||
DBUG_ENTER("mysqld_show_create");
|
||||
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
|
||||
table_list->table_name));
|
||||
@ -752,6 +770,10 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
||||
/* We want to preserve the tree for views. */
|
||||
thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
|
||||
|
||||
/* Store original names if called from SP */
|
||||
save_db= table_list->db;
|
||||
save_table_name= table_list->table_name;
|
||||
|
||||
{
|
||||
Show_create_error_handler view_error_suppressor(thd, table_list);
|
||||
thd->push_internal_handler(&view_error_suppressor);
|
||||
@ -759,7 +781,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
||||
DT_PREPARE | DT_CREATE);
|
||||
thd->pop_internal_handler();
|
||||
if (error && (thd->killed || thd->main_da.is_error()))
|
||||
DBUG_RETURN(TRUE);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* TODO: add environment variables show when it become possible */
|
||||
@ -767,7 +789,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
||||
{
|
||||
my_error(ER_WRONG_OBJECT, MYF(0),
|
||||
table_list->db, table_list->table_name, "VIEW");
|
||||
DBUG_RETURN(TRUE);
|
||||
goto error;
|
||||
}
|
||||
|
||||
buffer.length(0);
|
||||
@ -779,9 +801,8 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
||||
view_store_create_info(thd, table_list, &buffer) :
|
||||
store_create_info(thd, table_list, &buffer, NULL,
|
||||
FALSE /* show_database */)))
|
||||
DBUG_RETURN(TRUE);
|
||||
goto error;
|
||||
|
||||
List<Item> field_list;
|
||||
if (table_list->view)
|
||||
{
|
||||
field_list.push_back(new Item_empty_string("View",NAME_CHAR_LEN));
|
||||
@ -802,7 +823,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
||||
|
||||
if (protocol->send_fields(&field_list,
|
||||
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
|
||||
DBUG_RETURN(TRUE);
|
||||
goto error;
|
||||
protocol->prepare_for_resend();
|
||||
if (table_list->view)
|
||||
protocol->store(table_list->view_name.str, system_charset_info);
|
||||
@ -830,10 +851,17 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
||||
protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
|
||||
|
||||
if (protocol->write())
|
||||
DBUG_RETURN(TRUE);
|
||||
goto error;
|
||||
|
||||
my_eof(thd);
|
||||
DBUG_RETURN(FALSE);
|
||||
retval= FALSE; // ok
|
||||
|
||||
error:
|
||||
/* Restore table list if called by stored procedure */
|
||||
table_list->db= save_db;
|
||||
table_list->table_name= save_table_name;
|
||||
DBUG_RETURN(retval);
|
||||
|
||||
}
|
||||
|
||||
bool mysqld_show_create_db(THD *thd, char *dbname,
|
||||
@ -2870,12 +2898,11 @@ bool schema_table_store_record(THD *thd, TABLE *table)
|
||||
}
|
||||
|
||||
|
||||
int make_table_list(THD *thd, SELECT_LEX *sel,
|
||||
LEX_STRING *db_name, LEX_STRING *table_name)
|
||||
static int make_table_list(THD *thd, SELECT_LEX *sel,
|
||||
LEX_STRING *db_name, LEX_STRING *table_name)
|
||||
{
|
||||
Table_ident *table_ident;
|
||||
table_ident= new Table_ident(thd, *db_name, *table_name, 1);
|
||||
sel->init_query();
|
||||
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
|
||||
return 1;
|
||||
return 0;
|
||||
@ -3445,43 +3472,111 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
|
||||
|
||||
|
||||
/**
|
||||
@brief Fill I_S table for SHOW COLUMNS|INDEX commands
|
||||
Fill I_S table with data obtained by performing full-blown table open.
|
||||
|
||||
@param[in] thd thread handler
|
||||
@param[in] tables TABLE_LIST for I_S table
|
||||
@param[in] schema_table pointer to I_S structure
|
||||
@param[in] open_tables_state_backup pointer to Open_tables_state object
|
||||
which is used to save|restore original
|
||||
status of variables related to
|
||||
open tables state
|
||||
@param thd Thread handler.
|
||||
@param is_show_fields_or_keys Indicates whether it is a legacy SHOW
|
||||
COLUMNS or SHOW KEYS statement.
|
||||
@param table TABLE object for I_S table to be filled.
|
||||
@param schema_table I_S table description structure.
|
||||
@param orig_db_name Database name.
|
||||
@param orig_table_name Table name.
|
||||
@param open_tables_state_backup Open_tables_state object which is used
|
||||
to save/restore original status of
|
||||
variables related to open tables state.
|
||||
|
||||
@return Operation status
|
||||
@retval 0 success
|
||||
@retval 1 error
|
||||
@retval FALSE - Success.
|
||||
@retval TRUE - Failure.
|
||||
*/
|
||||
|
||||
static int
|
||||
fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
|
||||
ST_SCHEMA_TABLE *schema_table,
|
||||
Open_tables_state *open_tables_state_backup)
|
||||
static bool
|
||||
fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
|
||||
TABLE *table, ST_SCHEMA_TABLE *schema_table,
|
||||
LEX_STRING *orig_db_name,
|
||||
LEX_STRING *orig_table_name,
|
||||
Open_tables_state *open_tables_state_backup)
|
||||
{
|
||||
LEX *lex= thd->lex;
|
||||
bool res;
|
||||
LEX_STRING tmp_lex_string, tmp_lex_string1, *db_name, *table_name;
|
||||
enum_sql_command save_sql_command= lex->sql_command;
|
||||
TABLE_LIST *show_table_list= tables->schema_select_lex->table_list.first;
|
||||
TABLE *table= tables->table;
|
||||
int error= 1;
|
||||
DBUG_ENTER("fill_schema_show");
|
||||
Query_arena i_s_arena(thd->mem_root,
|
||||
Query_arena::CONVENTIONAL_EXECUTION),
|
||||
backup_arena, *old_arena;
|
||||
LEX *old_lex= thd->lex, temp_lex, *lex;
|
||||
LEX_STRING db_name, table_name;
|
||||
TABLE_LIST *table_list;
|
||||
bool result= true;
|
||||
DBUG_ENTER("fill_schema_table_by_open");
|
||||
|
||||
lex->all_selects_list= tables->schema_select_lex;
|
||||
/*
|
||||
Restore thd->temporary_tables to be able to process
|
||||
temporary tables(only for 'show index' & 'show columns').
|
||||
This should be changed when processing of temporary tables for
|
||||
I_S tables will be done.
|
||||
When a view is opened its structures are allocated on a permanent
|
||||
statement arena and linked into the LEX tree for the current statement
|
||||
(this happens even in cases when view is handled through TEMPTABLE
|
||||
algorithm).
|
||||
|
||||
To prevent this process from unnecessary hogging of memory in the permanent
|
||||
arena of our I_S query and to avoid damaging its LEX we use temporary
|
||||
arena and LEX for table/view opening.
|
||||
|
||||
Use temporary arena instead of statement permanent arena. Also make
|
||||
it active arena and save original one for successive restoring.
|
||||
*/
|
||||
thd->temporary_tables= open_tables_state_backup->temporary_tables;
|
||||
old_arena= thd->stmt_arena;
|
||||
thd->stmt_arena= &i_s_arena;
|
||||
thd->set_n_backup_active_arena(&i_s_arena, &backup_arena);
|
||||
|
||||
/* Prepare temporary LEX. */
|
||||
thd->lex= lex= &temp_lex;
|
||||
lex_start(thd);
|
||||
|
||||
/* Disable constant subquery evaluation as we won't be locking tables. */
|
||||
lex->context_analysis_only= CONTEXT_ANALYSIS_ONLY_VIEW;
|
||||
|
||||
/*
|
||||
Some of process_table() functions rely on wildcard being passed from
|
||||
old LEX (or at least being initialized).
|
||||
*/
|
||||
lex->wild= old_lex->wild;
|
||||
|
||||
/*
|
||||
Since make_table_list() might change database and table name passed
|
||||
to it we create copies of orig_db_name and orig_table_name here.
|
||||
These copies are used for make_table_list() while unaltered values
|
||||
are passed to process_table() functions.
|
||||
*/
|
||||
if (!thd->make_lex_string(&db_name, orig_db_name->str,
|
||||
orig_db_name->length, FALSE) ||
|
||||
!thd->make_lex_string(&table_name, orig_table_name->str,
|
||||
orig_table_name->length, FALSE))
|
||||
goto end;
|
||||
|
||||
/*
|
||||
Create table list element for table to be open. Link it with the
|
||||
temporary LEX. The latter is required to correctly open views and
|
||||
produce table describing their structure.
|
||||
*/
|
||||
if (make_table_list(thd, &lex->select_lex, &db_name, &table_name))
|
||||
goto end;
|
||||
|
||||
table_list= lex->select_lex.table_list.first;
|
||||
|
||||
if (is_show_fields_or_keys)
|
||||
{
|
||||
/*
|
||||
Restore thd->temporary_tables to be able to process
|
||||
temporary tables (only for 'show index' & 'show columns').
|
||||
This should be changed when processing of temporary tables for
|
||||
I_S tables will be done.
|
||||
*/
|
||||
thd->temporary_tables= open_tables_state_backup->temporary_tables;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Apply optimization flags for table opening which are relevant for
|
||||
this I_S table. We can't do this for SHOW COLUMNS/KEYS because of
|
||||
backward compatibility.
|
||||
*/
|
||||
table_list->i_s_requested_object= schema_table->i_s_requested_object;
|
||||
}
|
||||
|
||||
/*
|
||||
Let us set fake sql_command so views won't try to merge
|
||||
themselves into main statement. If we don't do this,
|
||||
@ -3489,36 +3584,66 @@ fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
|
||||
SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()'
|
||||
*/
|
||||
lex->sql_command= SQLCOM_SHOW_FIELDS;
|
||||
res= (open_normal_and_derived_tables(thd, show_table_list,
|
||||
MYSQL_LOCK_IGNORE_FLUSH,
|
||||
DT_PREPARE | DT_CREATE));
|
||||
lex->sql_command= save_sql_command;
|
||||
result= open_normal_and_derived_tables(thd, table_list,
|
||||
MYSQL_LOCK_IGNORE_FLUSH,
|
||||
DT_PREPARE | DT_CREATE);
|
||||
/*
|
||||
get_all_tables() returns 1 on failure and 0 on success thus
|
||||
return only these and not the result code of ::process_table()
|
||||
|
||||
We should use show_table_list->alias instead of
|
||||
show_table_list->table_name because table_name
|
||||
could be changed during opening of I_S tables. It's safe
|
||||
to use alias because alias contains original table name
|
||||
in this case(this part of code is used only for
|
||||
'show columns' & 'show statistics' commands).
|
||||
Restore old value of sql_command back as it is being looked at in
|
||||
process_table() function.
|
||||
*/
|
||||
table_name= thd->make_lex_string(&tmp_lex_string1, show_table_list->alias,
|
||||
strlen(show_table_list->alias), FALSE);
|
||||
if (!show_table_list->view)
|
||||
db_name= thd->make_lex_string(&tmp_lex_string, show_table_list->db,
|
||||
show_table_list->db_length, FALSE);
|
||||
else
|
||||
db_name= &show_table_list->view_db;
|
||||
lex->sql_command= old_lex->sql_command;
|
||||
|
||||
/*
|
||||
XXX: show_table_list has a flag i_is_requested,
|
||||
and when it's set, open_normal_and_derived_tables()
|
||||
can return an error without setting an error message
|
||||
in THD, which is a hack. This is why we have to
|
||||
check for res, then for thd->is_error() and only then
|
||||
for thd->main_da.sql_errno().
|
||||
|
||||
error= test(schema_table->process_table(thd, show_table_list,
|
||||
table, res, db_name,
|
||||
table_name));
|
||||
thd->temporary_tables= 0;
|
||||
close_tables_for_reopen(thd, &show_table_list);
|
||||
DBUG_RETURN(error);
|
||||
Again we don't do this for SHOW COLUMNS/KEYS because
|
||||
of backward compatibility.
|
||||
*/
|
||||
if (!is_show_fields_or_keys && result && thd->is_error() &&
|
||||
thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
|
||||
{
|
||||
/*
|
||||
Hide error for a non-existing table.
|
||||
For example, this error can occur when we use a where condition
|
||||
with a db name and table, but the table does not exist.
|
||||
*/
|
||||
result= 0;
|
||||
thd->clear_error();
|
||||
}
|
||||
else
|
||||
{
|
||||
result= schema_table->process_table(thd, table_list,
|
||||
table, result,
|
||||
orig_db_name,
|
||||
orig_table_name);
|
||||
}
|
||||
|
||||
end:
|
||||
lex->unit.cleanup();
|
||||
|
||||
/* Restore original LEX value, statement's arena and THD arena values. */
|
||||
lex_end(thd->lex);
|
||||
|
||||
if (i_s_arena.free_list)
|
||||
i_s_arena.free_items();
|
||||
|
||||
/*
|
||||
For safety reset list of open temporary tables before closing
|
||||
all tables open within this Open_tables_state.
|
||||
*/
|
||||
thd->temporary_tables= NULL;
|
||||
close_thread_tables(thd);
|
||||
thd->lex= old_lex;
|
||||
|
||||
thd->stmt_arena= old_arena;
|
||||
thd->restore_active_arena(&i_s_arena, &backup_arena);
|
||||
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
|
||||
@ -3743,11 +3868,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
{
|
||||
LEX *lex= thd->lex;
|
||||
TABLE *table= tables->table;
|
||||
SELECT_LEX *old_all_select_lex= lex->all_selects_list;
|
||||
enum_sql_command save_sql_command= lex->sql_command;
|
||||
SELECT_LEX *lsel= tables->schema_select_lex;
|
||||
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
|
||||
SELECT_LEX sel;
|
||||
LOOKUP_FIELD_VALUES lookup_field_vals;
|
||||
LEX_STRING *db_name, *table_name;
|
||||
bool with_i_schema;
|
||||
@ -3755,19 +3877,14 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
List<LEX_STRING> db_names;
|
||||
List_iterator_fast<LEX_STRING> it(db_names);
|
||||
COND *partial_cond= 0;
|
||||
uint derived_tables= lex->derived_tables;
|
||||
int error= 1;
|
||||
Open_tables_state open_tables_state_backup;
|
||||
uint8 save_context_analysis_only= lex->context_analysis_only;
|
||||
Query_tables_list query_tables_list_backup;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
Security_context *sctx= thd->security_ctx;
|
||||
#endif
|
||||
uint table_open_method;
|
||||
DBUG_ENTER("get_all_tables");
|
||||
|
||||
lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
|
||||
|
||||
/*
|
||||
We should not introduce deadlocks even if we already have some
|
||||
tables open and locked, since we won't lock tables which we will
|
||||
@ -3782,8 +3899,18 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
*/
|
||||
if (lsel && lsel->table_list.first)
|
||||
{
|
||||
error= fill_schema_show_cols_or_idxs(thd, tables, schema_table,
|
||||
&open_tables_state_backup);
|
||||
LEX_STRING db_name, table_name;
|
||||
|
||||
db_name.str= lsel->table_list.first->db;
|
||||
db_name.length= lsel->table_list.first->db_length;
|
||||
|
||||
table_name.str= lsel->table_list.first->table_name;
|
||||
table_name.length= lsel->table_list.first->table_name_length;
|
||||
|
||||
error= fill_schema_table_by_open(thd, TRUE,
|
||||
table, schema_table,
|
||||
&db_name, &table_name,
|
||||
&open_tables_state_backup);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -3841,15 +3968,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
it.rewind(); /* To get access to new elements in basis list */
|
||||
while ((db_name= it++))
|
||||
{
|
||||
LEX_STRING orig_db_name;
|
||||
|
||||
/*
|
||||
db_name can be changed in make_table_list() func.
|
||||
We need copy of db_name because it can change case.
|
||||
*/
|
||||
if (!thd->make_lex_string(&orig_db_name, db_name->str,
|
||||
db_name->length, FALSE))
|
||||
goto err;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (!(check_access(thd,SELECT_ACL, db_name->str,
|
||||
&thd->col_access, 0, 1, with_i_schema) ||
|
||||
@ -3907,6 +4025,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
!with_i_schema)
|
||||
{
|
||||
my_bool res;
|
||||
uint8 save_context_analysis_only= lex->context_analysis_only;
|
||||
lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
|
||||
res= fill_schema_table_from_frm(thd, table, schema_table,
|
||||
db_name,
|
||||
@ -3916,65 +4035,13 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
continue;
|
||||
}
|
||||
|
||||
int res;
|
||||
LEX_STRING tmp_lex_string;
|
||||
/*
|
||||
Set the parent lex of 'sel' because it is needed by
|
||||
sel.init_query() which is called inside make_table_list.
|
||||
*/
|
||||
thd->no_warnings_for_error= 1;
|
||||
sel.parent_lex= lex;
|
||||
if (make_table_list(thd, &sel, db_name, table_name))
|
||||
goto err;
|
||||
TABLE_LIST *show_table_list= sel.table_list.first;
|
||||
lex->all_selects_list= &sel;
|
||||
lex->derived_tables= 0;
|
||||
lex->sql_command= SQLCOM_SHOW_FIELDS;
|
||||
show_table_list->i_s_requested_object=
|
||||
schema_table->i_s_requested_object;
|
||||
|
||||
DEBUG_SYNC(thd, "before_open_in_get_all_tables");
|
||||
res= (open_normal_and_derived_tables(thd, show_table_list,
|
||||
MYSQL_LOCK_IGNORE_FLUSH,
|
||||
DT_PREPARE | DT_CREATE));
|
||||
lex->sql_command= save_sql_command;
|
||||
/*
|
||||
XXX: show_table_list has a flag i_is_requested,
|
||||
and when it's set, open_normal_and_derived_tables()
|
||||
can return an error without setting an error message
|
||||
in THD, which is a hack. This is why we have to
|
||||
check for res, then for thd->is_error() only then
|
||||
for thd->main_da.sql_errno().
|
||||
*/
|
||||
if (res && thd->is_error() &&
|
||||
thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
|
||||
{
|
||||
/*
|
||||
Hide error for not existing table.
|
||||
This error can occur for example when we use
|
||||
where condition with db name and table name and this
|
||||
table does not exist.
|
||||
*/
|
||||
res= 0;
|
||||
thd->clear_error();
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
We should use show_table_list->alias instead of
|
||||
show_table_list->table_name because table_name
|
||||
could be changed during opening of I_S tables. It's safe
|
||||
to use alias because alias contains original table name
|
||||
in this case.
|
||||
*/
|
||||
thd->make_lex_string(&tmp_lex_string, show_table_list->alias,
|
||||
strlen(show_table_list->alias), FALSE);
|
||||
res= schema_table->process_table(thd, show_table_list, table,
|
||||
res, &orig_db_name,
|
||||
&tmp_lex_string);
|
||||
close_tables_for_reopen(thd, &show_table_list);
|
||||
}
|
||||
DBUG_ASSERT(!lex->query_tables_own_last);
|
||||
if (res)
|
||||
if (fill_schema_table_by_open(thd, FALSE,
|
||||
table, schema_table,
|
||||
db_name, table_name,
|
||||
&open_tables_state_backup))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@ -3990,11 +4057,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
error= 0;
|
||||
err:
|
||||
thd->restore_backup_open_tables_state(&open_tables_state_backup);
|
||||
lex->restore_backup_query_tables_list(&query_tables_list_backup);
|
||||
lex->derived_tables= derived_tables;
|
||||
lex->all_selects_list= old_all_select_lex;
|
||||
lex->context_analysis_only= save_context_analysis_only;
|
||||
lex->sql_command= save_sql_command;
|
||||
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
@ -7829,7 +7892,7 @@ static TABLE_LIST *get_trigger_table_impl(
|
||||
|
||||
if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST))))
|
||||
{
|
||||
my_error(ER_OUTOFMEMORY, MYF(0), sizeof(TABLE_LIST));
|
||||
my_error(ER_OUTOFMEMORY, MYF(0), static_cast<int>(sizeof(TABLE_LIST)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user