Skip to content

Commit 5c8c085

Browse files
committed
Bug#30528450: SPECIAL SYMBOL NAMED COLUMN NOT HONORED IN A SELECT
This patch is for 5.7. Issue 1 ======= A quoted identifier name consisting of a single asterisk character could recognized as an unquoted asterisk, i.e. SELECT `*` ... was parsed as SELECT * ... Issue 2 ======= A qualified quoted identifier with a name starting with the asterisk character could recognized as as unquoted asterisk if the same select list contained an unquoted asterisk symbol, i.e. SELECT a.`*`, ... b.* ... was parsed as SELECT a.*, ... b.`*` ... Analysis for issue 1 ==================== After the WL7200, a special processing of qualified [<schema>].table.* and unqualified * in a select list has diverged: the unqualified one has went to Item_field::itemize(), but the qualified has become PTI_table_wild. As well as it's impossible to mistake quoted and unquoted asterisk inside PTI_table_wild, it is also impossible (too late) to distinguish quoted and unquoted names inside Item_field::itemize(). Thus, the code for the unqualified asterisk in Item_field::itemize() has failed to recognize identifiers like a back-quoted `*` as identifiers. Analysis for issue 2 ==================== From the beginning, the resolver (see setup_wild()) has been designed to recognize asterisks in a select list with a help of: 1. an Item_field placeholder objects with "*" in place of their column names, 2. a counter of asterisk select list items in SELECT_LIST::with_wild local to each query block, Thus, a loop in setup_wild() has searched over all select list items checking all Item_field objects (including either placeholders for * or regular column reference items) for the 1st character of Item_field::field_name until it reached SELECT_LIST::with_wild of such objects. So, if a select list contained unquoted asterisk items before column names containing "*" at their start, everything worked fine. However, if there was a column name starting with "*" before an unquoted asterisk in a select list, the former recognized as an unquoted asterisk, while the latest recognized as a quoted column name. Solution ======== 1. The code branch in Item_field::itemize() that processed asterisks has been removed. 2. The Item_asterisk class has been introduced to replace PTI_table_wild. Reasoning: * unlike PTI_table_wild, that disappears after the PTI_table_wild::itemize() call leaving Item_field in its place, the new Item_asterisk class can survive till the setup_wild() call to be distinguished there from other Item_field objects those represent regular column references. * minus one MEM_ROOT allocation * the new name Item_asterisk is closer to the standard 3. All direct allocations of Item_field for the unquoted asterisk thing have been replaced with allocations of Item_asterisk. 4. setup_wild() has been updated to recognize asterisk items using Item_field::is_asterisk() instead of looking into Item_field::field_name. Change-Id: Id0e5eea03608ed6140901e32d840dc3190a67bee
1 parent 82c6a77 commit 5c8c085

10 files changed

+127
-57
lines changed

Diff for: mysql-test/r/parser.result

+15
Original file line numberDiff line numberDiff line change
@@ -1239,3 +1239,18 @@ Bug #27714748: @@PARSER_MAX_MEM_SIZE DOES NOT WORK FOR ROUTINES
12391239
SET parser_max_mem_size = 10000000;
12401240
ERROR HY000: Memory capacity of 10000000 bytes for 'parser_max_mem_size' exceeded. Parser bailed out for this query.
12411241
SET parser_max_mem_size = default;
1242+
#
1243+
# Bug#30528450: SPECIAL SYMBOL NAMED COLUMN NOT HONORED IN A SELECT
1244+
#
1245+
CREATE TABLE t1 (c1 INT, `*` INT, c3 INT);
1246+
INSERT INTO t1 VALUES (1, 2, 3);
1247+
SELECT `*` FROM t1;
1248+
*
1249+
2
1250+
SELECT t1.`*`, t1.* FROM t1;
1251+
* c1 * c3
1252+
2 1 2 3
1253+
SELECT test.t1.`*`, test.t1.* FROM t1;
1254+
* c1 * c3
1255+
2 1 2 3
1256+
DROP TABLE t1;

Diff for: mysql-test/t/parser.test

+13
Original file line numberDiff line numberDiff line change
@@ -1376,3 +1376,16 @@ SET parser_max_mem_size = 10000000; # minimum allowed value
13761376
--eval CREATE PROCEDURE p() SELECT 1 FROM (SELECT '$s') a
13771377
--enable_query_log
13781378
SET parser_max_mem_size = default;
1379+
1380+
--echo #
1381+
--echo # Bug#30528450: SPECIAL SYMBOL NAMED COLUMN NOT HONORED IN A SELECT
1382+
--echo #
1383+
1384+
CREATE TABLE t1 (c1 INT, `*` INT, c3 INT);
1385+
INSERT INTO t1 VALUES (1, 2, 3);
1386+
1387+
SELECT `*` FROM t1;
1388+
SELECT t1.`*`, t1.* FROM t1;
1389+
SELECT test.t1.`*`, test.t1.* FROM t1;
1390+
1391+
DROP TABLE t1;

Diff for: sql/item.cc

+23-3
Original file line numberDiff line numberDiff line change
@@ -2748,9 +2748,6 @@ bool Item_field::itemize(Parse_context *pc, Item **res)
27482748
if (select->parsing_place != CTX_HAVING)
27492749
select->select_n_where_fields++;
27502750

2751-
if (select->parsing_place == CTX_SELECT_LIST &&
2752-
field_name && field_name[0] == '*' && field_name[1] == 0)
2753-
select->with_wild++;
27542751
return false;
27552752
}
27562753

@@ -11019,3 +11016,26 @@ bool Item_field::repoint_const_outer_ref(uchar *arg)
1101911016
*is_outer_ref= false;
1102011017
return false;
1102111018
}
11019+
11020+
11021+
Item_asterisk::Item_asterisk(Name_resolution_context *context_arg,
11022+
const char *opt_schema_name,
11023+
const char *opt_table_name)
11024+
: super(context_arg, opt_schema_name, opt_table_name, "*")
11025+
{
11026+
context_arg->select_lex->with_wild++;
11027+
}
11028+
11029+
11030+
bool Item_asterisk::itemize(Parse_context *pc, Item **res)
11031+
{
11032+
DBUG_ASSERT(pc->select->parsing_place == CTX_SELECT_LIST);
11033+
11034+
if (skip_itemize(res))
11035+
return false;
11036+
if (super::itemize(pc, res))
11037+
return true;
11038+
11039+
pc->select->with_wild++;
11040+
return false;
11041+
}

Diff for: sql/item.h

+56-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef ITEM_INCLUDED
22
#define ITEM_INCLUDED
33

4-
/* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
4+
/* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
55
66
This program is free software; you can redistribute it and/or modify
77
it under the terms of the GNU General Public License, version 2.0,
@@ -3042,6 +3042,61 @@ class Item_field :public Item_ident
30423042
}
30433043

30443044
bool repoint_const_outer_ref(uchar *arg);
3045+
3046+
3047+
/**
3048+
Checks if the current object represents an asterisk select list item
3049+
3050+
@returns false if a regular column reference, true if an asterisk
3051+
select list item.
3052+
*/
3053+
virtual bool is_asterisk() const { return false; }
3054+
};
3055+
3056+
/**
3057+
Represents [schema.][table.]* in a select list
3058+
3059+
Item_asterisk is used to insert placeholder objects for the special
3060+
select list item * (asterisk) into AST.
3061+
Those placeholder objects are to be substituted later with e.g. a list of real
3062+
table columns by a resolver (@see setup_wild).
3063+
3064+
@todo The parent class Item_field is redundant. Refactor setup_wild() to
3065+
replace Item_field with a simpler one.
3066+
*/
3067+
class Item_asterisk : public Item_field
3068+
{
3069+
typedef Item_field super;
3070+
3071+
public:
3072+
/**
3073+
Constructor
3074+
3075+
@param context_arg Name resolution context.
3076+
@param opt_schema_name Schema name or NULL.
3077+
@param opt_table_name Table name or NULL.
3078+
*/
3079+
3080+
Item_asterisk(Name_resolution_context *context_arg,
3081+
const char *opt_schema_name, const char *opt_table_name);
3082+
3083+
/**
3084+
Constructor
3085+
3086+
@param pos Location of the * (asterisk) lexeme.
3087+
@param opt_schema_name Schema name or NULL.
3088+
@param opt_table_name Table name or NULL.
3089+
*/
3090+
Item_asterisk(const POS &pos, const char *opt_schema_name,
3091+
const char *opt_table_name)
3092+
: super(pos, opt_schema_name, opt_table_name, "*") {}
3093+
3094+
virtual bool itemize(Parse_context *pc, Item **res);
3095+
virtual bool fix_fields(THD *, Item **) {
3096+
DBUG_ASSERT(false); // should never happen: see setup_wild()
3097+
return true;
3098+
}
3099+
virtual bool is_asterisk() const { return true; }
30453100
};
30463101

30473102
class Item_null :public Item_basic_constant

Diff for: sql/parse_tree_items.cc

+1-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2013, 2020, Oracle and/or its affiliates.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -101,21 +101,6 @@ static Item* handle_sql2003_note184_exception(Parse_context *pc, Item* left,
101101
}
102102

103103

104-
bool PTI_table_wild::itemize(Parse_context *pc, Item **item)
105-
{
106-
if (super::itemize(pc, item))
107-
return true;
108-
109-
schema=
110-
pc->thd->get_protocol()->has_client_capability(CLIENT_NO_SCHEMA) ? NullS : schema;
111-
*item= new (pc->mem_root) Item_field(POS(), schema, table, "*");
112-
if (*item == NULL || (*item)->itemize(pc, item))
113-
return true;
114-
pc->select->with_wild++;
115-
return false;
116-
}
117-
118-
119104
bool PTI_comp_op::itemize(Parse_context *pc, Item **res)
120105
{
121106
if (super::itemize(pc, res) ||

Diff for: sql/parse_tree_items.h

+1-18
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2013, 2020, Oracle and/or its affiliates.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -32,23 +32,6 @@
3232
#include "sp_head.h" // sp_head
3333
#include "sql_parse.h" // negate_expression
3434

35-
class PTI_table_wild : public Parse_tree_item
36-
{
37-
typedef Parse_tree_item super;
38-
39-
const char *schema;
40-
const char *table;
41-
42-
public:
43-
explicit PTI_table_wild(const POS &pos,
44-
const char *schema_arg, const char *table_arg)
45-
: super(pos), schema(schema_arg), table(table_arg)
46-
{}
47-
48-
virtual bool itemize(Parse_context *pc, Item **item);
49-
};
50-
51-
5235
class PTI_negate_expression : public Parse_tree_item
5336
{
5437
typedef Parse_tree_item super;

Diff for: sql/sql_handler.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2001, 2020, Oracle and/or its affiliates.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -513,8 +513,8 @@ bool Sql_cmd_handler_read::execute(THD *thd)
513513
offset_limit_cnt= unit->offset_limit_cnt;
514514

515515
select_lex->context.resolve_in_table_list_only(tables);
516-
list.push_front(new Item_field(&select_lex->context,
517-
NULL, NULL, "*"));
516+
list.push_front(new Item_asterisk(&select_lex->context,
517+
NULL, NULL));
518518
List_iterator<Item> it(list);
519519
it++;
520520

Diff for: sql/sql_resolver.cc

+3-4
Original file line numberDiff line numberDiff line change
@@ -1111,11 +1111,10 @@ bool SELECT_LEX::setup_wild(THD *thd)
11111111
{
11121112
Item_field *item_field;
11131113
if (item->type() == Item::FIELD_ITEM &&
1114-
(item_field= (Item_field *) item) &&
1115-
item_field->field_name &&
1116-
item_field->field_name[0] == '*' &&
1117-
!item_field->field)
1114+
(item_field= down_cast<Item_field *>(item)) &&
1115+
item_field->is_asterisk())
11181116
{
1117+
DBUG_ASSERT(item_field->field == NULL);
11191118
const uint elem= fields_list.elements;
11201119
const bool any_privileges= item_field->any_privileges;
11211120
Item_subselect *subsel= master_unit()->item;

Diff for: sql/sql_show_status.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2015, 2020 Oracle and/or its affiliates.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -90,7 +90,7 @@ build_query(const POS &pos,
9090

9191

9292
/* * */
93-
Item *star= new (thd->mem_root) Item_field(pos, NULL, NULL, "*");
93+
Item *star= new (thd->mem_root) Item_asterisk(pos, NULL, NULL);
9494

9595
PT_select_item_list *item_list2;
9696
item_list2= new (thd->mem_root) PT_select_item_list();

Diff for: sql/sql_yacc.yy

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2000, 2020, Oracle and/or its affiliates.
33

44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License, version 2.0,
@@ -35,6 +35,7 @@ Note: YYTHD is passed as an argument to yyparse(), and subsequently to yylex().
3535
#define YYLIP (& YYTHD->m_parser_state->m_lip)
3636
#define YYPS (& YYTHD->m_parser_state->m_yacc)
3737
#define YYCSCL (YYLIP->query_charset)
38+
#define YYCLIENT_NO_SCHEMA (YYTHD->get_protocol()->has_client_capability(CLIENT_NO_SCHEMA))
3839

3940
#define YYINITDEPTH 100
4041
#define YYMAXDEPTH 3200 /* Because of 64K stack */
@@ -9216,9 +9217,9 @@ select_item_list:
92169217
}
92179218
| '*'
92189219
{
9219-
Item *item= NEW_PTN Item_field(@$, NULL, NULL, "*");
9220+
Item *item = NEW_PTN Item_asterisk(@$, NULL, NULL);
92209221
$$= NEW_PTN PT_select_item_list;
9221-
if ($$ == NULL || $$->push_back(item))
9222+
if ($$ == NULL || item == NULL || $$->push_back(item))
92229223
MYSQL_YYABORT;
92239224
}
92249225
;
@@ -12960,11 +12961,12 @@ insert_ident:
1296012961
table_wild:
1296112962
ident '.' '*'
1296212963
{
12963-
$$= NEW_PTN PTI_table_wild(@$, NULL, $1.str);
12964+
$$= NEW_PTN Item_asterisk(@$, NULL, $1.str);
1296412965
}
1296512966
| ident '.' ident '.' '*'
1296612967
{
12967-
$$= NEW_PTN PTI_table_wild(@$, $1.str, $3.str);
12968+
const char *schema_name = YYCLIENT_NO_SCHEMA ? NULL : $1.str;
12969+
$$= NEW_PTN Item_asterisk(@$, schema_name, $3.str);
1296812970
}
1296912971
;
1297012972

@@ -13065,11 +13067,9 @@ table_ident:
1306513067
}
1306613068
| ident '.' ident
1306713069
{
13068-
if (YYTHD->get_protocol()->has_client_capability(CLIENT_NO_SCHEMA))
13069-
$$= NEW_PTN Table_ident(to_lex_cstring($3));
13070-
else {
13071-
$$= NEW_PTN Table_ident(to_lex_cstring($1), to_lex_cstring($3));
13072-
}
13070+
LEX_CSTRING schema_name= YYCLIENT_NO_SCHEMA ? LEX_CSTRING()
13071+
: to_lex_cstring($1);
13072+
$$= NEW_PTN Table_ident(schema_name, to_lex_cstring($3));
1307313073
if ($$ == NULL)
1307413074
MYSQL_YYABORT;
1307513075
}

0 commit comments

Comments
 (0)