mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
MDEV-5273 Prepared statement doesn't return metadata after prepare.
The metadata creation part of the mysqld_shww_create separated to be used on the mysqld_stmt_prepare stage.
This commit is contained in:
@@ -103,6 +103,7 @@ When one supplies long data for a placeholder:
|
|||||||
#include "sql_derived.h" // mysql_derived_prepare,
|
#include "sql_derived.h" // mysql_derived_prepare,
|
||||||
// mysql_handle_derived
|
// mysql_handle_derived
|
||||||
#include "sql_cursor.h"
|
#include "sql_cursor.h"
|
||||||
|
#include "sql_show.h"
|
||||||
#include "sp_head.h"
|
#include "sp_head.h"
|
||||||
#include "sp.h"
|
#include "sp.h"
|
||||||
#include "sp_cache.h"
|
#include "sp_cache.h"
|
||||||
@@ -1811,6 +1812,42 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Validate and prepare for execution CREATE TABLE statement.
|
||||||
|
|
||||||
|
@param stmt prepared statement
|
||||||
|
@param tables list of tables used in this query
|
||||||
|
|
||||||
|
@retval
|
||||||
|
FALSE success
|
||||||
|
@retval
|
||||||
|
TRUE error, error message is set in THD
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int mysql_test_show_create_table(Prepared_statement *stmt,
|
||||||
|
TABLE_LIST *tables)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("mysql_test_show_create_table");
|
||||||
|
THD *thd= stmt->thd;
|
||||||
|
List<Item> fields;
|
||||||
|
char buff[2048];
|
||||||
|
String buffer(buff, sizeof(buff), system_charset_info);
|
||||||
|
|
||||||
|
if (mysqld_show_create_get_fields(thd, tables, &fields, &buffer))
|
||||||
|
goto err_exit;
|
||||||
|
|
||||||
|
if (send_prep_stmt(stmt, fields.elements) ||
|
||||||
|
thd->protocol->send_result_set_metadata(&fields, Protocol::SEND_EOF) ||
|
||||||
|
thd->protocol->flush())
|
||||||
|
goto err_exit;
|
||||||
|
|
||||||
|
DBUG_RETURN(2);
|
||||||
|
|
||||||
|
err_exit:
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Validate and prepare for execution CREATE VIEW statement
|
@brief Validate and prepare for execution CREATE VIEW statement
|
||||||
|
|
||||||
@@ -2144,7 +2181,14 @@ static bool check_prepared_statement(Prepared_statement *stmt)
|
|||||||
case SQLCOM_CREATE_TABLE:
|
case SQLCOM_CREATE_TABLE:
|
||||||
res= mysql_test_create_table(stmt);
|
res= mysql_test_create_table(stmt);
|
||||||
break;
|
break;
|
||||||
|
case SQLCOM_SHOW_CREATE:
|
||||||
|
res= mysql_test_show_create_table(stmt, tables);
|
||||||
|
if (res == 2)
|
||||||
|
{
|
||||||
|
/* Statement and field info has already been sent */
|
||||||
|
DBUG_RETURN(FALSE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SQLCOM_CREATE_VIEW:
|
case SQLCOM_CREATE_VIEW:
|
||||||
if (lex->create_view_mode == VIEW_ALTER)
|
if (lex->create_view_mode == VIEW_ALTER)
|
||||||
{
|
{
|
||||||
|
168
sql/sql_show.cc
168
sql/sql_show.cc
@@ -1091,6 +1091,106 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Return metadata for CREATE command for table or view
|
||||||
|
|
||||||
|
@param thd Thread handler
|
||||||
|
@param table_list Table / view
|
||||||
|
@param field_list resulting list of fields
|
||||||
|
@param buffer resulting CREATE statement
|
||||||
|
|
||||||
|
@return
|
||||||
|
@retval 0 OK
|
||||||
|
@retval 1 Error
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool
|
||||||
|
mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list,
|
||||||
|
List<Item> *field_list, String *buffer)
|
||||||
|
{
|
||||||
|
bool error= TRUE;
|
||||||
|
MEM_ROOT *mem_root= thd->mem_root;
|
||||||
|
DBUG_ENTER("mysqld_show_create_get_fields");
|
||||||
|
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
|
||||||
|
table_list->table_name));
|
||||||
|
|
||||||
|
/* We want to preserve the tree for views. */
|
||||||
|
thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
|
||||||
|
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Use open_tables() directly rather than
|
||||||
|
open_normal_and_derived_tables(). This ensures that
|
||||||
|
close_thread_tables() is not called if open tables fails and the
|
||||||
|
error is ignored. This allows us to handle broken views nicely.
|
||||||
|
*/
|
||||||
|
uint counter;
|
||||||
|
Show_create_error_handler view_error_suppressor(thd, table_list);
|
||||||
|
thd->push_internal_handler(&view_error_suppressor);
|
||||||
|
bool open_error=
|
||||||
|
open_tables(thd, &table_list, &counter,
|
||||||
|
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL) ||
|
||||||
|
mysql_handle_derived(thd->lex, DT_PREPARE);
|
||||||
|
thd->pop_internal_handler();
|
||||||
|
if (open_error && (thd->killed || thd->is_error()))
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: add environment variables show when it become possible */
|
||||||
|
if (thd->lex->only_view && !table_list->view)
|
||||||
|
{
|
||||||
|
my_error(ER_WRONG_OBJECT, MYF(0),
|
||||||
|
table_list->db, table_list->table_name, "VIEW");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->length(0);
|
||||||
|
|
||||||
|
if (table_list->view)
|
||||||
|
buffer->set_charset(table_list->view_creation_ctx->get_client_cs());
|
||||||
|
|
||||||
|
if ((table_list->view ?
|
||||||
|
show_create_view(thd, table_list, buffer) :
|
||||||
|
show_create_table(thd, table_list, buffer, NULL, WITHOUT_DB_NAME)))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
if (table_list->view)
|
||||||
|
{
|
||||||
|
field_list->push_back(new (mem_root)
|
||||||
|
Item_empty_string(thd, "View", NAME_CHAR_LEN),
|
||||||
|
mem_root);
|
||||||
|
field_list->push_back(new (mem_root)
|
||||||
|
Item_empty_string(thd, "Create View",
|
||||||
|
MY_MAX(buffer->length(),1024)),
|
||||||
|
mem_root);
|
||||||
|
field_list->push_back(new (mem_root)
|
||||||
|
Item_empty_string(thd, "character_set_client",
|
||||||
|
MY_CS_NAME_SIZE),
|
||||||
|
mem_root);
|
||||||
|
field_list->push_back(new (mem_root)
|
||||||
|
Item_empty_string(thd, "collation_connection",
|
||||||
|
MY_CS_NAME_SIZE),
|
||||||
|
mem_root);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
field_list->push_back(new (mem_root)
|
||||||
|
Item_empty_string(thd, "Table", NAME_CHAR_LEN),
|
||||||
|
mem_root);
|
||||||
|
// 1024 is for not to confuse old clients
|
||||||
|
field_list->push_back(new (mem_root)
|
||||||
|
Item_empty_string(thd, "Create Table",
|
||||||
|
MY_MAX(buffer->length(),1024)),
|
||||||
|
mem_root);
|
||||||
|
}
|
||||||
|
error= FALSE;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
DBUG_RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return CREATE command for table or view
|
Return CREATE command for table or view
|
||||||
|
|
||||||
@@ -1125,75 +1225,9 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
|||||||
*/
|
*/
|
||||||
MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
|
MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
|
||||||
|
|
||||||
/* We want to preserve the tree for views. */
|
|
||||||
thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
|
|
||||||
|
|
||||||
{
|
if (mysqld_show_create_get_fields(thd, table_list, &field_list, &buffer))
|
||||||
/*
|
|
||||||
Use open_tables() directly rather than
|
|
||||||
open_normal_and_derived_tables(). This ensures that
|
|
||||||
close_thread_tables() is not called if open tables fails and the
|
|
||||||
error is ignored. This allows us to handle broken views nicely.
|
|
||||||
*/
|
|
||||||
uint counter;
|
|
||||||
Show_create_error_handler view_error_suppressor(thd, table_list);
|
|
||||||
thd->push_internal_handler(&view_error_suppressor);
|
|
||||||
bool open_error=
|
|
||||||
open_tables(thd, &table_list, &counter,
|
|
||||||
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL) ||
|
|
||||||
mysql_handle_derived(thd->lex, DT_PREPARE);
|
|
||||||
thd->pop_internal_handler();
|
|
||||||
if (open_error && (thd->killed || thd->is_error()))
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: add environment variables show when it become possible */
|
|
||||||
if (thd->lex->only_view && !table_list->view)
|
|
||||||
{
|
|
||||||
my_error(ER_WRONG_OBJECT, MYF(0),
|
|
||||||
table_list->db, table_list->table_name, "VIEW");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.length(0);
|
|
||||||
|
|
||||||
if (table_list->view)
|
|
||||||
buffer.set_charset(table_list->view_creation_ctx->get_client_cs());
|
|
||||||
|
|
||||||
if ((table_list->view ?
|
|
||||||
show_create_view(thd, table_list, &buffer) :
|
|
||||||
show_create_table(thd, table_list, &buffer, NULL, WITHOUT_DB_NAME)))
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
if (table_list->view)
|
|
||||||
{
|
|
||||||
field_list.push_back(new (mem_root)
|
|
||||||
Item_empty_string(thd, "View", NAME_CHAR_LEN),
|
|
||||||
mem_root);
|
|
||||||
field_list.push_back(new (mem_root)
|
|
||||||
Item_empty_string(thd, "Create View",
|
|
||||||
MY_MAX(buffer.length(),1024)),
|
|
||||||
mem_root);
|
|
||||||
field_list.push_back(new (mem_root)
|
|
||||||
Item_empty_string(thd, "character_set_client",
|
|
||||||
MY_CS_NAME_SIZE),
|
|
||||||
mem_root);
|
|
||||||
field_list.push_back(new (mem_root)
|
|
||||||
Item_empty_string(thd, "collation_connection",
|
|
||||||
MY_CS_NAME_SIZE),
|
|
||||||
mem_root);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
field_list.push_back(new (mem_root)
|
|
||||||
Item_empty_string(thd, "Table", NAME_CHAR_LEN),
|
|
||||||
mem_root);
|
|
||||||
// 1024 is for not to confuse old clients
|
|
||||||
field_list.push_back(new (mem_root)
|
|
||||||
Item_empty_string(thd, "Create Table",
|
|
||||||
MY_MAX(buffer.length(),1024)),
|
|
||||||
mem_root);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (protocol->send_result_set_metadata(&field_list,
|
if (protocol->send_result_set_metadata(&field_list,
|
||||||
Protocol::SEND_NUM_ROWS |
|
Protocol::SEND_NUM_ROWS |
|
||||||
|
@@ -85,6 +85,8 @@ bool append_identifier(THD *thd, String *packet, const char *name,
|
|||||||
uint length);
|
uint length);
|
||||||
void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
|
void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
|
||||||
int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
|
int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
|
||||||
|
bool mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list,
|
||||||
|
List<Item> *field_list, String *buffer);
|
||||||
bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
|
bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
|
||||||
bool mysqld_show_create_db(THD *thd, LEX_STRING *db_name,
|
bool mysqld_show_create_db(THD *thd, LEX_STRING *db_name,
|
||||||
LEX_STRING *orig_db_name,
|
LEX_STRING *orig_db_name,
|
||||||
|
@@ -422,6 +422,15 @@ static void test_prepare_simple()
|
|||||||
|
|
||||||
mysql_stmt_close(stmt);
|
mysql_stmt_close(stmt);
|
||||||
|
|
||||||
|
/* show create */
|
||||||
|
strmov(query, "SHOW CREATE TABLE test_prepare_simple");
|
||||||
|
stmt= mysql_simple_prepare(mysql, query);
|
||||||
|
check_stmt(stmt);
|
||||||
|
|
||||||
|
DIE_UNLESS(mysql_stmt_field_count(stmt) == 2);
|
||||||
|
|
||||||
|
mysql_stmt_close(stmt);
|
||||||
|
|
||||||
/* now fetch the results ..*/
|
/* now fetch the results ..*/
|
||||||
rc= mysql_commit(mysql);
|
rc= mysql_commit(mysql);
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
Reference in New Issue
Block a user