forked from StoneAtom/StoneDB
215 lines
6.6 KiB
C++
215 lines
6.6 KiB
C++
/* Copyright (c) 2013, 2021, Oracle and/or its affiliates.
|
|
|
|
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_INCLUDED
|
|
#define PARSE_TREE_NODE_INCLUDED
|
|
|
|
#include "my_config.h"
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include "my_sys.h"
|
|
#include "sql_const.h"
|
|
|
|
#include "parse_location.h"
|
|
|
|
class THD;
|
|
class st_select_lex;
|
|
|
|
// 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_LIST, ///< UPDATE ... SET field=(subquery)...
|
|
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_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
|
|
st_select_lex * select; ///< Current SELECT_LEX object
|
|
|
|
Parse_context(THD *thd, st_select_lex *select);
|
|
};
|
|
|
|
|
|
// defined in sql_parse.cc:
|
|
bool check_stack_overrun(THD *thd, long margin, uchar *dummy);
|
|
|
|
|
|
/**
|
|
Base class for parse tree nodes
|
|
*/
|
|
class Parse_tree_node
|
|
{
|
|
friend class Item; // for direct access to the "contextualized" field
|
|
|
|
Parse_tree_node(const Parse_tree_node &); // undefined
|
|
void operator=(const Parse_tree_node &); // undefined
|
|
|
|
#ifndef NDEBUG
|
|
private:
|
|
bool contextualized; // true if the node object is contextualized
|
|
bool transitional; // TODO: remove that after parser refactoring
|
|
#endif//NDEBUG
|
|
|
|
public:
|
|
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
|
|
{ return alloc_root(mem_root, size); }
|
|
static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
|
|
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
|
|
|
|
protected:
|
|
Parse_tree_node()
|
|
{
|
|
#ifndef NDEBUG
|
|
contextualized= false;
|
|
transitional= false;
|
|
#endif//NDEBUG
|
|
}
|
|
|
|
public:
|
|
virtual ~Parse_tree_node() {}
|
|
|
|
#ifndef NDEBUG
|
|
bool is_contextualized() const { return contextualized; }
|
|
#endif//NDEBUG
|
|
|
|
/**
|
|
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(Parse_context *pc)
|
|
{
|
|
#ifndef NDEBUG
|
|
if (transitional)
|
|
{
|
|
assert(contextualized);
|
|
return false;
|
|
}
|
|
#endif//NDEBUG
|
|
|
|
uchar dummy;
|
|
if (check_stack_overrun(pc->thd, STACK_MIN_SIZE, &dummy))
|
|
return true;
|
|
|
|
#ifndef NDEBUG
|
|
assert(!contextualized);
|
|
contextualized= true;
|
|
#endif//NDEBUG
|
|
|
|
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() 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_(Parse_context *pc)
|
|
{
|
|
#ifndef NDEBUG
|
|
assert(!contextualized && !transitional);
|
|
transitional= true;
|
|
contextualized= true;
|
|
#endif//NDEBUG
|
|
return false;
|
|
}
|
|
|
|
void error(Parse_context *pc,
|
|
const POS &position,
|
|
const char * msg= NULL) const;
|
|
};
|
|
|
|
#endif /* PARSE_TREE_NODE_INCLUDED */
|