338 lines
11 KiB
C++
338 lines
11 KiB
C++
/* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License, version 2.0,
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is also distributed with certain software (including
|
|
but not limited to OpenSSL) that is licensed under separate terms,
|
|
as designated in a particular file or component or in included license
|
|
documentation. The authors of MySQL hereby grant you an additional
|
|
permission to link the program and your derivative works with the
|
|
separately licensed software that they have included with MySQL.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License, version 2.0, for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
|
|
#include "sql/dd/info_schema/show_query_builder.h" // Select_lex_builder
|
|
|
|
#include "m_string.h" // STRING_WITH_LEN
|
|
#include "my_dbug.h"
|
|
#include "sql/auth/sql_security_ctx.h"
|
|
#include "sql/item_cmpfunc.h" // Item_func_like
|
|
#include "sql/item_func.h"
|
|
#include "sql/key.h"
|
|
#include "sql/key_spec.h"
|
|
#include "sql/parse_location.h"
|
|
#include "sql/parse_tree_helpers.h"
|
|
#include "sql/parse_tree_items.h" // PTI_simple_ident_ident
|
|
#include "sql/parse_tree_node_base.h"
|
|
#include "sql/parse_tree_nodes.h" // PT_select_item_list
|
|
#include "sql/query_options.h" // OPTION_SELECT_FOR_SHOW
|
|
#include "sql/sql_class.h"
|
|
#include "sql/sql_lex.h" // Query_options
|
|
#include "sql/strfunc.h"
|
|
#include "sql_string.h"
|
|
|
|
class Item;
|
|
|
|
namespace dd {
|
|
namespace info_schema {
|
|
|
|
static const Query_options options = {
|
|
OPTION_SELECT_FOR_SHOW /* query_spec_options */
|
|
};
|
|
|
|
Select_lex_builder::Select_lex_builder(const POS *pc, THD *thd)
|
|
: m_pos(pc),
|
|
m_thd(thd),
|
|
m_select_item_list(nullptr),
|
|
m_where_clause(nullptr),
|
|
m_order_by_list(nullptr) {
|
|
m_table_reference_list.init(m_thd->mem_root);
|
|
}
|
|
|
|
bool Select_lex_builder::add_to_select_item_list(Item *expr) {
|
|
// Prepare list if not exist.
|
|
if (!m_select_item_list) {
|
|
m_select_item_list = new (m_thd->mem_root) PT_select_item_list();
|
|
|
|
if (m_select_item_list == nullptr) return true;
|
|
}
|
|
|
|
m_select_item_list->push_back(expr);
|
|
|
|
return false;
|
|
}
|
|
|
|
// Add item representing star in "SELECT '*' ...".
|
|
bool Select_lex_builder::add_star_select_item() {
|
|
const LEX_CSTRING star = {STRING_WITH_LEN("*")};
|
|
|
|
PTI_simple_ident_ident *ident_star =
|
|
new (m_thd->mem_root) PTI_simple_ident_ident(*m_pos, star);
|
|
if (ident_star == nullptr) return true;
|
|
|
|
return add_to_select_item_list(ident_star);
|
|
}
|
|
|
|
/**
|
|
Add item representing a column as,
|
|
"SELECT <field_name> AS <alias>, ...".
|
|
*/
|
|
bool Select_lex_builder::add_select_item(const LEX_CSTRING &field_name,
|
|
const LEX_CSTRING &alias) {
|
|
/* ... FIELD_NAME ... */
|
|
PTI_simple_ident_ident *ident_field =
|
|
new (m_thd->mem_root) PTI_simple_ident_ident(*m_pos, field_name);
|
|
if (ident_field == nullptr) return true;
|
|
|
|
/* ... FIELD_NAME as alias ... */
|
|
PTI_expr_with_alias *expr;
|
|
expr = new (m_thd->mem_root)
|
|
PTI_expr_with_alias(*m_pos, ident_field, m_pos->cpp, alias);
|
|
if (expr == nullptr) return true;
|
|
|
|
return add_to_select_item_list(expr);
|
|
}
|
|
|
|
/**
|
|
Add expression item representing a column as,
|
|
"SELECT <expr> AS <alias>, ...".
|
|
*/
|
|
bool Select_lex_builder::add_select_expr(Item *select_list_item,
|
|
const LEX_CSTRING &alias) {
|
|
/* ... FIELD_NAME as alias ... */
|
|
PTI_expr_with_alias *expr = new (m_thd->mem_root)
|
|
PTI_expr_with_alias(*m_pos, select_list_item, m_pos->cpp, alias);
|
|
if (expr == nullptr) return true;
|
|
|
|
return add_to_select_item_list(expr);
|
|
}
|
|
|
|
/**
|
|
Add item representing a FROM clause table as,
|
|
"SELECT ... FROM <schema_name>.<table_name> ...".
|
|
*/
|
|
bool Select_lex_builder::add_from_item(const LEX_CSTRING &schema_name,
|
|
const LEX_CSTRING &table_name) {
|
|
/*
|
|
make_table_list() might alter the database and table name
|
|
strings. Create copies and leave the original values
|
|
unaltered.
|
|
*/
|
|
|
|
/* ... schame_name ... */
|
|
LEX_CSTRING tmp_db_name;
|
|
if (lex_string_strmake(m_thd->mem_root, &tmp_db_name, schema_name.str,
|
|
schema_name.length))
|
|
return true;
|
|
|
|
/* ... <table_name> ... */
|
|
LEX_CSTRING tmp_table_name;
|
|
if (lex_string_strmake(m_thd->mem_root, &tmp_table_name, table_name.str,
|
|
table_name.length))
|
|
return true;
|
|
|
|
/* ... schame_name.<table_name> ... */
|
|
Table_ident *table_ident =
|
|
new (m_thd->mem_root) Table_ident(tmp_db_name, tmp_table_name);
|
|
if (table_ident == nullptr) return true;
|
|
|
|
/* ... FROM schame_name.<table_name> ... */
|
|
PT_table_factor_table_ident *table_factor = new (m_thd->mem_root)
|
|
PT_table_factor_table_ident(table_ident, nullptr, NULL_CSTR, nullptr);
|
|
if (table_factor == nullptr) return true;
|
|
|
|
if (m_table_reference_list.push_back(table_factor)) return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
Add item representing a FROM clause table as,
|
|
"SELECT ... FROM <sub query or derived table> ...".
|
|
*/
|
|
bool Select_lex_builder::add_from_item(PT_derived_table *dt) {
|
|
if (m_table_reference_list.push_back(dt)) return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// Prepare item representing a LIKE condition.
|
|
Item *Select_lex_builder::prepare_like_item(const LEX_CSTRING &field_name,
|
|
const String *wild) {
|
|
/* ... FIELD_NAME ... */
|
|
PTI_simple_ident_ident *ident_field =
|
|
new (m_thd->mem_root) PTI_simple_ident_ident(*m_pos, field_name);
|
|
if (ident_field == nullptr) return nullptr;
|
|
|
|
/* ... <value> ... */
|
|
LEX_STRING *lex_string =
|
|
static_cast<LEX_STRING *>(m_thd->alloc(sizeof(LEX_STRING)));
|
|
if (lex_string == nullptr) return nullptr;
|
|
lex_string->length = wild->length();
|
|
lex_string->str = m_thd->strmake(wild->ptr(), wild->length());
|
|
if (lex_string->str == nullptr) return nullptr;
|
|
|
|
PTI_text_literal_text_string *wild_string =
|
|
new (m_thd->mem_root) PTI_text_literal_text_string(
|
|
*m_pos, false, *lex_string); // TODO WL#6629 check is_7bit
|
|
if (wild_string == nullptr) return nullptr;
|
|
|
|
/* ... field_name LIKE <value> ... */
|
|
Item_func_like *func_like = new (m_thd->mem_root)
|
|
Item_func_like(*m_pos, ident_field, wild_string, nullptr);
|
|
|
|
return func_like;
|
|
}
|
|
|
|
// Prepare item representing a equal to comparision condition.
|
|
Item *Select_lex_builder::prepare_equal_item(const LEX_CSTRING &field_name,
|
|
const LEX_CSTRING &value) {
|
|
/* ... FIELD_NAME ... */
|
|
PTI_simple_ident_ident *ident_field =
|
|
new (m_thd->mem_root) PTI_simple_ident_ident(*m_pos, field_name);
|
|
if (ident_field == nullptr) return nullptr;
|
|
|
|
/* ... <value> ... */
|
|
LEX_STRING *lex_string =
|
|
static_cast<LEX_STRING *>(m_thd->alloc(sizeof(LEX_STRING)));
|
|
if (lex_string == nullptr) return nullptr;
|
|
lex_string->length = value.length;
|
|
lex_string->str = m_thd->strmake(value.str, value.length);
|
|
if (lex_string->str == nullptr) return nullptr;
|
|
|
|
PTI_text_literal_underscore_charset *value_string =
|
|
new (m_thd->mem_root) PTI_text_literal_underscore_charset(
|
|
*m_pos, false, system_charset_info,
|
|
*lex_string); // TODO WL#6629 check is_7bit
|
|
if (value_string == nullptr) return nullptr;
|
|
|
|
/* ... FIELD_NAME = <value> ... */
|
|
Item_func_eq *func_eq =
|
|
new (m_thd->mem_root) Item_func_eq(*m_pos, ident_field, value_string);
|
|
|
|
return func_eq;
|
|
}
|
|
|
|
// Add a WHERE clause condition to Select_lex_builder.
|
|
bool Select_lex_builder::add_condition(Item *a) {
|
|
DBUG_ASSERT(a != nullptr);
|
|
|
|
/* ... WHERE cond ... */
|
|
if (m_where_clause == nullptr) {
|
|
m_where_clause = a;
|
|
}
|
|
/* ... WHERE <cond> AND <cond> ... */
|
|
else {
|
|
m_where_clause =
|
|
flatten_associative_operator<Item_cond_and, Item_func::COND_AND_FUNC>(
|
|
m_thd->mem_root, *m_pos, m_where_clause, a);
|
|
|
|
if (m_where_clause == nullptr) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Add a ORDER BY clause field to Select_lex_builder.
|
|
bool Select_lex_builder::add_order_by(const LEX_CSTRING &field_name) {
|
|
/* ... ORDER BY <field_name> ASC... */
|
|
if (!m_order_by_list) {
|
|
m_order_by_list = new (m_thd->mem_root) PT_order_list();
|
|
if (m_order_by_list == nullptr) return true;
|
|
}
|
|
|
|
/* ... FIELD_NAME ... */
|
|
PTI_simple_ident_ident *ident_field =
|
|
new (m_thd->mem_root) PTI_simple_ident_ident(*m_pos, field_name);
|
|
if (ident_field == nullptr) return true;
|
|
|
|
PT_order_expr *expression =
|
|
new (m_thd->mem_root) PT_order_expr(ident_field, ORDER_ASC);
|
|
m_order_by_list->push_back(expression);
|
|
|
|
return expression == nullptr;
|
|
}
|
|
|
|
/**
|
|
This function build ParseTree node that represents this
|
|
Select_lex_builder as sub-query.
|
|
*/
|
|
PT_derived_table *Select_lex_builder::prepare_derived_table(
|
|
const LEX_CSTRING &table_alias) {
|
|
PT_query_primary *query_specification =
|
|
new (m_thd->mem_root) PT_query_specification(
|
|
options, m_select_item_list, m_table_reference_list, m_where_clause);
|
|
|
|
if (query_specification == nullptr) return nullptr;
|
|
|
|
PT_query_expression_body_primary *query_expression_body_primary =
|
|
new (m_thd->mem_root)
|
|
PT_query_expression_body_primary(query_specification);
|
|
if (query_expression_body_primary == nullptr) return nullptr;
|
|
|
|
PT_query_expression *query_expression =
|
|
new (m_thd->mem_root) PT_query_expression(query_expression_body_primary);
|
|
if (query_expression == nullptr) return nullptr;
|
|
|
|
PT_subquery *sub_query =
|
|
new (m_thd->mem_root) PT_subquery(*m_pos, query_expression);
|
|
if (sub_query == nullptr) return nullptr;
|
|
|
|
Create_col_name_list column_names;
|
|
column_names.init(m_thd->mem_root);
|
|
PT_derived_table *derived_table = new (m_thd->mem_root)
|
|
PT_derived_table(false, sub_query, table_alias, &column_names);
|
|
|
|
return derived_table;
|
|
}
|
|
|
|
/**
|
|
Prepare a SELECT_LEX using all the information information
|
|
added to this Select_lex_builder.
|
|
*/
|
|
SELECT_LEX *Select_lex_builder::prepare_select_lex() {
|
|
PT_query_specification *query_specification2 =
|
|
new (m_thd->mem_root) PT_query_specification(
|
|
options, m_select_item_list, m_table_reference_list, m_where_clause);
|
|
if (query_specification2 == nullptr) return nullptr;
|
|
|
|
PT_query_expression_body_primary *query_expression_body_primary2 =
|
|
new (m_thd->mem_root)
|
|
PT_query_expression_body_primary(query_specification2);
|
|
if (query_expression_body_primary2 == nullptr) return nullptr;
|
|
|
|
PT_order *pt_order_by = nullptr;
|
|
if (m_order_by_list) {
|
|
pt_order_by = new (m_thd->mem_root) PT_order(m_order_by_list);
|
|
if (pt_order_by == nullptr) return nullptr;
|
|
}
|
|
|
|
PT_query_expression *query_expression2 =
|
|
new (m_thd->mem_root) PT_query_expression(query_expression_body_primary2,
|
|
pt_order_by, nullptr, nullptr);
|
|
if (query_expression2 == nullptr) return nullptr;
|
|
|
|
LEX *lex = m_thd->lex;
|
|
SELECT_LEX *current_select = lex->current_select();
|
|
|
|
lex->sql_command = SQLCOM_SELECT;
|
|
Parse_context pc(m_thd, current_select);
|
|
if (m_thd->is_error()) return nullptr;
|
|
|
|
if (query_expression2->contextualize(&pc)) return nullptr;
|
|
|
|
return current_select;
|
|
}
|
|
|
|
} // namespace info_schema
|
|
} // namespace dd
|