MXS-1364 Collect function column access in qc_mysqlembedded
Initial support, more updates will be needed.
This commit is contained in:
@ -1786,7 +1786,18 @@ static void parsing_info_done(void* ptr)
|
|||||||
|
|
||||||
for (size_t i = 0; i < pi->function_infos_len; ++i)
|
for (size_t i = 0; i < pi->function_infos_len; ++i)
|
||||||
{
|
{
|
||||||
free(pi->function_infos[i].name);
|
QC_FUNCTION_INFO& fi = pi->function_infos[i];
|
||||||
|
|
||||||
|
free(fi.name);
|
||||||
|
|
||||||
|
for (size_t j = 0; j < fi.n_fields; ++j)
|
||||||
|
{
|
||||||
|
QC_FIELD_NAME& field = fi.fields[j];
|
||||||
|
|
||||||
|
free(field.database);
|
||||||
|
free(field.table);
|
||||||
|
free(field.column);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(pi->function_infos);
|
free(pi->function_infos);
|
||||||
|
|
||||||
@ -2184,6 +2195,45 @@ static bool should_exclude(const char* name, List<Item>* excludep)
|
|||||||
return exclude;
|
return exclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void unalias_names(st_select_lex* select,
|
||||||
|
const char* from_database,
|
||||||
|
const char* from_table,
|
||||||
|
const char** to_database,
|
||||||
|
const char** to_table)
|
||||||
|
{
|
||||||
|
*to_database = from_database;
|
||||||
|
*to_table = from_table;
|
||||||
|
|
||||||
|
if (!from_database && from_table)
|
||||||
|
{
|
||||||
|
st_select_lex* s = select;
|
||||||
|
|
||||||
|
while ((*to_table == from_table) && s)
|
||||||
|
{
|
||||||
|
TABLE_LIST* tbl = s->table_list.first;
|
||||||
|
|
||||||
|
while ((*to_table == from_table) && tbl)
|
||||||
|
{
|
||||||
|
if (tbl->alias &&
|
||||||
|
(strcasecmp(tbl->alias, from_table) == 0) &&
|
||||||
|
(strcasecmp(tbl->table_name, "*") != 0))
|
||||||
|
{
|
||||||
|
// The dummy default database "skygw_virtual" is not included.
|
||||||
|
if (tbl->db && *tbl->db && (strcmp(tbl->db, "skygw_virtual") != 0))
|
||||||
|
{
|
||||||
|
*to_database = (char*)tbl->db;
|
||||||
|
}
|
||||||
|
*to_table = (char*)tbl->table_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbl = tbl->next_local;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = s->outer_select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void add_field_info(parsing_info_t* info,
|
static void add_field_info(parsing_info_t* info,
|
||||||
st_select_lex* select,
|
st_select_lex* select,
|
||||||
const char* database,
|
const char* database,
|
||||||
@ -2194,37 +2244,10 @@ static void add_field_info(parsing_info_t* info,
|
|||||||
{
|
{
|
||||||
ss_dassert(column);
|
ss_dassert(column);
|
||||||
|
|
||||||
|
unalias_names(select, database, table, &database, &table);
|
||||||
|
|
||||||
QC_FIELD_INFO item = { (char*)database, (char*)table, (char*)column, usage };
|
QC_FIELD_INFO item = { (char*)database, (char*)table, (char*)column, usage };
|
||||||
|
|
||||||
if (!database && table)
|
|
||||||
{
|
|
||||||
st_select_lex* s = select;
|
|
||||||
|
|
||||||
while ((item.table == table) && s)
|
|
||||||
{
|
|
||||||
TABLE_LIST* tbl = s->table_list.first;
|
|
||||||
|
|
||||||
while ((item.table == table) && tbl)
|
|
||||||
{
|
|
||||||
if (tbl->alias &&
|
|
||||||
(strcmp(tbl->alias, table) == 0) &&
|
|
||||||
(strcmp(tbl->table_name, "*") != 0))
|
|
||||||
{
|
|
||||||
// The dummy default database "skygw_virtual" is not included.
|
|
||||||
if (tbl->db && *tbl->db && (strcmp(tbl->db, "skygw_virtual") != 0))
|
|
||||||
{
|
|
||||||
item.database = (char*)tbl->db;
|
|
||||||
}
|
|
||||||
item.table = (char*)tbl->table_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
tbl = tbl->next_local;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = s->outer_select();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < info->field_infos_len; ++i)
|
for (i = 0; i < info->field_infos_len; ++i)
|
||||||
{
|
{
|
||||||
@ -2302,9 +2325,183 @@ static void add_field_info(parsing_info_t* info,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void add_function_field_usage(const char* database,
|
||||||
|
const char* table,
|
||||||
|
const char* column,
|
||||||
|
QC_FUNCTION_INFO* fi)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
uint32_t i = 0;
|
||||||
|
|
||||||
|
while (!found && (i < fi->n_fields))
|
||||||
|
{
|
||||||
|
QC_FIELD_NAME& field = fi->fields[i];
|
||||||
|
|
||||||
|
if (strcasecmp(field.column, column) == 0)
|
||||||
|
{
|
||||||
|
if (!field.table && !table)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
else if (field.table && table && (strcasecmp(field.table, table) == 0))
|
||||||
|
{
|
||||||
|
if (!field.database && !database)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
else if (field.database && database && (strcasecmp(field.database, database) == 0))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
QC_FIELD_NAME* fields = (QC_FIELD_NAME*)realloc(fi->fields,
|
||||||
|
(fi->n_fields + 1) * sizeof(QC_FIELD_NAME));
|
||||||
|
ss_dassert(fields);
|
||||||
|
|
||||||
|
if (fields)
|
||||||
|
{
|
||||||
|
// Ignore potential alloc failures
|
||||||
|
QC_FIELD_NAME& field = fields[fi->n_fields];
|
||||||
|
field.database = database ? strdup(database) : NULL;
|
||||||
|
field.table = table ? strdup(table) : NULL;
|
||||||
|
field.column = strdup(column);
|
||||||
|
|
||||||
|
fi->fields = fields;
|
||||||
|
++fi->n_fields;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_function_field_usage(st_select_lex* select,
|
||||||
|
Item_field* item,
|
||||||
|
QC_FUNCTION_INFO* fi)
|
||||||
|
{
|
||||||
|
const char* database = item->db_name;
|
||||||
|
const char* table = item->table_name;
|
||||||
|
|
||||||
|
unalias_names(select, item->db_name, item->table_name, &database, &table);
|
||||||
|
|
||||||
|
const char* s1;
|
||||||
|
size_t l1;
|
||||||
|
get_string_and_length(item->field_name, &s1, &l1);
|
||||||
|
char* column = NULL;
|
||||||
|
|
||||||
|
if (!database && !table)
|
||||||
|
{
|
||||||
|
List_iterator<Item> ilist(select->item_list);
|
||||||
|
Item* item2;
|
||||||
|
|
||||||
|
while (!column && (item2 = ilist++))
|
||||||
|
{
|
||||||
|
if (item2->type() == Item::FIELD_ITEM)
|
||||||
|
{
|
||||||
|
Item_field* field = (Item_field*)item2;
|
||||||
|
|
||||||
|
const char* s2;
|
||||||
|
size_t l2;
|
||||||
|
get_string_and_length(field->name, &s2, &l2);
|
||||||
|
|
||||||
|
if (l1 == l2)
|
||||||
|
{
|
||||||
|
if (strncasecmp(s1, s2, l1) == 0)
|
||||||
|
{
|
||||||
|
get_string_and_length(field->orig_field_name, &s1, &l1);
|
||||||
|
column = strndup(s1, l1);
|
||||||
|
|
||||||
|
table = field->orig_table_name;
|
||||||
|
database = field->orig_db_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!column)
|
||||||
|
{
|
||||||
|
get_string_and_length(item->field_name, &s1, &l1);
|
||||||
|
column = strndup(s1, l1);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_function_field_usage(database, table, column, fi);
|
||||||
|
|
||||||
|
free(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_function_field_usage(st_select_lex* select,
|
||||||
|
Item** items,
|
||||||
|
int n_items,
|
||||||
|
QC_FUNCTION_INFO* fi)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < n_items; ++i)
|
||||||
|
{
|
||||||
|
Item* item = items[i];
|
||||||
|
|
||||||
|
switch (item->type())
|
||||||
|
{
|
||||||
|
case Item::FIELD_ITEM:
|
||||||
|
add_function_field_usage(select, static_cast<Item_field*>(item), fi);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
//ss_dassert(!true);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static QC_FUNCTION_INFO* get_function_info(parsing_info_t* info, const char* name)
|
||||||
|
{
|
||||||
|
QC_FUNCTION_INFO* function_info = NULL;
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < info->function_infos_len; ++i)
|
||||||
|
{
|
||||||
|
function_info = info->function_infos + i;
|
||||||
|
|
||||||
|
if (strcasecmp(name, function_info->name) == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == info->function_infos_len)
|
||||||
|
{
|
||||||
|
// Not found
|
||||||
|
|
||||||
|
if (info->function_infos_len == info->function_infos_capacity)
|
||||||
|
{
|
||||||
|
size_t capacity = info->function_infos_capacity ? 2 * info->function_infos_capacity : 8;
|
||||||
|
QC_FUNCTION_INFO* function_infos =
|
||||||
|
(QC_FUNCTION_INFO*)realloc(info->function_infos,
|
||||||
|
capacity * sizeof(QC_FUNCTION_INFO));
|
||||||
|
assert(function_infos);
|
||||||
|
|
||||||
|
info->function_infos = function_infos;
|
||||||
|
info->function_infos_capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
function_info = &info->function_infos[info->function_infos_len++];
|
||||||
|
|
||||||
|
function_info->name = strdup(name);
|
||||||
|
function_info->usage = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function_info;
|
||||||
|
}
|
||||||
|
|
||||||
static void add_function_info(parsing_info_t* info,
|
static void add_function_info(parsing_info_t* info,
|
||||||
|
st_select_lex* select,
|
||||||
const char* name,
|
const char* name,
|
||||||
uint32_t usage)
|
uint32_t usage,
|
||||||
|
Item** items,
|
||||||
|
int n_items)
|
||||||
{
|
{
|
||||||
ss_dassert(name);
|
ss_dassert(name);
|
||||||
|
|
||||||
@ -2347,6 +2544,11 @@ static void add_function_info(parsing_info_t* info,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
info->function_infos[i].usage |= usage;
|
info->function_infos[i].usage |= usage;
|
||||||
|
|
||||||
|
if (strcmp(name, "=") != 0)
|
||||||
|
{
|
||||||
|
add_function_field_usage(select, items, n_items, &info->function_infos[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If function_infos is NULL, then the function was found and has already been noted.
|
// If function_infos is NULL, then the function was found and has already been noted.
|
||||||
@ -2356,7 +2558,13 @@ static void add_function_info(parsing_info_t* info,
|
|||||||
|
|
||||||
if (item.name)
|
if (item.name)
|
||||||
{
|
{
|
||||||
function_infos[info->function_infos_len++] = item;
|
int i = info->function_infos_len++;
|
||||||
|
function_infos[i] = item;
|
||||||
|
|
||||||
|
if (strcmp(name, "=") != 0)
|
||||||
|
{
|
||||||
|
add_function_field_usage(select, items, n_items, &info->function_infos[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2717,7 +2925,7 @@ static void update_field_infos(parsing_info_t* pi,
|
|||||||
strcpy(func_name, "addtime");
|
strcpy(func_name, "addtime");
|
||||||
}
|
}
|
||||||
|
|
||||||
add_function_info(pi, func_name, usage);
|
add_function_info(pi, select, func_name, usage, items, n_items);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < n_items; ++i)
|
for (size_t i = 0; i < n_items; ++i)
|
||||||
@ -2734,7 +2942,7 @@ static void update_field_infos(parsing_info_t* pi,
|
|||||||
switch (subselect_item->substype())
|
switch (subselect_item->substype())
|
||||||
{
|
{
|
||||||
case Item_subselect::IN_SUBS:
|
case Item_subselect::IN_SUBS:
|
||||||
add_function_info(pi, "in", usage);
|
add_function_info(pi, select, "in", usage, 0, 0);
|
||||||
case Item_subselect::ALL_SUBS:
|
case Item_subselect::ALL_SUBS:
|
||||||
case Item_subselect::ANY_SUBS:
|
case Item_subselect::ANY_SUBS:
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user