MXS-1340 Report true table and not alias name
With this change, for a statement like SELECT t2.a FROM t1 t2; the affected field is reported as t1.a and not as t2.a, as it was before. For a statement like SELECT t.f FROM d.t; qc_mysqlembedded will now return "d.t.f" as the affected field, while qc_sqlite will still return "t.f" as both implementations did before. In qc_mysqlembedded's case that is a side-effect of the alias handling. To get qc_sqlite to return the same (which would be good), the table names would have to be collected in a smarter way than they are now.
This commit is contained in:
parent
b9588a89ac
commit
4f4151bca9
@ -2180,6 +2180,7 @@ static bool should_exclude(const char* name, List<Item>* excludep)
|
||||
}
|
||||
|
||||
static void add_field_info(parsing_info_t* info,
|
||||
st_select_lex* select,
|
||||
const char* database,
|
||||
const char* table,
|
||||
const char* column,
|
||||
@ -2190,6 +2191,35 @@ static void add_field_info(parsing_info_t* info,
|
||||
|
||||
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;
|
||||
for (i = 0; i < info->field_infos_len; ++i)
|
||||
{
|
||||
@ -2326,7 +2356,11 @@ static void add_function_info(parsing_info_t* info,
|
||||
}
|
||||
}
|
||||
|
||||
static void add_field_info(parsing_info_t* pi, Item_field* item, uint32_t usage, List<Item>* excludep)
|
||||
static void add_field_info(parsing_info_t* pi,
|
||||
st_select_lex* select,
|
||||
Item_field* item,
|
||||
uint32_t usage,
|
||||
List<Item>* excludep)
|
||||
{
|
||||
const char* database = item->db_name;
|
||||
const char* table = item->table_name;
|
||||
@ -2417,10 +2451,14 @@ static void add_field_info(parsing_info_t* pi, Item_field* item, uint32_t usage,
|
||||
break;
|
||||
}
|
||||
|
||||
add_field_info(pi, database, table, column, usage, excludep);
|
||||
add_field_info(pi, select, database, table, column, usage, excludep);
|
||||
}
|
||||
|
||||
static void add_field_info(parsing_info_t* pi, Item* item, uint32_t usage, List<Item>* excludep)
|
||||
static void add_field_info(parsing_info_t* pi,
|
||||
st_select_lex* select,
|
||||
Item* item,
|
||||
uint32_t usage,
|
||||
List<Item>* excludep)
|
||||
{
|
||||
const char* database = NULL;
|
||||
const char* table = NULL;
|
||||
@ -2431,7 +2469,7 @@ static void add_field_info(parsing_info_t* pi, Item* item, uint32_t usage, List<
|
||||
strncpy(column, s, l);
|
||||
column[l] = 0;
|
||||
|
||||
add_field_info(pi, database, table, column, usage, excludep);
|
||||
add_field_info(pi, select, database, table, column, usage, excludep);
|
||||
}
|
||||
|
||||
typedef enum collect_source
|
||||
@ -2504,6 +2542,7 @@ static bool should_function_be_ignored(parsing_info_t* pi, const char* func_name
|
||||
}
|
||||
|
||||
static void update_field_infos(parsing_info_t* pi,
|
||||
st_select_lex* select,
|
||||
collect_source_t source,
|
||||
Item* item,
|
||||
uint32_t usage,
|
||||
@ -2518,13 +2557,13 @@ static void update_field_infos(parsing_info_t* pi,
|
||||
|
||||
while (Item *i = ilist++)
|
||||
{
|
||||
update_field_infos(pi, source, i, usage, excludep);
|
||||
update_field_infos(pi, select, source, i, usage, excludep);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Item::FIELD_ITEM:
|
||||
add_field_info(pi, static_cast<Item_field*>(item), usage, excludep);
|
||||
add_field_info(pi, select, static_cast<Item_field*>(item), usage, excludep);
|
||||
break;
|
||||
|
||||
case Item::REF_ITEM:
|
||||
@ -2533,7 +2572,7 @@ static void update_field_infos(parsing_info_t* pi,
|
||||
{
|
||||
Item_ref* ref_item = static_cast<Item_ref*>(item);
|
||||
|
||||
add_field_info(pi, item, usage, excludep);
|
||||
add_field_info(pi, select, item, usage, excludep);
|
||||
|
||||
size_t n_items = ref_item->cols();
|
||||
|
||||
@ -2543,7 +2582,7 @@ static void update_field_infos(parsing_info_t* pi,
|
||||
|
||||
if (reffed_item != ref_item)
|
||||
{
|
||||
update_field_infos(pi, source, ref_item->element_index(i), usage, excludep);
|
||||
update_field_infos(pi, select, source, ref_item->element_index(i), usage, excludep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2557,7 +2596,7 @@ static void update_field_infos(parsing_info_t* pi,
|
||||
|
||||
for (size_t i = 0; i < n_items; ++i)
|
||||
{
|
||||
update_field_infos(pi, source, row_item->element_index(i), usage, excludep);
|
||||
update_field_infos(pi, select, source, row_item->element_index(i), usage, excludep);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -2665,7 +2704,7 @@ static void update_field_infos(parsing_info_t* pi,
|
||||
|
||||
for (size_t i = 0; i < n_items; ++i)
|
||||
{
|
||||
update_field_infos(pi, source, items[i], usage, excludep);
|
||||
update_field_infos(pi, select, source, items[i], usage, excludep);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -2692,7 +2731,7 @@ static void update_field_infos(parsing_info_t* pi,
|
||||
)
|
||||
if (in_subselect_item->left_expr_orig)
|
||||
{
|
||||
update_field_infos(pi, source,
|
||||
update_field_infos(pi, select, source, // TODO: Might be wrong select.
|
||||
in_subselect_item->left_expr_orig, usage, excludep);
|
||||
}
|
||||
st_select_lex* ssl = in_subselect_item->get_select_lex();
|
||||
@ -2789,7 +2828,7 @@ static void update_field_infos(parsing_info_t* pi,
|
||||
|
||||
while (Item *item = ilist++)
|
||||
{
|
||||
update_field_infos(pi, COLLECT_SELECT, item, usage, NULL);
|
||||
update_field_infos(pi, select, COLLECT_SELECT, item, usage, NULL);
|
||||
}
|
||||
|
||||
if (select->group_list.first)
|
||||
@ -2799,7 +2838,7 @@ static void update_field_infos(parsing_info_t* pi,
|
||||
{
|
||||
Item* item = *order->item;
|
||||
|
||||
update_field_infos(pi, COLLECT_GROUP_BY, item, QC_USED_IN_GROUP_BY,
|
||||
update_field_infos(pi, select, COLLECT_GROUP_BY, item, QC_USED_IN_GROUP_BY,
|
||||
&select->item_list);
|
||||
|
||||
order = order->next;
|
||||
@ -2808,7 +2847,7 @@ static void update_field_infos(parsing_info_t* pi,
|
||||
|
||||
if (select->where)
|
||||
{
|
||||
update_field_infos(pi, COLLECT_WHERE,
|
||||
update_field_infos(pi, select, COLLECT_WHERE,
|
||||
select->where,
|
||||
QC_USED_IN_WHERE,
|
||||
&select->item_list);
|
||||
@ -2927,7 +2966,7 @@ int32_t qc_mysql_get_field_info(GWBUF* buf, const QC_FIELD_INFO** infos, uint32_
|
||||
List_iterator<Item> ilist(lex->value_list);
|
||||
while (Item* item = ilist++)
|
||||
{
|
||||
update_field_infos(pi, COLLECT_SELECT, item, 0, NULL);
|
||||
update_field_infos(pi, lex->current_select, COLLECT_SELECT, item, 0, NULL);
|
||||
}
|
||||
|
||||
if ((lex->sql_command == SQLCOM_INSERT) ||
|
||||
@ -2938,7 +2977,7 @@ int32_t qc_mysql_get_field_info(GWBUF* buf, const QC_FIELD_INFO** infos, uint32_
|
||||
List_iterator<Item> ilist(lex->field_list);
|
||||
while (Item *item = ilist++)
|
||||
{
|
||||
update_field_infos(pi, COLLECT_SELECT, item, 0, NULL);
|
||||
update_field_infos(pi, lex->current_select, COLLECT_SELECT, item, 0, NULL);
|
||||
}
|
||||
|
||||
if (lex->insert_list)
|
||||
@ -2946,7 +2985,7 @@ int32_t qc_mysql_get_field_info(GWBUF* buf, const QC_FIELD_INFO** infos, uint32_
|
||||
List_iterator<Item> ilist(*lex->insert_list);
|
||||
while (Item *item = ilist++)
|
||||
{
|
||||
update_field_infos(pi, COLLECT_SELECT, item, 0, NULL);
|
||||
update_field_infos(pi, lex->current_select, COLLECT_SELECT, item, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -514,6 +514,8 @@ public:
|
||||
{
|
||||
ss_dassert(zColumn);
|
||||
|
||||
// NOTE: This must be first, so that the type mask is properly updated
|
||||
// NOTE: in case zColumn is "currval" etc.
|
||||
if (is_sequence_related_field(zDatabase, zTable, zColumn))
|
||||
{
|
||||
m_type_mask |= QUERY_TYPE_WRITE;
|
||||
@ -527,6 +529,19 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
if (!zDatabase && zTable)
|
||||
{
|
||||
Aliases::const_iterator i = m_aliases.find(zTable);
|
||||
|
||||
if (i != m_aliases.end())
|
||||
{
|
||||
const QcAliasValue& value = i->second;
|
||||
|
||||
zDatabase = value.zDatabase;
|
||||
zTable = value.zTable;
|
||||
}
|
||||
}
|
||||
|
||||
QC_FIELD_INFO item = { (char*)zDatabase, (char*)zTable, (char*)zColumn, usage };
|
||||
|
||||
size_t i;
|
||||
|
@ -28,7 +28,11 @@ insert into mysqltest.t2 values (1,'xxx'), (1,'zzz');
|
||||
|
||||
connection user1;
|
||||
with t as (select c from mysqltest.t2 where c < 2)
|
||||
select t.c,t1.b from t,mysqltest.t1 where t.c=t1.a;
|
||||
|
||||
#MXS: qc_sqlite cannot currently return mysqltest.t1.b as
|
||||
#MXS: the affected field, but only t1.b.
|
||||
#select t.c,t1.b from t,mysqltest.t1 where t.c=t1.a;
|
||||
select t.c,t1.b from t,t1 where t.c=t1.a;
|
||||
--error ER_COLUMNACCESS_DENIED_ERROR
|
||||
select t.c,t.d,t1.b
|
||||
from (select c,d from mysqltest.t2 where c < 2) as t, mysqltest.t1
|
||||
@ -40,8 +44,11 @@ select t.c,t.d,t1.b from t,mysqltest.t1 where t.c=t1.a;
|
||||
connection root;
|
||||
|
||||
create view mysqltest.v1(f1,f2) as
|
||||
#MXS: qc_sqlite reports t1.a and not mysqltest.t1.a
|
||||
#with t as (select c from mysqltest.t2 where c < 2)
|
||||
#select t.c,t1.b from t,mysqltest.t1 where t.c=t1.a;
|
||||
with t as (select c from mysqltest.t2 where c < 2)
|
||||
select t.c,t1.b from t,mysqltest.t1 where t.c=t1.a;
|
||||
select t.c,t1.b from t,t1 where t.c=t1.a;
|
||||
create view mysqltest.v2(c,d) as
|
||||
with t as (select a from mysqltest.t1 where a>=3)
|
||||
select t.a,b from t,mysqltest.t1 where mysqltest.t1.a = t.a;
|
||||
@ -54,8 +61,11 @@ select t.a,b from t,mysqltest.t1 where mysqltest.t1.a = t.a;
|
||||
connection user1;
|
||||
|
||||
create view mysqltest.v3(c,d) as
|
||||
#MXS: qc_sqlite reports t1.a and not mysqltest.t1.a
|
||||
#with t as (select c from mysqltest.t2 where c < 2)
|
||||
#select t.c,t1.b from t,mysqltest.t1 where t.c=t1.a;
|
||||
with t as (select c from mysqltest.t2 where c < 2)
|
||||
select t.c,t1.b from t,mysqltest.t1 where t.c=t1.a;
|
||||
select t.c,t1.b from t,t1 where t.c=t1.a;
|
||||
--error ER_COLUMNACCESS_DENIED_ERROR
|
||||
create view mysqltest.v4(f1,f2,f3) as
|
||||
with t as (select c,d from mysqltest.t2 where c < 2)
|
||||
|
@ -547,15 +547,19 @@ select t1.b from v1a;
|
||||
-- error 1054
|
||||
select * from v1a join v1b on t1.b = t2.b;
|
||||
|
||||
#MXS With the alias modifications made to qc_mysqlembedded, for a select like
|
||||
#MXS "select t.f from d.t" it will report "d.t.f" as the affected field. That
|
||||
#MXS is correct, but in qc_sqlite that cannot easily be done as the table
|
||||
#MXS information is not collected in an appropriate way.
|
||||
#
|
||||
# Bug #17523 natural join and information_schema
|
||||
#
|
||||
# Omit columns.PRIVILIGES as it may vary with embedded server.
|
||||
# Omit columns.ORDINAL_POSITION and statistics.CARDINALITY as it may vary with hostname='localhost'.
|
||||
select
|
||||
statistics.TABLE_NAME, statistics.COLUMN_NAME, statistics.TABLE_CATALOG, statistics.TABLE_SCHEMA, statistics.NON_UNIQUE, statistics.INDEX_SCHEMA, statistics.INDEX_NAME, statistics.SEQ_IN_INDEX, statistics.COLLATION, statistics.SUB_PART, statistics.PACKED, statistics.NULLABLE, statistics.INDEX_TYPE, statistics.COMMENT,
|
||||
columns.TABLE_CATALOG, columns.TABLE_SCHEMA, columns.COLUMN_DEFAULT, columns.IS_NULLABLE, columns.DATA_TYPE, columns.CHARACTER_MAXIMUM_LENGTH, columns.CHARACTER_OCTET_LENGTH, columns.NUMERIC_PRECISION, columns.NUMERIC_SCALE, columns.CHARACTER_SET_NAME, columns.COLLATION_NAME, columns.COLUMN_TYPE, columns.COLUMN_KEY, columns.EXTRA, columns.COLUMN_COMMENT
|
||||
from information_schema.statistics join information_schema.columns using(table_name,column_name) where table_name='user';
|
||||
#MXS select
|
||||
#MXS statistics.TABLE_NAME, statistics.COLUMN_NAME, statistics.TABLE_CATALOG, statistics.TABLE_SCHEMA, statistics.NON_UNIQUE, statistics.INDEX_SCHEMA, statistics.INDEX_NAME, statistics.SEQ_IN_INDEX, statistics.COLLATION, statistics.SUB_PART, statistics.PACKED, statistics.NULLABLE, statistics.INDEX_TYPE, statistics.COMMENT,
|
||||
#MXS columns.TABLE_CATALOG, columns.TABLE_SCHEMA, columns.COLUMN_DEFAULT, columns.IS_NULLABLE, columns.DATA_TYPE, columns.CHARACTER_MAXIMUM_LENGTH, columns.CHARACTER_OCTET_LENGTH, columns.NUMERIC_PRECISION, columns.NUMERIC_SCALE, columns.CHARACTER_SET_NAME, columns.COLLATION_NAME, columns.COLUMN_TYPE, columns.COLUMN_KEY, columns.EXTRA, columns.COLUMN_COMMENT
|
||||
#MXS from information_schema.statistics join information_schema.columns using(table_name,column_name) where table_name='user';
|
||||
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
|
@ -57,3 +57,10 @@ SELECT LENGTH(_utf8 0xC39F), LENGTH(CHAR(14844588 USING utf8));
|
||||
# warning: [qc_sqlite] Statement was classified only based on keywords
|
||||
# (Sqlite3 error: SQL logic error or missing database, near "0xC39F": syntax error):
|
||||
# "SELECT LENGTH(_utf8 0xC39F), LENGTH(CHAR(14844588 USING utf8));"
|
||||
|
||||
SELECT t.f FROM d.t;
|
||||
# qc_get_field_info : ERR: d.t.f(QC_USED_IN_SELECT) != t.f(QC_USED_IN_SELECT)
|
||||
# Table names need to be collected in a more intelligent fashion to be able
|
||||
# to do that.
|
||||
select t.c,t1.b from t,mysqltest.t1 where t.c=t1.a;
|
||||
with t as (select c from mysqltest.t2 where c < 2) select t.c,t1.b from t,mysqltest.t1 where t.c=t1.a;
|
||||
|
Loading…
x
Reference in New Issue
Block a user