/* Copyright (c) 2013, 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 */ #ifndef PARSE_TREE_NODE_BASE_INCLUDED #define PARSE_TREE_NODE_BASE_INCLUDED #include #include #include #include "memory_debugging.h" #include "my_compiler.h" #include "my_dbug.h" #include "my_inttypes.h" #include "sql/check_stack.h" #include "sql/mem_root_array.h" #include "sql/parse_location.h" #include "sql/sql_const.h" class SELECT_LEX; class THD; struct MEM_ROOT; // uncachable cause #define UNCACHEABLE_DEPENDENT 1 #define UNCACHEABLE_RAND 2 #define UNCACHEABLE_SIDEEFFECT 4 /* For uncorrelated SELECT in an UNION with some correlated SELECTs */ #define UNCACHEABLE_UNITED 8 #define UNCACHEABLE_CHECKOPTION 16 /** Names for different query parse tree parts */ enum enum_parsing_context { CTX_NONE = 0, ///< Empty value CTX_MESSAGE, ///< "No tables used" messages etc. CTX_TABLE, ///< for single-table UPDATE/DELETE/INSERT/REPLACE CTX_SELECT_LIST, ///< SELECT (subquery), (subquery)... CTX_UPDATE_VALUE, ///< UPDATE ... SET field=(subquery)... CTX_INSERT_VALUES, ///< INSERT ... VALUES CTX_INSERT_UPDATE, ///< INSERT ... ON DUPLICATE KEY UPDATE ... CTX_JOIN, CTX_QEP_TAB, CTX_MATERIALIZATION, CTX_DUPLICATES_WEEDOUT, CTX_DERIVED, ///< "Derived" subquery CTX_WHERE, ///< Subquery in WHERE clause item tree CTX_ON, ///< ON clause context CTX_WINDOW, ///< Named or unnamed window CTX_HAVING, ///< Subquery in HAVING clause item tree CTX_ORDER_BY, ///< ORDER BY clause execution context CTX_GROUP_BY, ///< GROUP BY clause execution context CTX_SIMPLE_ORDER_BY, ///< ORDER BY clause execution context CTX_SIMPLE_GROUP_BY, ///< GROUP BY clause execution context CTX_DISTINCT, ///< DISTINCT clause execution context CTX_SIMPLE_DISTINCT, ///< DISTINCT clause execution context CTX_BUFFER_RESULT, ///< see SQL_BUFFER_RESULT in the manual CTX_ORDER_BY_SQ, ///< Subquery in ORDER BY clause item tree CTX_GROUP_BY_SQ, ///< Subquery in GROUP BY clause item tree CTX_OPTIMIZED_AWAY_SUBQUERY, ///< Subquery executed once during optimization CTX_UNION, CTX_UNION_RESULT, ///< Pseudo-table context for UNION result CTX_QUERY_SPEC ///< Inner SELECTs of UNION expression }; /* Note: YYLTYPE doesn't overload a default constructor (as well an underlying Symbol_location). OTOH if we need a zero-initialized POS, YYLTYPE or Symbol_location object, we can simply call POS(), YYLTYPE() or Symbol_location(): C++ does value-initialization in that case. */ typedef YYLTYPE POS; /** Environment data for the contextualization phase */ struct Parse_context { THD *const thd; ///< Current thread handler MEM_ROOT *mem_root; ///< Current MEM_ROOT SELECT_LEX *select; ///< Current SELECT_LEX object Parse_context(THD *thd, SELECT_LEX *sl); }; /** Base class for parse tree nodes (excluding the Parse_tree_root hierarchy) */ template class Parse_tree_node_tmpl { friend class Item; // for direct access to the "contextualized" field Parse_tree_node_tmpl(const Parse_tree_node_tmpl &); // undefined void operator=(const Parse_tree_node_tmpl &); // undefined #ifndef DBUG_OFF private: bool contextualized; // true if the node object is contextualized bool transitional; // TODO: remove that after parser refactoring #endif // DBUG_OFF public: typedef Context context_t; static void *operator new(size_t size, MEM_ROOT *mem_root, const std::nothrow_t &arg MY_ATTRIBUTE((unused)) = std::nothrow) noexcept { return mem_root->Alloc(size); } static void operator delete(void *ptr MY_ATTRIBUTE((unused)), size_t size MY_ATTRIBUTE((unused))) { TRASH(ptr, size); } static void operator delete(void *, MEM_ROOT *, const std::nothrow_t &)noexcept {} protected: Parse_tree_node_tmpl() { #ifndef DBUG_OFF contextualized = false; transitional = false; #endif // DBUG_OFF } public: virtual ~Parse_tree_node_tmpl() {} #ifndef DBUG_OFF bool is_contextualized() const { return contextualized; } #endif // DBUG_OFF /** Do all context-sensitive things and mark the node as contextualized @param pc current parse context @retval false success @retval true syntax/OOM/etc error */ virtual bool contextualize(Context *pc) { #ifndef DBUG_OFF if (transitional) { DBUG_ASSERT(contextualized); return false; } #endif // DBUG_OFF uchar dummy; if (check_stack_overrun(pc->thd, STACK_MIN_SIZE, &dummy)) return true; #ifndef DBUG_OFF DBUG_ASSERT(!contextualized); contextualized = true; #endif // DBUG_OFF return false; } /** Intermediate version of the contextualize() function This function is intended to resolve parser grammar loops. During the step-by-step refactoring of the parser grammar we wrap each context-sensitive semantic action with 3 calls: 1. Parse_tree_node_tmpl() context-independent constructor call, 2. contextualize_() function call to evaluate all context-sensitive things from the former context-sensitive semantic action code. 3. Call of dummy contextualize() function. Then we lift the contextualize() function call to outer grammar rules but save the contextualize_() function call untouched. When all loops in the grammar rules are resolved (i.e. transformed as described above) we: a. remove all contextualize_() function calls and b. rename all contextualize_() function definitions to contextualize() function definitions. Note: it's not necessary to transform the whole grammar and remove this function calls in one pass: it's possible to transform the grammar statement by statement in a way described above. Note: remove this function together with Item::contextualize_(). */ virtual bool contextualize_(Context *) { #ifndef DBUG_OFF DBUG_ASSERT(!contextualized && !transitional); transitional = true; contextualized = true; #endif // DBUG_OFF return false; } /** syntax_error() function replacement for deferred reporting of syntax errors @param pc Current parse context. @param pos Location of the error in lexical scanner buffers. */ void error(Context *pc, const POS &pos) const { pc->thd->syntax_error_at(pos); } /** syntax_error() function replacement for deferred reporting of syntax errors @param pc Current parse context. @param pos Location of the error in lexical scanner buffers. @param msg Error message. */ void error(Context *pc, const POS &pos, const char *msg) const { pc->thd->syntax_error_at(pos, "%s", msg); } /** syntax_error() function replacement for deferred reporting of syntax errors @param pc Current parse context. @param pos Location of the error in lexical scanner buffers. @param format Error message format string with optional argument list. */ void errorf(Context *pc, const POS &pos, const char *format, ...) const MY_ATTRIBUTE((format(printf, 4, 5))); }; template inline void Parse_tree_node_tmpl::errorf(Context *pc, const POS &pos, const char *format, ...) const { va_list args; va_start(args, format); pc->thd->vsyntax_error_at(pos, format, args); va_end(args); } typedef Parse_tree_node_tmpl Parse_tree_node; #endif /* PARSE_TREE_NODE_BASE_INCLUDED */