polardbxengine/sql/parse_tree_node_base.h

264 lines
8.9 KiB
C++

/* 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 <stdarg.h>
#include <cstdlib>
#include <new>
#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 <typename Context>
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 <typename Context>
inline void Parse_tree_node_tmpl<Context>::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_context> Parse_tree_node;
#endif /* PARSE_TREE_NODE_BASE_INCLUDED */