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,8 +4832,13 @@ class THD: public THD_count, /* this must be first */
*/
bool copy_db_to(LEX_CSTRING *to)
{
if (db.str == NULL)
if (db.str)
{
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
......@@ -4846,11 +4851,6 @@ class THD: public THD_count, /* this must be first */
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 */
}
/* Get db name or "". Use for printing current db */
const char *get_db()
{ return safe_str(db.str); }
......
......@@ -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);
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;
}
return thd->copy_db_to(to);
}
/**
......
......@@ -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,54 +8307,21 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
DBUG_RETURN(0);
}
if (!alias) /* Alias is case sensitive */
{
if (unlikely(table->sel))
{
my_message(ER_DERIVED_MUST_HAVE_ALIAS,
ER_THD(thd, ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
DBUG_RETURN(0);
}
/* alias_str points to table->table; Let's make a copy */
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 */
LEX_CSTRING db{0, 0};
bool fqtn= false;
LEX *lex= thd->lex;
if (table->db.str)
{
ptr->is_fqtn= TRUE;
ptr->db= table->db;
fqtn= TRUE;
db= table->db;
}
else if (!lex->with_cte_resolution && lex->copy_db_to(&ptr->db))
else if (!lex->with_cte_resolution && lex->copy_db_to(&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 &&
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)
......@@ -8371,19 +8332,30 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
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;
LEX_CSTRING alias_str= alias ? *alias : table->table;
DBUG_ASSERT(alias_str.str);
if (!alias) /* Alias is case sensitive */
{
if (unlikely(table->sel))
{
my_message(ER_DERIVED_MUST_HAVE_ALIAS,
ER_THD(thd, ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
DBUG_RETURN(0);
}
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;
/* alias_str points to table->table; Let's make a copy */
if (unlikely(!(alias_str.str= (char*) thd->memdup(alias_str.str, alias_str.length+1))))
DBUG_RETURN(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