Commit a8a75ba2 authored by Dave Gosselin's avatar Dave Gosselin Committed by Dave Gosselin

Factor TABLE_LIST creation from add_table_to_list

Ideally our methods and functions should do one thing, do that well,
and do only that.  add_table_to_list does far more than adding a
table to a list, so this commit factors the TABLE_LIST creation out
to a new TABLE_LIST constructor.  It then uses placement new()
to create it in the correct memory area (result of thd->calloc).
Benefits of this approach:
 1. add_table_to_list now returns as early as possible on an error
 2. fewer side-effects incurred on creating the TABLE_LIST object
 3. TABLE_LIST won't be calloc'd if copy_to_db fails
 4. local declarations moved closer to their respective first uses
 5. improved code readability and logical flow
Also factored a couple of other functions to keep the happy path
more to the left, which makes them easier to follow at a glance.
parent 8dda6027
......@@ -4832,24 +4832,24 @@ class THD: public THD_count, /* this must be first */
*/
bool copy_db_to(LEX_CSTRING *to)
{
if (db.str == NULL)
if (db.str)
{
/*
No default database is set. In this case if it's guaranteed that
no CTE can be used in the statement then we can throw an error right
now at the parser stage. Otherwise the decision about throwing such
a message must be postponed until a post-parser stage when we are able
to resolve all CTE names as we don't need this message to be thrown
for any CTE references.
*/
if (!lex->with_cte_resolution)
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
return TRUE;
to->str= strmake(db.str, db.length);
to->length= db.length;
return to->str == NULL; /* True on error */
}
to->str= strmake(db.str, db.length);
to->length= db.length;
return to->str == NULL; /* True on error */
/*
No default database is set. In this case if it's guaranteed that
no CTE can be used in the statement then we can throw an error right
now at the parser stage. Otherwise the decision about throwing such
a message must be postponed until a post-parser stage when we are able
to resolve all CTE names as we don't need this message to be thrown
for any CTE references.
*/
if (!lex->with_cte_resolution)
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
return TRUE;
}
/* Get db name or "". Use for printing current db */
const char *get_db()
......
......@@ -4290,17 +4290,18 @@ uint8 LEX::get_effective_with_check(TABLE_LIST *view)
bool LEX::copy_db_to(LEX_CSTRING *to)
{
if (sphead && sphead->m_name.str)
{
DBUG_ASSERT(sphead->m_db.str && sphead->m_db.length);
/*
It is safe to assign the string by-pointer, both sphead and
its statements reside in the same memory root.
*/
*to= sphead->m_db;
return FALSE;
}
return thd->copy_db_to(to);
if (!sphead || !sphead->m_name.str)
return thd->copy_db_to(to);
DBUG_ASSERT(sphead->m_db.str);
DBUG_ASSERT(sphead->m_db.length);
/*
It is safe to assign the string by-pointer, both sphead and
its statements reside in the same memory root.
*/
*to= sphead->m_db;
return FALSE;
}
/**
......
......@@ -8283,10 +8283,6 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
List<String> *partition_names,
LEX_STRING *option)
{
TABLE_LIST *ptr;
TABLE_LIST *UNINIT_VAR(previous_table_ref); /* The table preceding the current one. */
LEX_CSTRING alias_str;
LEX *lex= thd->lex;
DBUG_ENTER("add_table_to_list");
DBUG_PRINT("enter", ("Table '%s' (%p) Select %p (%u)",
(alias ? alias->str : table->table.str),
......@@ -8296,9 +8292,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
if (unlikely(!table))
DBUG_RETURN(0); // End of memory
alias_str= alias ? *alias : table->table;
DBUG_ASSERT(alias_str.str);
if (!MY_TEST(table_options & TL_OPTION_ALIAS) &&
if (!(table_options & TL_OPTION_ALIAS) &&
unlikely(check_table_name(table->table.str, table->table.length, FALSE)))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
......@@ -8313,6 +8307,34 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
DBUG_RETURN(0);
}
LEX_CSTRING db{0, 0};
bool fqtn= false;
LEX *lex= thd->lex;
if (table->db.str)
{
fqtn= TRUE;
db= table->db;
}
else if (!lex->with_cte_resolution && lex->copy_db_to(&db))
DBUG_RETURN(0);
else
fqtn= FALSE;
bool info_schema= is_infoschema_db(&db);
if (!table->sel && info_schema &&
(table_options & TL_OPTION_UPDATING) &&
/* Special cases which are processed by commands itself */
lex->sql_command != SQLCOM_CHECK &&
lex->sql_command != SQLCOM_CHECKSUM)
{
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
thd->security_ctx->priv_user,
thd->security_ctx->priv_host,
INFORMATION_SCHEMA_NAME.str);
DBUG_RETURN(0);
}
LEX_CSTRING alias_str= alias ? *alias : table->table;
DBUG_ASSERT(alias_str.str);
if (!alias) /* Alias is case sensitive */
{
if (unlikely(table->sel))
......@@ -8325,65 +8347,15 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
if (unlikely(!(alias_str.str= (char*) thd->memdup(alias_str.str, alias_str.length+1))))
DBUG_RETURN(0);
}
if (unlikely(!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST)))))
DBUG_RETURN(0); /* purecov: inspected */
if (table->db.str)
{
ptr->is_fqtn= TRUE;
ptr->db= table->db;
}
else if (!lex->with_cte_resolution && lex->copy_db_to(&ptr->db))
DBUG_RETURN(0);
else
ptr->is_fqtn= FALSE;
ptr->alias= alias_str;
ptr->is_alias= alias ? TRUE : FALSE;
if (lower_case_table_names)
{
if (table->table.length)
table->table.length= my_casedn_str(files_charset_info,
(char*) table->table.str);
if (ptr->db.length && ptr->db.str != any_db.str)
ptr->db.length= my_casedn_str(files_charset_info, (char*) ptr->db.str);
}
ptr->table_name= table->table;
ptr->lock_type= lock_type;
ptr->mdl_type= mdl_type;
ptr->table_options= table_options;
ptr->updating= MY_TEST(table_options & TL_OPTION_UPDATING);
/* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */
ptr->force_index= MY_TEST(table_options & TL_OPTION_FORCE_INDEX);
ptr->ignore_leaves= MY_TEST(table_options & TL_OPTION_IGNORE_LEAVES);
ptr->sequence= MY_TEST(table_options & TL_OPTION_SEQUENCE);
ptr->derived= table->sel;
if (!ptr->derived && is_infoschema_db(&ptr->db))
{
if (ptr->updating &&
/* Special cases which are processed by commands itself */
lex->sql_command != SQLCOM_CHECK &&
lex->sql_command != SQLCOM_CHECKSUM)
{
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
thd->security_ctx->priv_user,
thd->security_ctx->priv_host,
INFORMATION_SCHEMA_NAME.str);
DBUG_RETURN(0);
}
ST_SCHEMA_TABLE *schema_table;
schema_table= find_schema_table(thd, &ptr->table_name);
ptr->schema_table_name= ptr->table_name;
ptr->schema_table= schema_table;
}
ptr->select_lex= this;
/*
We can't cache internal temporary tables between prepares as the
table may be deleted before next exection.
*/
ptr->cacheable_table= !table->is_derived_table();
ptr->index_hints= index_hints_arg;
ptr->option= option ? option->str : 0;
bool has_alias_ptr= alias != nullptr;
void *memregion= thd->calloc(sizeof(TABLE_LIST));
TABLE_LIST *ptr= new (memregion) TABLE_LIST(thd, db, fqtn, alias_str,
has_alias_ptr, table, lock_type,
mdl_type, table_options,
info_schema, this,
index_hints_arg, option);
/* check that used name is unique. Sequences are ignored */
if (lock_type != TL_IGNORE && !ptr->sequence)
{
......@@ -8406,6 +8378,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
}
/* Store the table reference preceding the current one. */
TABLE_LIST *UNINIT_VAR(previous_table_ref); /* The table preceding the current one. */
if (table_list.elements > 0 && likely(!ptr->sequence))
{
/*
......
......@@ -49,6 +49,7 @@
#include "wsrep_schema.h"
#endif
#include "log_event.h" // MAX_TABLE_MAP_ID
#include "sql_class.h"
/* For MySQL 5.7 virtual fields */
#define MYSQL57_GENERATED_FIELD 128
......@@ -5850,6 +5851,59 @@ void TABLE::reset_item_list(List<Item> *item_list, uint skip) const
}
}
TABLE_LIST::TABLE_LIST(THD *thd,
LEX_CSTRING db_str,
bool fqtn,
LEX_CSTRING alias_str,
bool has_alias_ptr,
Table_ident *table_ident,
thr_lock_type lock_t,
enum_mdl_type mdl_t,
ulong table_opts,
bool info_schema,
st_select_lex *sel,
List<Index_hint> *index_hints_ptr,
LEX_STRING *option_ptr)
{
db= db_str;
is_fqtn= fqtn;
alias= alias_str;
is_alias= has_alias_ptr;
if (lower_case_table_names)
{
if (table_ident->table.length)
table_ident->table.length= my_casedn_str(files_charset_info,
(char*) table_ident->table.str);
if (db.length && db.str != any_db.str)
db.length= my_casedn_str(files_charset_info, (char*) db.str);
}
table_name= table_ident->table;
lock_type= lock_t;
mdl_type= mdl_t;
table_options= table_opts;
updating= table_options & TL_OPTION_UPDATING;
/* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */
force_index= table_options & TL_OPTION_FORCE_INDEX;
ignore_leaves= table_options & TL_OPTION_IGNORE_LEAVES;
sequence= table_options & TL_OPTION_SEQUENCE;
derived= table_ident->sel;
if (!table_ident->sel && info_schema)
{
schema_table= find_schema_table(thd, &table_name);
schema_table_name= table_name;
}
select_lex= sel;
/*
We can't cache internal temporary tables between prepares as the
table may be deleted before next exection.
*/
cacheable_table= !table_ident->is_derived_table();
index_hints= index_hints_ptr;
option= option_ptr ? option_ptr->str : 0;
}
/*
calculate md5 of query
......
......@@ -2175,8 +2175,23 @@ struct TABLE_CHAIN
void set_end_pos(TABLE_LIST **pos) { end_pos= pos; }
};
class Table_ident;
struct TABLE_LIST
{
TABLE_LIST(THD *thd,
LEX_CSTRING db_str,
bool fqtn,
LEX_CSTRING alias_str,
bool has_alias_ptr,
Table_ident *table_ident,
thr_lock_type lock_t,
enum_mdl_type mdl_t,
ulong table_opts,
bool info_schema,
st_select_lex *sel,
List<Index_hint> *index_hints_ptr,
LEX_STRING *option_ptr);
TABLE_LIST() = default; /* Remove gcc warning */
enum prelocking_types
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment