Compare commits

..

26 Commits

Author SHA1 Message Date
XL_up 8e1236d519 Update tcap_manager.cpp 2023-10-02 14:12:23 +08:00
XL_up ffd5d15617 Update tcap_drop.cpp 2023-10-02 00:37:49 +08:00
XL_up d5d6a7a17e Update analyze.cpp 2023-10-01 23:12:48 +08:00
XL_up d064984625 Update tcap_drop.cpp 2023-10-01 18:42:32 +08:00
XL_up e649815e3a Update parse_oper.cpp 2023-10-01 15:45:37 +08:00
XL_up 5de15c1e08 Update prepjointree.cpp 2023-09-28 17:26:51 +08:00
XL_up c95b024884 Update prepjointree.cpp 2023-09-26 21:00:48 +08:00
XL_up 363bbba83a Update prepnonjointree.cpp 2023-09-19 21:55:00 +08:00
XL_up 304749b6ef Update prepnonjointree.cpp 2023-09-19 19:25:05 +08:00
XL_up 2951191031 Update prepnonjointree.cpp 2023-09-19 18:25:15 +08:00
XL_up 550305c80a Update scansup.cpp 2023-09-15 13:39:43 +08:00
XL_up 5d259833d0 Update analyze.cpp 2023-08-31 11:04:44 +08:00
XL_up afe278d162 Update parse_param.cpp 2023-08-31 00:17:19 +08:00
XL_up 519962b095 Update parse_oper.cpp 2023-08-31 00:13:17 +08:00
XL_up 44dcab4ab7 Update parse_oper.cpp 2023-08-30 23:51:33 +08:00
XL_up ee97a711ee Update parse_oper.cpp 2023-08-30 23:30:30 +08:00
XL_up 6a0a170d45 Update rewriteSupport.cpp 2023-08-28 23:15:33 +08:00
XL_up 3916fbd442 Update rewriteRemove.cpp 2023-08-28 23:15:23 +08:00
XL_up ed22d5c2e2 Update rewriteHandler.cpp 2023-08-28 23:15:06 +08:00
XL_up 52fe47cf55 Update parse_oper.cpp 2023-08-28 23:12:56 +08:00
XL_up 6743204011 Update parse_param.cpp 2023-08-28 23:12:40 +08:00
XL_up 70cd993234 Update scansup.cpp 2023-08-28 23:12:14 +08:00
XL_up af24481deb Update parser.cpp 2023-08-28 23:11:58 +08:00
XL_up 488c48fab0 Update kwlookup.cpp 2023-08-28 23:11:42 +08:00
XL_up 8e01f2eeeb Update keywords.cpp 2023-08-28 23:11:19 +08:00
XL_up 7b9a65f8d9 Update analyze.cpp 2023-08-28 23:10:52 +08:00
14 changed files with 4631 additions and 3392 deletions

View File

@ -152,31 +152,55 @@ static const char* NOKEYUPDATE_KEYSHARE_ERRMSG = "";
* transformation, while utility-type statements are simply hung off
* a dummy CMD_UTILITY Query node.
*/
/*
* @DescriptionAnalyze the raw syntax tree, do semantic analysis and output query tree.
* @Param[IN] parseTree: a raw parse tree(abstract syntax tree).
* @Param[IN] sourceText: The source text of the query statement.
* @Param[IN] numParams: number of params.
* @Param[IN] paramTypes: stores the type OID of each parameter.
* @Returnan analyzed query tree(of Query class).
*/
Query* parse_analyze(
Node* parseTree, const char* sourceText, Oid* paramTypes, int numParams, bool isFirstNode, bool isCreateView)
{
// Initialization of ParseState object.
ParseState* pstate = make_parsestate(NULL);
// Declaration of the query tree.
Query* query = NULL;
/* required as of 8.4 */
// sourceText can't be NULL.
AssertEreport(sourceText != NULL, MOD_OPT, "para cannot be NULL");
pstate->p_sourcetext = sourceText;
if (numParams > 0) {
/*
* parse_fixed_parameters() was defined in parse_param.cpp.
*
* This function converts the reference contained in the query into a
* fixed parameter structure, that is, pass in the reference parameters
* of the query statement and constructs a FixedParamState structure
* for it.
*/
parse_fixed_parameters(pstate, paramTypes, numParams);
}
PUSH_SKIP_UNIQUE_SQL_HOOK();
// Converts the raw parse tree into a query tree.
query = transformTopLevelStmt(pstate, parseTree, isFirstNode, isCreateView);
POP_SKIP_UNIQUE_SQL_HOOK();
POP_SKIP_UNIQUE_SQL_HOOK();
/* it's unsafe to deal with plugins hooks as dynamic lib may be released */
if (post_parse_analyze_hook && !(g_instance.status > NoShutdown)) {
(*post_parse_analyze_hook)(pstate, query);
}
pfree_ext(pstate->p_ref_hook_state);
// release the ParseState object pstate.
free_parsestate(pstate);
/* For plpy CTAS query. CTAS is a recursive call. CREATE query is the first rewrited.
@ -185,7 +209,8 @@ Query* parse_analyze(
*/
query->fixed_paramTypes = paramTypes;
query->fixed_numParams = numParams;
// return the analyzed raw parse tree, that is, the query tree.
return query;
}
@ -1959,6 +1984,9 @@ List* BuildExcludedTargetlist(Relation targetrel, Index exclRelIndex)
return result;
}
/*
* check Rls policy for DUPLICATE KEY UPDATE clause.
*/
static bool CheckRlsPolicyForUpsert(Relation targetrel)
{
ListCell *item = NULL;
@ -1997,6 +2025,11 @@ static bool ContainSubLink(Node* clause)
}
#endif /* ENABLE_MULTIPLE_NODES */
/*
* process the DUPLICATE KEY UPDATE clause.
*
* DUPLICATE KEY UPDATE clause: perform update command if the insert already exists.
*/
static UpsertExpr* transformUpsertClause(ParseState* pstate, UpsertClause* upsertClause, RangeVar* relation)
{
UpsertExpr* result = NULL;
@ -3752,6 +3785,9 @@ static bool checkExecDirectVariableSetStmt(const Node* node)
}
#endif
/*
* Given a nodename, fetch its index and nodetype.
*/
static void get_index_and_type_from_nodename(const char* node_name, int* node_index, char* node_type)
{
Oid node_oid;
@ -3771,6 +3807,23 @@ static void get_index_and_type_from_nodename(const char* node_name, int* node_in
return;
}
/*
* Determines the execution type of a remote query node by given nodetype and
* execution direct option ExecDirectOption.
*
* exec_type could only take the following four values:
* ---- EXEC_ON_COORDS: Indicates that the query will be executed on the coordinator.
* Under this execution type, the query is sent to the coordinator
* node for execution and the results are returned from the
* coordinator node.
* ---- EXEC_ON_DATANODES: Indicates that the query will execute on the data node.
* Under this execution type, the query is executed on a remote
* data node and returns results from that node.
* ---- EXEC_ON_NONE: Indicates that the query does not need to be executed remotely.
* Under this execution type, the query is executed on the current
* node and does not need to be sent to the remote node.
* ---- EXEC_ON_ALL_NODES: Indicates that the query may execute on any type of node.
*/
RemoteQueryExecType fill_exec_type(char node_type, ExecDirectOption option)
{
RemoteQueryExecType exec_type;
@ -3800,6 +3853,9 @@ RemoteQueryExecType fill_exec_type(char node_type, ExecDirectOption option)
return exec_type;
}
/*
* raise an error if the node's index is illegal.
*/
void check_node_index(int node_index, char* node_flag, int length_node_flag)
{
if ((node_flag != NULL) &&
@ -3875,6 +3931,9 @@ static void fill_node_list_and_exec_type(const List* nodenames_list, ExecDirectO
return;
}
/*
* Set ExecDirectType by given command type.
*/
ExecDirectType set_exec_direct_type(bool is_local, CmdType command_type)
{
ExecDirectType type = EXEC_DIRECT_NONE;
@ -3915,6 +3974,9 @@ ExecDirectType set_exec_direct_type(bool is_local, CmdType command_type)
return type;
}
/*
* raise an error if command type is CMD_MERGE or CMD_NOTHING.
*/
void check_command_type(CmdType command_type)
{
if (command_type == CMD_MERGE) {
@ -4007,6 +4069,9 @@ static Query* generate_query_execdirect_statement(const ExecDirectStmt* stmt)
return result;
}
/*
* Needed initialization work by planner.
*/
static void init_execdirect_utility_stmt(RemoteQuery* step, const char* statement)
{
step->cursor = NULL;
@ -4706,8 +4771,14 @@ static bool checkAllowedTableCombination(ParseState* pstate)
bool has_ustore = false;
bool has_else = false;
// Check range table list for the presence of
// relations with different storages
/*
* Check range table list for the presence of relations with different storages.
*
* p_rtable is an array of pointers to a RangeTblEntry that stores information about
* all the tables that appear in the query during the parsing phase. The RangeTblEntry
* structure stores table aliases, table names, column information, and so on. With
* p_rtable, we can get the details of all the tables involved in the query.
*/
foreach(lc, pstate->p_rtable) {
rte = (RangeTblEntry*)lfirst(lc);
if (rte && rte->rtekind == RTE_RELATION) {
@ -4719,7 +4790,14 @@ static bool checkAllowedTableCombination(ParseState* pstate)
}
}
// Check target table for the type of storage
/*
* Check target table for the type of storage
*
* p_target_rangetblentry points to the RangeTblEntry structure of the target
* table being parsed in p_rtable. During parsing, p_target_rangetblentry is
* used to track the target table that is currently being parsed so that subsequent
* processing can be properly applied to that table.
*/
rte = pstate->p_target_rangetblentry;
if (rte && rte->rtekind == RTE_RELATION) {
if (rte->is_ustore) {

View File

@ -21,9 +21,11 @@
#define PG_KEYWORD(a, b, c) {a, b, c},
// A table that stores keywords information.
// This table will be used in keyword-matching process.
const ScanKeyword ScanKeywords[] = {
#include "parser/kwlist.h"
};
// The number of table items, which is also the total number of keywords
const int NumScanKeywords = lengthof(ScanKeywords);

View File

@ -28,7 +28,7 @@
*
* Returns a pointer to the ScanKeyword table entry, or NULL if no match.
*
* The match is done case-insensitively. Note that we deliberately use a
* The match is done case-insensitively. Note that we deliberately use a
* dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z',
* even if we are in a locale where tolower() would produce more or different
* translations. This is to conform to the SQL99 spec, which says that
@ -36,13 +36,20 @@
* receive a different case-normalization mapping.
*/
const ScanKeyword* ScanKeywordLookup(const char* text, const ScanKeyword* keywords, int num_keywords)
{
{ /*
* @param[IN] textThe identifier to be matched.
* @param[IN] keywordsA pointer to the keyword table.
* @param[IN] num_keywords: The number of keywords table items (keywords).
* @param[OUT]A pointer to a keywords table item. Null is returned if the match fails.
*/
int len, i;
char word[NAMEDATALEN] = {0};
const ScanKeyword* low = NULL;
const ScanKeyword* high = NULL;
char word[NAMEDATALEN] = {0};
const ScanKeyword* low = NULL; // Pointer used in the binary search.
const ScanKeyword* high = NULL; // Pointer used in the binary search.
if (text == NULL) {
// The input is NULL, no match is made, and NULL is returned.
if (text == NULL) {
return NULL;
}
@ -64,7 +71,7 @@ const ScanKeyword* ScanKeywordLookup(const char* text, const ScanKeyword* keywor
}
word[i] = ch;
}
word[len] = '\0';
word[len] = '\0'; // The converted text should ends with '\0'.
/*
* Now do a binary search using plain strcmp() comparison.
@ -85,6 +92,6 @@ const ScanKeyword* ScanKeywordLookup(const char* text, const ScanKeyword* keywor
high = middle - 1;
}
}
// The binary search fails and returns a null value.
return NULL;
}
}

View File

@ -57,9 +57,9 @@ typedef struct OprCacheKey {
typedef struct OprCacheEntry {
/* the hash lookup key MUST BE FIRST */
OprCacheKey key;
Oid opr_oid; /* OID of the resolved operator */
OprCacheKey key;
/* OID of the resolved operator */
Oid opr_oid;
} OprCacheEntry;
static Oid binary_oper_exact(List* opname, Oid arg1, Oid arg2, bool use_a_style_coercion);
@ -90,12 +90,18 @@ static void make_oper_cache_entry(OprCacheKey* key, Oid opr_oid);
Oid LookupOperName(ParseState* pstate, List* opername, Oid oprleft, Oid oprright, bool noError, int location)
{
Oid result;
// Search the operator Oid according to the value of OprCacheKey.left_arg.oprname,
// OprCacheKey.left_arg and OprCacheKey.right_arg.
// Returns result if the lookup is successful.
result = OpernameGetOprid(opername, oprleft, oprright);
if (OidIsValid(result))
return result;
/* we don't use op_error here because only an exact match is wanted */
// The lookup fails, and passed-in param noError = false,
// Indicates that the caller allows a lookup failure to be treated as an error.
// This if-branch is used to report the error messages.
if (!noError) {
char oprkind;
@ -127,6 +133,7 @@ Oid LookupOperNameTypeNames(
{
Oid leftoid, rightoid;
/* fetch type's OID by given TypeNames */
if (oprleft == NULL)
leftoid = InvalidOid;
else
@ -166,9 +173,9 @@ void get_sort_group_operators(
{
TypeCacheEntry* typentry = NULL;
int cache_flags;
Oid lt_opr;
Oid eq_opr;
Oid gt_opr;
Oid lt_opr; // '<'
Oid eq_opr; // '='
Oid gt_opr; // '>'
bool hashable = false;
/*
@ -183,9 +190,9 @@ void get_sort_group_operators(
cache_flags = TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR;
typentry = lookup_type_cache(argtype, cache_flags);
lt_opr = typentry->lt_opr;
eq_opr = typentry->eq_opr;
gt_opr = typentry->gt_opr;
lt_opr = typentry->lt_opr;
eq_opr = typentry->eq_opr;
gt_opr = typentry->gt_opr;
hashable = OidIsValid(typentry->hash_proc);
/* Report errors if needed */
@ -210,7 +217,11 @@ void get_sort_group_operators(
*isHashable = hashable;
}
/* given operator tuple, return the operator OID */
/*
* given operator tuple, return the operator OID.
*
* This is a wrapper of HeapTupleGetOid().
*/
Oid oprid(Operator op)
{
return HeapTupleGetOid(op);
@ -224,6 +235,12 @@ Oid oprfuncid(Operator op)
return pgopform->oprcode;
}
/*
* Given operator tuple, check if the operator is a shell.
*
* Returns tup after casting to Form_pg_operator, or raise
* an error if op passed in is only a shell.
*/
static Form_pg_operator check_operator_is_shell(List* opname, ParseState* pstate, int location, Operator tup)
{
Form_pg_operator opform = (Form_pg_operator)GETSTRUCT(tup);
@ -237,6 +254,13 @@ static Form_pg_operator check_operator_is_shell(List* opname, ParseState* pstate
return opform;
}
/*
* Find mapping tuple in SysCache by given cache key.
*
* Look for a cache entry matching the given key and get the
* contained operator OID. If found, call SearchSysCache1()
* to lookup mapping HeapTuple in cache by operator OID.
*/
static HeapTuple find_mapping_in_cache(OprCacheKey key, bool key_ok)
{
HeapTuple tup = NULL;
@ -487,12 +511,17 @@ Oid compatible_oper_opid(List* op, Oid arg1, Oid arg2, bool noError)
Operator optup;
Oid result;
/* given binary opname and OIDs of its args, find the operator tuple. */
optup = compatible_oper(NULL, op, arg1, arg2, noError, -1);
if (optup != NULL) {
/* given operator tuple, return the operator OID. */
result = oprid(optup);
/* release the unit of optup in SysCache. */
ReleaseSysCache(optup);
return result;
}
return InvalidOid;
}
@ -529,6 +558,7 @@ Operator right_oper(ParseState* pstate, List* op, Oid arg, bool noError, int loc
* First try for an "exact" match.
*/
operOid = OpernameGetOprid(op, arg, InvalidOid);
if (!OidIsValid(operOid)) {
/*
* Otherwise, search for the most suitable candidate.
@ -681,7 +711,8 @@ static void op_error(
}
/*
* Operator expression construction.
* make_op
* Operator expression construction.
*
* Transform operator expression ensuring type compatibility.
* This is where some type conversion happens.
@ -691,19 +722,25 @@ static void op_error(
*/
Expr* make_op(ParseState* pstate, List* opname, Node* ltree, Node* rtree, int location, bool inNumeric)
{
Oid ltypeId, rtypeId;
Operator tup;
Form_pg_operator opform;
Oid actual_arg_types[2];
Oid declared_arg_types[2];
int nargs;
List* args = NIL;
Oid rettype;
OpExpr* result = NULL;
// Enter the operator name and the structure tree of the left and right operators,
// and then construct the expression structure for them.
Oid ltypeId, rtypeId; // Oid of left operator and right operator
Operator tup; // The Operator structure to get before constructing OpExpr
Form_pg_operator opform; // Related to type conversion between Pg_Operator and Operator
Oid actual_arg_types[2]; // Oid of the actual left, right operator determined by ltree, rtree
Oid declared_arg_types[2]; // Oid declared in Pg
int nargs; // the number of left and right operators(0/1/2).
List* args = NIL; // tree structure representing the left and right operators
Oid rettype; // Oid of the operator type returned
OpExpr* result = NULL; // The expression structure returned
/* Select the operator */
// Get the OID of the left and right operators, and then obtain
// the Operator structure of the left and right operators accordingly
if (rtree == NULL) {
/* right operator */
/* right operator */
ltypeId = exprType(ltree);
rtypeId = InvalidOid;
tup = right_oper(pstate, opname, ltypeId, false, location);
@ -724,7 +761,7 @@ Expr* make_op(ParseState* pstate, List* opname, Node* ltree, Node* rtree, int lo
}
tup = oper(pstate, opname, ltypeId, rtypeId, false, location, inNumeric);
}
// Related to type conversion between Pg_Operator and Operator
opform = check_operator_is_shell(opname, pstate, location, tup);
/* Do typecasting and build the expression tree */
@ -732,13 +769,13 @@ Expr* make_op(ParseState* pstate, List* opname, Node* ltree, Node* rtree, int lo
/* right operator */
args = list_make1(ltree);
actual_arg_types[0] = ltypeId;
declared_arg_types[0] = opform->oprleft;
nargs = 1;
declared_arg_types[0] = opform->oprleft;
nargs = 1;
} else if (ltree == NULL) {
/* left operator */
args = list_make1(rtree);
actual_arg_types[0] = rtypeId;
declared_arg_types[0] = opform->oprright;
args = list_make1(rtree);
actual_arg_types[0] = rtypeId;
declared_arg_types[0] = opform->oprright;
nargs = 1;
} else {
/* otherwise, binary operator */
@ -747,7 +784,7 @@ Expr* make_op(ParseState* pstate, List* opname, Node* ltree, Node* rtree, int lo
actual_arg_types[1] = rtypeId;
declared_arg_types[0] = opform->oprleft;
declared_arg_types[1] = opform->oprright;
nargs = 2;
nargs = 2; // Both the left operator and the right operator are valid.
}
/*
@ -755,6 +792,7 @@ Expr* make_op(ParseState* pstate, List* opname, Node* ltree, Node* rtree, int lo
* possibly adjusting return type or declared_arg_types (which will be
* used as the cast destination by make_fn_arguments)
*/
// Oid of the operator type returned
rettype = enforce_generic_type_consistency(actual_arg_types, declared_arg_types, nargs, opform->oprresult, false);
/* perform the necessary typecasting of arguments */
@ -762,17 +800,17 @@ Expr* make_op(ParseState* pstate, List* opname, Node* ltree, Node* rtree, int lo
/* and build the expression node */
result = makeNode(OpExpr);
result->opno = oprid(tup);
result->opfuncid = opform->oprcode;
result->opresulttype = rettype;
result->opno = oprid(tup);
result->opfuncid = opform->oprcode;
result->opresulttype = rettype;
result->opretset = get_func_retset(opform->oprcode);
/* opcollid and inputcollid will be set by parse_collate.c */
result->args = args;
result->location = location;
result->args = args;
result->location = location;
ReleaseSysCache(tup);
ReleaseSysCache(tup); // Release the cache space
return (Expr*)result;
return (Expr*)result; // Returned as an Expr* type
}
/*

View File

@ -3,7 +3,7 @@
* parse_param.cpp
* handle parameters in parser
*
* This code covers two cases that are used within the core backend:
* This code covers two cases that are used within the core backend:
* * a fixed list of parameters with known types
* * an expandable list of parameters whose types can optionally
* be determined from context
@ -33,7 +33,8 @@
#include "utils/builtins.h"
#include "utils/lsyscache.h"
typedef struct FixedParamState {
// Stmt of fixed parameters.
typedef struct FixedParamState {
Oid* paramTypes; /* array of parameter type OIDs */
int numParams; /* number of array entries */
} FixedParamState;
@ -44,6 +45,7 @@ typedef struct FixedParamState {
* hasn't been seen, while UNKNOWNOID means the parameter has been used but
* its type is not yet known.
*/
// Stmt of variable parameters.
typedef struct VarParamState {
Oid** paramTypes; /* array of parameter type OIDs */
int* numParams; /* number of array entries */
@ -64,10 +66,12 @@ static bool check_parameter_resolution_walker(Node* node, ParseState* pstate);
*/
void parse_fixed_parameters(ParseState* pstate, Oid* paramTypes, int numParams)
{
// palloc for FixedParamState.
FixedParamState* parstate = (FixedParamState*)palloc(sizeof(FixedParamState));
// Construct the FixedParamState structure.
parstate->paramTypes = paramTypes;
parstate->numParams = numParams;
pstate->p_ref_hook_state = (void*)parstate;
pstate->p_paramref_hook = fixed_paramref_hook;
/* no need to use p_coerce_param_hook */
@ -78,10 +82,12 @@ void parse_fixed_parameters(ParseState* pstate, Oid* paramTypes, int numParams)
*/
void parse_variable_parameters(ParseState* pstate, Oid** paramTypes, int* numParams)
{
// palloc for VarParamState
VarParamState* parstate = (VarParamState*)palloc(sizeof(VarParamState));
// Construct the VarParamState structure.
parstate->paramTypes = paramTypes;
parstate->numParams = numParams;
pstate->p_ref_hook_state = (void*)parstate;
pstate->p_paramref_hook = variable_paramref_hook;
pstate->p_coerce_param_hook = variable_coerce_param_hook;
@ -103,7 +109,9 @@ static Node* fixed_paramref_hook(ParseState* pstate, ParamRef* pref)
errmsg("there is no parameter $%d", paramno),
parser_errposition(pstate, pref->location)));
}
param = makeNode(Param);
/* construct the Param structure for pref. */
param->paramkind = PARAM_EXTERN;
param->paramid = paramno;
param->paramtype = parstate->paramTypes[paramno - 1];
@ -265,10 +273,10 @@ static bool check_parameter_resolution_walker(Node* node, ParseState* pstate)
if (node == NULL) {
return false;
}
if (IsA(node, Param)) {
Param* param = (Param*)node;
if (IsA(node, Param)) { // If the current node is an object of the Param class
Param* param = (Param*)node;
if (param->paramkind == PARAM_EXTERN) {
if (param->paramkind == PARAM_EXTERN) { // If param is external
VarParamState* parstate = (VarParamState*)pstate->p_ref_hook_state;
int paramno = param->paramid;
@ -288,7 +296,7 @@ static bool check_parameter_resolution_walker(Node* node, ParseState* pstate)
}
return false;
}
if (IsA(node, Query)) {
if (IsA(node, Query)) { // If the current node is an object of the Query class
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
return query_tree_walker((Query*)node, (bool (*)())check_parameter_resolution_walker, (void*)pstate, 0);
}

View File

@ -9,7 +9,6 @@
* the grammar are "raw" parsetrees that still need to be analyzed by
* analyze.c and related files.
*
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
@ -40,15 +39,15 @@ static void resetCreateFuncFlag()
/*
* raw_parser
* Given a query in string form, do lexical and grammatical analysis.
* Given a query in string form, do lexical and grammatical analysis.
*
* Returns a list of raw (un-analyzed) parse trees.
*/
List* raw_parser(const char* str, List** query_string_locationlist)
{
core_yyscan_t yyscanner;
base_yy_extra_type yyextra;
int yyresult;
core_yyscan_t yyscanner;
base_yy_extra_type yyextra; // An intermediate variable that holds the returned syntax tree.
int yyresult; // The calling result of base_yyparse().
/* reset u_sess->parser_cxt.stmt_contains_operator_plus */
resetOperatorPlusFlag();
@ -58,7 +57,7 @@ List* raw_parser(const char* str, List** query_string_locationlist)
/* reset u_sess->parser_cxt.isCreateFuncOrProc */
resetCreateFuncFlag();
/* initialize the flex scanner */
yyscanner = scanner_init(str, &yyextra.core_yy_extra, ScanKeywords, NumScanKeywords);
@ -89,6 +88,7 @@ List* raw_parser(const char* str, List** query_string_locationlist)
}
}
// Returns the generated syntax tree.
return yyextra.parsetree;
}
@ -127,7 +127,7 @@ List* raw_parser(const char* str, List** query_string_locationlist)
* words. Furthermore it's not clear how to do it without re-introducing
* scanner backtrack, which would cost more performance than this filter
* layer does.
*
*
* The filter also provides a convenient place to translate between
* the core_YYSTYPE and YYSTYPE representations (which are really the
* same thing anyway, but notationally they're different).
@ -489,8 +489,8 @@ int base_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, core_yyscan_t yyscanner)
/*
* @Description: Check whether its a empty query with only comments and semicolon.
* @Param query_string: the query need check.
* @retrun:true or false.
* @Param[IN] query_string: the query need check.
* @return:the bool value of the check result.
*/
static bool is_empty_query(char* query_string)
{
@ -513,6 +513,7 @@ static bool is_empty_query(char* query_string)
end_comment_postion = strstr(query_string, end_comment);
query_string = end_comment_postion + 2;
while (isspace((unsigned char)*query_string)) {
// Trim the spaces after comments.
query_string++;
}
}
@ -537,11 +538,12 @@ static bool is_empty_query(char* query_string)
char** get_next_snippet(
char** query_string_single, const char* query_string, List* query_string_locationlist, int* stmt_num)
{
int query_string_location_start = 0;
int query_string_location_end = -1;
char* query_string_single_p = NULL;
int single_query_string_len = 0;
int query_string_location_start = 0; // The starting position of the query statement.
int query_string_location_end = -1; // The ending position of the query statement.
char* query_string_single_p = NULL; // An intermediate variable used to copy the string.
int single_query_string_len = 0; // The length of the query statement.
// Count the number of query statements.
int stmt_count = list_length(query_string_locationlist);
/* Malloc memory for single query here just for the first time. */
@ -558,11 +560,13 @@ char** get_next_snippet(
* Notice : The locationlist only store the end postion of each single query but not any
* start postion.
*/
// Calculate the starting position of the specified query statement.
if (*stmt_num == 0) {
query_string_location_start = 0;
} else {
query_string_location_start = list_nth_int(query_string_locationlist, *stmt_num - 1) + 1;
}
// Calculate the ending position of the specified query statement.
query_string_location_end = list_nth_int(query_string_locationlist, (*stmt_num)++);
/* Malloc memory for each single query string. */
@ -583,10 +587,10 @@ char** get_next_snippet(
*/
if (is_empty_query(query_string_single[*stmt_num - 1])) {
continue;
} else {
} else { // The obtained query statement is not a null query, exit the loop, and return this statement.
break;
}
}
return query_string_single;
}
}

View File

@ -21,30 +21,29 @@
#include "parser/scansup.h"
#include "mb/pg_wchar.h"
/* ----------------
* scanstr
*
* if the string passed in has escaped codes, map the escape codes to actual
* chars
/*
* scanstr() --- if the string passed in has escaped codes, map the escape
* codes to actual chars.
*
* the string returned is palloc'd and should eventually be pfree'd by the
* caller!
* ----------------
*/
char* scanstr(const char* s)
{
char* newStr = NULL;
int len, i, j;
if (s == NULL || s[0] == '\0')
if (s == NULL || s[0] == '\0') // The input string is empty.
return pstrdup("");
len = strlen(s);
newStr = (char*)palloc(len + 1); /* string cannot get longer */
// The new string constructed does not exceed the length of the original string.
// That is because the processes of the escape code would get the string shorter.
newStr = (char*)palloc(len + 1); /* string cannot get longer */
for (i = 0, j = 0; i < len; i++) {
if (s[i] == '\'') {
if (s[i] == '\'') {
/*
* Note: if scanner is working right, unescaped quotes can only
* appear in pairs, so there should be another character.
@ -52,11 +51,11 @@ char* scanstr(const char* s)
i++;
newStr[j] = s[i];
} else if (s[i] == '\\') {
i++;
i++; // "\" and a next character are translated together into an escape symbol.
switch (s[i]) {
case 'b':
newStr[j] = '\b';
break;
break;
case 'f':
newStr[j] = '\f';
break;
@ -76,18 +75,20 @@ char* scanstr(const char* s)
case '4':
case '5':
case '6':
case '7': {
case '7': {
// case '0'~'7', represents this is the highest bit of an octal number.
int k;
unsigned long octVal = 0;
// Converts the next consecutive digits of up to three 0-7 digits into an octal number.
for (k = 0; s[i + k] >= '0' && s[i + k] <= '7' && k < 3; k++){
octVal = (octVal << 3) + (s[i + k] - '0');
}
i += k - 1;
newStr[j] = ((char)octVal);
// According to the octal numeric value corresponding to the ASCII code to determine the specific characters.
newStr[j] = ((char)octVal);
} break;
default:
newStr[j] = s[i];
newStr[j] = s[i];
break;
} /* switch */
} /* s[i] == '\\' */
@ -96,7 +97,7 @@ char* scanstr(const char* s)
}
j++;
}
newStr[j] = '\0';
newStr[j] = '\0'; // The new string constructed should end with '\0'.
return newStr;
}
@ -120,6 +121,8 @@ char* downcase_truncate_identifier(const char* ident, int len, bool warn)
bool enc_is_single_byte = false;
result = (char*)palloc(len + 1);
// Gets the maximum byte of the database encoding.
// enc_is_single_byte = TRUE IF it is single-byte encoding.
enc_is_single_byte = pg_database_encoding_max_length() == 1;
/*
@ -131,7 +134,7 @@ char* downcase_truncate_identifier(const char* ident, int len, bool warn)
* the high bit set, as long as they aren't part of a multi-byte character,
* and use an ASCII-only downcasing for 7-bit characters.
*/
for (i = 0; i < len; i++) {
for (i = 0; i < len; i++) { // Implementation of downcasing.
unsigned char ch = (unsigned char)ident[i];
if (ch >= 'A' && ch <= 'Z') {
@ -143,7 +146,8 @@ char* downcase_truncate_identifier(const char* ident, int len, bool warn)
}
result[i] = '\0';
if (i >= NAMEDATALEN)
// The length exceeds the identifier's maximum length, so truncate.
if (i >= NAMEDATALEN)
truncate_identifier(result, i, warn);
return result;
@ -152,15 +156,13 @@ char* downcase_truncate_identifier(const char* ident, int len, bool warn)
/*
* truncate_identifier() --- truncate an identifier to NAMEDATALEN-1 bytes.
*
* The given string is modified in-place, if necessary. A warning is
* issued if requested.
*
* We require the caller to pass in the string length since this saves a
* strlen() call in some common usages.
*/
void truncate_identifier(char* ident, int len, bool warn)
{
if (len >= NAMEDATALEN) {
// Calculate the appropriate length after truncation.
len = pg_mbcliplen(ident, len, NAMEDATALEN - 1);
if (warn) {
/*
@ -169,17 +171,21 @@ void truncate_identifier(char* ident, int len, bool warn)
*/
char buf[NAMEDATALEN];
errno_t rc;
rc = memcpy_s(buf, NAMEDATALEN, ident, len);
securec_check(rc, "\0", "\0");
buf[len] = '\0';
ereport(NOTICE,
(errcode(ERRCODE_NAME_TOO_LONG), errmsg("identifier \"%s\" will be truncated to \"%s\"", ident, buf)));
}
ident[len] = '\0';
// Truncate by setting the end character of the identifier to '\0'.
ident[len] = '\0';
}
}
/*
* scanner_isspace() --- return TRUE if flex scanner considers char whitespace
*
@ -197,4 +203,4 @@ bool scanner_isspace(char ch)
}
return false;
}
}

View File

@ -93,7 +93,7 @@ static bool jointree_contains_lateral_outer_refs(Node *jtnode,
bool restricted, Relids safe_upper_varnos);
static void replace_vars_in_jointree(Node* jtnode, pullup_replace_vars_context* context, JoinExpr* lowest_nulling_outer_join);
static Node* pullup_replace_vars(Node* expr, pullup_replace_vars_context* context);
static Node* pullup_replace_vars_callback(Var* var, replace_rte_variables_context* context);
static Node* pullup_replace_vars_callback(Var* var, replace_rte_variables_context* contextreduce_outer_joins;
static Query *pullup_replace_vars_subquery(Query *query, pullup_replace_vars_context *context);
static reduce_outer_joins_state* reduce_outer_joins_pass1(Node* jtnode);
static void reduce_outer_joins_pass2(Node* jtnode, reduce_outer_joins_state* state, PlannerInfo* root,
@ -157,6 +157,7 @@ void replace_empty_jointree(Query *parse)
}
#ifndef ENABLE_MULTIPLE_NODES
/*
* helper function to check if SWCB ctes contaisn in current SubQuery, normally help us to
* idenfity if it is OK to appy SWCB related optimization steps
@ -182,6 +183,7 @@ static bool contains_swctes(const PlannerInfo *root)
return found;
}
#endif
/*
@ -280,10 +282,14 @@ Node* assign_qual_clause(Node* new_node, Node* old_node, Node* qual, Relids old_
if (qual == NULL) {
return new_node;
}
/*
* Extracts the varnos (the relationship to which the variables belong) of all the vars in the expression.
* The collection containing these varnos is preserved in qual_varnos.
*/
Relids qual_varnos = pull_varnos(qual);
/*
* We need add this quals to new_node if old_node_relids can not include qual_varnos.
* than can happend when or_clause pull up.
* We need add this quals to new_node if old_node_relids can not include qual_varnos,
* which can happen when or_clause pull up.
*/
if (!bms_is_subset(qual_varnos, old_node_relids)) {
if (IsA(new_node, FromExpr)) {
@ -858,10 +864,11 @@ void inline_set_returning_functions(PlannerInfo* root)
}
/*
* This recursively processes the jointree and returns a modified jointree.
* pull_up_subqueries() ---
* Wrapper function of pull_up_subqueries_recurse(). This function
* recursively processes the jointree and returns a modified jointree.
*/
Node *
pull_up_subqueries(PlannerInfo *root, Node *jtnode)
Node * pull_up_subqueries(PlannerInfo *root, Node *jtnode)
{
/* Start off with no containing join nor appendrel */
return pull_up_subqueries_recurse(root, jtnode, NULL, NULL, NULL);
@ -1039,6 +1046,16 @@ void pull_up_subquery_hint(PlannerInfo* root, Query* parse, HintState* hint_stat
}
}
/*
* is_subquery_partial_push()
*
* Determines whether a subquery can be partially pushed optimized, which refers
* to pushing part of the computation operation of the subquery to an upper query
* to reduce the computation of the subquery and improve the query performance.
*
* This routine checks the conditions and expressions in the subquery to see if
* they can be pushed to an external query for processing.
*/
static bool is_subquery_partial_push(PlannerInfo* root, RangeTblEntry* rte)
{
@ -1783,6 +1800,10 @@ static bool is_simple_subquery(Query* subquery, RangeTblEntry *rte, JoinExpr *lo
* We require all the setops to be UNION ALL (no mixing) and there can't be
* any datatype coercions involved, ie, all the leaf queries must emit the
* same datatypes.
*
* This routine does some simple pre-judging processes and error checking,
* and calls is_simple_union_all_recurse() to recursively check through the
* setop tree to see if it's a simple UNION ALL setop structure.
*/
static bool is_simple_union_all(Query* subquery)
{
@ -1815,13 +1836,17 @@ static bool is_simple_union_all(Query* subquery)
return is_simple_union_all_recurse((Node*)topop, subquery, topop->colTypes);
}
/*
* is_simple_union_all_recurse
* Recursively check through the setop tree to see if it's a simple UNION ALL
*/
static bool is_simple_union_all_recurse(Node* setOp, Query* setOpQuery, List* colTypes)
{
if (IsA(setOp, RangeTblRef)) {
RangeTblRef* rtr = (RangeTblRef*)setOp;
RangeTblEntry* rte = rt_fetch(rtr->rtindex, setOpQuery->rtable);
Query* subquery = rte->subquery;
/* Leaf nodes in setop tree must be subqueries. */
AssertEreport(subquery != NULL, MOD_OPT_REWRITE, "subquery should not be NULL in is_simple_union_all_recurse");
/* Leaf nodes are OK if they match the toplevel column types */
@ -1834,7 +1859,7 @@ static bool is_simple_union_all_recurse(Node* setOp, Query* setOpQuery, List* co
if (op->op != SETOP_UNION || !op->all)
return false;
/* Recurse to check inputs */
/* Recurse into each argument to check. */
return is_simple_union_all_recurse(op->larg, setOpQuery, colTypes) &&
is_simple_union_all_recurse(op->rarg, setOpQuery, colTypes);
} else {
@ -2282,6 +2307,11 @@ void flatten_simple_union_all(PlannerInfo* root)
while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
leftmostjtnode = ((SetOperationStmt*)leftmostjtnode)->larg;
/*
* The leaf nodes in setop tree must be a RangeTblRef type and the members
* of UNION must be subqueries specified in SELECT statement. Else, raise
* an err.
*/
if (leftmostjtnode && IsA(leftmostjtnode, RangeTblRef)) {
leftmostRTI = ((RangeTblRef*)leftmostjtnode)->rtindex;
leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
@ -2501,12 +2531,15 @@ static reduce_outer_joins_state* reduce_outer_joins_pass1(Node* jtnode)
return result;
if (IsA(jtnode, RangeTblRef)) {
int varno = ((RangeTblRef*)jtnode)->rtindex;
/* only include rtindex of current rtr node. */
result->relids = bms_make_singleton(varno);
} else if (IsA(jtnode, FromExpr)) {
FromExpr* f = (FromExpr*)jtnode;
ListCell* l = NULL;
/*
* Recursively process each member in jointree and merge
* the information gathered.
*/
foreach (l, f->fromlist) {
reduce_outer_joins_state* sub_state = NULL;
@ -2522,7 +2555,10 @@ static reduce_outer_joins_state* reduce_outer_joins_pass1(Node* jtnode)
/* join's own RT index is not wanted in result->relids */
if (IS_OUTER_JOIN(j->jointype))
result->contains_outer = true;
/*
* Process each argument of JOIN expression and merge
* the information gathered.
*/
sub_state = reduce_outer_joins_pass1(j->larg);
result->relids = bms_add_members(result->relids, sub_state->relids);
result->contains_outer |= sub_state->contains_outer;
@ -2926,6 +2962,10 @@ void remove_result_refs(PlannerInfo *root, int varno, Node *newjtloc)
*/
}
/*
* Traverses the query tree to find the PlaceholderVar node associated
* with the specified external parameter.
*/
bool find_dependent_phvs_walker(Node *node,
find_dependent_phvs_context *context)
{
@ -2959,6 +2999,10 @@ bool find_dependent_phvs_walker(Node *node,
(void *) context);
}
/*
* Wrapper function of query_or_expression_tree_walker. Find the
* PlaceholderVar node associated with the specified external parameter.
*/
bool find_dependent_phvs(Node *node, int varno)
{
find_dependent_phvs_context context;
@ -2992,6 +3036,9 @@ typedef struct {
Relids subrelids;
} substitute_multiple_relids_context;
/*
* Recursively replace multiple relids in the query plan with new relids.
*/
static bool substitute_multiple_relids_walker(Node* node, substitute_multiple_relids_context* context)
{
if (node == NULL)
@ -3032,6 +3079,11 @@ static bool substitute_multiple_relids_walker(Node* node, substitute_multiple_re
return expression_tree_walker(node, (bool (*)())substitute_multiple_relids_walker, (void*)context);
}
/*
* Replace multiple relids in the query plan with new relids. This function is typically
* used to process query statements that contain multiple relationships. It ensures that
* the query plan references the relevant relationships correctly.
*/
static void substitute_multiple_relids(Node* node, int varno, Relids subrelids)
{
substitute_multiple_relids_context context;
@ -3580,6 +3632,9 @@ static Node* reduce_inequality_fulljoins_jointree_recurse(PlannerInfo* root, Nod
return jtnode;
}
/*
* Look into the plan tree and see if any qual involves with rownum.
*/
extern bool find_rownum_in_quals(PlannerInfo *root)
{
if (root->parse == NULL) {
@ -3608,7 +3663,9 @@ extern bool find_rownum_in_quals(PlannerInfo *root)
return hasRownum;
}
/*
* Check if current node of Query tree has a rownum qual.
*/
bool ContainRownumQual(const Query *parse)
{
if (!IsA(parse->jointree, FromExpr)) {

View File

@ -2113,36 +2113,50 @@ Query* lazyagg_main(Query* parse)
/* ------------------------------------------------------------ */
/* Lazy Agg : end */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* Reduce orderby : begin */
/* Reduce orderby : begin */
/* ------------------------------------------------------------ */
static void reduce_orderby_final(RangeTblEntry* rte, bool reduce);
static void reduce_orderby_recurse(Query* query, Node* jtnode, bool reduce);
/* Reduce orderby clause in subquery for join and setop */
/*
* reduce_orderby_recurse
* recurse check join node and reduce order by final for RangeTblRef.
* reduce_orderby_recurse() ---
* Recurse in a jointree or a setop tree and try to reduce redundant orderby clauses.
*
* @param (in) query: the query tree for reduce orderby
* @param (in) jtnode: join node for RangeTblRef/FromExpr/JoinExpr/SetOperationStmt
* @ Caller: reduce_orderby()
*
* @return: void
* @ Param [IN] query: current node of query tree.
* @ Param [IN] jtnode: jointree node for RangeTblRef/FromExpr/JoinExpr or setop tree
* node for SetOperationStmt.
* @ Param [IN] reduce: the flag identifier that runs through the recursing
* process that decide whether to reduce the orderby clause for subquery.
* @ Returns: void
*
* Note: this routine is the main recursive procedure through the orderby reducing
* process. It will recursively traverses a jointree or a setop tree in an attempt
* to drop redundant orderby clauses for it.
*/
static void reduce_orderby_recurse(Query* query, Node* jtnode, bool reduce)
{
/* query isn't in a from-where clause, join-structure or an aggregation. */
if (jtnode == NULL)
return;
/* jtnode point to an entity relation table that is referred by subquery. */
if (IsA(jtnode, RangeTblRef)) {
int varno = ((RangeTblRef*)jtnode)->rtindex;
RangeTblEntry* rte = rt_fetch(varno, query->rtable);
/* Reduce orderby clause in subquery for join or from clause of more than one rte */
/* Try to drop orderby-clause on this RTE. */
reduce_orderby_final(rte, reduce);
} else if (IsA(jtnode, FromExpr)) {
}else if (IsA(jtnode, FromExpr)) {
#ifndef ENABLE_MULTIPLE_NODES
/* If there is ROWNUM, can not reduce orderby clause in subquery from fromlist.
/*
* If there is ROWNUM, can not reduce orderby clause in subquery from fromlist.
* For example, If there is a SQL {select * from table_name where rownum < n union
* select * from (select * from table_name order by column_name desc) where rownum < n;},
* can not reduce orderby clause here.
@ -2151,20 +2165,30 @@ static void reduce_orderby_recurse(Query* query, Node* jtnode, bool reduce)
return;
}
#endif
FromExpr* f = (FromExpr*)jtnode;
ListCell* l = NULL;
bool flag = false;
/*
* If the number of tables referenced by the from-where clause is 1, then there are two
* situations: If the from-clause is at the top of the query, then we don't need to drop
* this orderby; Otherwise the query refers to more than one table, at which point we
* can try to drop the orderby-clause of the tables referenced by current from-clause.
*/
if (1 == list_length(f->fromlist))
flag = reduce;
else
flag = true;
/* Recurse into each reference of from-clause to reduce its orderby. */
foreach (l, f->fromlist)
reduce_orderby_recurse(query, (Node*)lfirst(l), flag);
} else if (IsA(jtnode, JoinExpr)) {
/* top level of a join-clause. */
JoinExpr* j = (JoinExpr*)jtnode;
/* Recurse into each argument to reduce its orderby. */
if ((JOIN_INNER == j->jointype) || (JOIN_LEFT == j->jointype) || (JOIN_SEMI == j->jointype) ||
(JOIN_ANTI == j->jointype) || (JOIN_FULL == j->jointype) || (JOIN_RIGHT == j->jointype) ||
(JOIN_LEFT_ANTI_FULL == j->jointype) || (JOIN_RIGHT_ANTI_FULL == j->jointype)) {
@ -2177,8 +2201,10 @@ static void reduce_orderby_recurse(Query* query, Node* jtnode, bool reduce)
errmsg("unrecognized join type: %d", (int)j->jointype)));
}
} else if (IsA(jtnode, SetOperationStmt)) {
/* top level of a aggregate clause. */
SetOperationStmt* op = (SetOperationStmt*)jtnode;
/* Recurse into each argument to reduce its orderby. */
reduce_orderby_recurse(query, op->larg, true);
reduce_orderby_recurse(query, op->rarg, true);
}
@ -2186,38 +2212,58 @@ static void reduce_orderby_recurse(Query* query, Node* jtnode, bool reduce)
return;
}
/*
* reduce_orderby_final
* Reduce order by clause for subquery for join and setop if the subquery have sortClause.
*
* @param (in) rte: the RTE of subquery for reduce orderby.
* @param (in) reduce: the flag identify if reduce the orderby clause or not.
*
* @return: void
* reduce_orderby_final() ---
* Reduce orderby clause for subquery if it has a removable sortClause.
*
* @ Caller: reduce_orderby_recurse()
*
* @ Param [IN] rte: the RTE of subquery whose orderby clause needs to be reduced.
* @ Param [IN] reduce: the flag identify that runs through the recursing
* process that decide whether to reduce the orderby clause for subquery.
* @ Returns: void
*/
static void reduce_orderby_final(RangeTblEntry* rte, bool reduce)
{
/* Reduce orderby clause in subquery for join or from clause of more than one rte */
/*
* Both subquery's limitOffset and limitCount are NULL, which shows that
* the orderby-clause on this RTE does not use LIMIT-clause to specify
* a subset of the query results.
*/
if (rte->rtekind == RTE_SUBQUERY) {
if (reduce && rte->subquery->sortClause && !rte->subquery->limitOffset && !rte->subquery->limitCount) {
pfree_ext(rte->subquery->sortClause);
rte->subquery->sortClause = NULL;
}
/* Recurse into subquery of current subquery to reduce its orderby. */
reduce_orderby(rte->subquery, reduce);
}
return;
}
/*
* reduce_orderby
* The entry of reduce orderby which called by subquery_planner.
* reduce_orderby() ---
* The entry point of orderby reducing process.
*
* @ Caller: subquery_planner()
*
* @ Param [IN] query: current node of query tree.
* @ Param [IN] reduce: the flag identifier that runs through the recursing
* process that decide whether to reduce the orderby clause for subquery.
* @ Returns: void
*
* @param (in) query: the query tree for reduce orderby.
* @param (in) reduce: the flag identify if reduce the orderby clause or not.
*
* @return: void
* Note: when this routine called by subquery_planner(), the passed-in
* parameter reduce would always be FALSE. And this argument would be used
* to decide whether to reduce a orderby clause for subquery in function
* reduce_orderby_final().
*
* Note: through the recursing process, function reduce_orderby_final()
* would also call this routine. When it's called by reduce_orderby_final(),
* the value of reduce could be TRUE or FALSE.
*/
void reduce_orderby(Query* query, bool reduce)
{
@ -2227,21 +2273,33 @@ void reduce_orderby(Query* query, bool reduce)
if (query == NULL)
return;
/* If subquery in insert or update, it should find select query and deside whether reduce order by in subquery or
* not. */
/*
* If subquery is not a SELECT, we should find SELECT query and deside
* whether to reduce orderby in subquery or not.
*/
if (query->commandType != CMD_SELECT) {
foreach (l, query->rtable) {
rte = (RangeTblEntry*)lfirst(l);
/*
* Recurse into subqueries to locate orderby and decide
* whether to reduce it.
*/
if (rte->rtekind == RTE_SUBQUERY)
reduce_orderby(rte->subquery, reduce);
}
return;
}
/* Recurse find subquery in form,join or subquery, and deside whether reduce order by in subquery or not. */
/*
* Recurse to find subquerys in from-where clause, join clause or aggregation
* structure, and to decide whether to drop its orderby.
*/
reduce_orderby_recurse(query, (Node*)query->jointree, reduce);
/* If there has setop, it should optimize orderby clause. */
/*
* If this is the top-level node of a setop tree, we shall recurse into
* its arguments and try to reduce orderby for each argument.
*/
if (query->setOperations) {
reduce_orderby_recurse(query, ((SetOperationStmt*)query->setOperations)->larg, true);
reduce_orderby_recurse(query, ((SetOperationStmt*)query->setOperations)->rarg, true);
@ -2249,4 +2307,5 @@ void reduce_orderby(Query* query, bool reduce)
}
/* ------------------------------------------------------------ */
/* Reduce orderby : end */
/* Reduce orderby : end */
/* ------------------------------------------------------------ */

View File

@ -127,6 +127,15 @@ static bool pull_qual_vars_walker(Node* node, pull_qual_vars_context* context);
*/
void AcquireRewriteLocks(Query* parsetree, bool forUpdatePushedDown)
{
/*
* @Param[IN] parsetree: A query tree. We need to acquire suitable
* locks on all the relations mentioned in the Query.
* @Param[IN] forUpdatePushedDown: Indicates that whether there is a
* pushed-down FOR UPDATE/SHARE statement that applies to the
* current subquery. It should always be false at the start
* of the recursion.
* @Return[OUT]: None.
*/
ListCell* l = NULL;
int rt_index;
@ -1712,6 +1721,7 @@ static bool fireRIRonSubLink(Node* node, List* activeRIRs)
/*
* fireRIRrules -
* Apply all RIR rules on each rangetable entry in a query
*
*/
static Query* fireRIRrules(Query* parsetree, List* activeRIRs, bool forUpdatePushedDown)
{
@ -1733,7 +1743,8 @@ static Query* fireRIRrules(Query* parsetree, List* activeRIRs, bool forUpdatePus
int i;
++rt_index;
// fetch RTE of current parsetree node.
rte = rt_fetch(rt_index, parsetree->rtable);
/*
@ -2699,14 +2710,17 @@ static List* RewriteQuery(Query* parsetree, List* rewrite_events)
return rewritten;
}
/*
* QueryRewrite -
* Primary entry point to the query rewriter.
* Rewrite one query via query rewrite system, possibly returning 0
* or many queries.
*
* NOTE: the parsetree must either have come straight from the parser,
* or have been scanned by AcquireRewriteLocks to acquire suitable locks.
* QueryRewrite()---
*
* @DescriptionPrimary entry point to the query rewriter.
* Rewrite one query via query rewrite system, possibly returning 0
* or many queries.
* @Param[IN] parsetreeA Query Tree. It must either have come straight
* from the parser, or have been scanned by AcquireRewriteLocks to
* acquire suitable locks.
* @Return[OUT] Rewrited queries(0 or several queries).
*/
List* QueryRewrite(Query* parsetree)
{
@ -2722,6 +2736,7 @@ List* QueryRewrite(Query* parsetree)
* This function is only applied to top-level original queries
*/
AssertEreport(parsetree->querySource == QSRC_ORIGINAL, MOD_OPT, "");
AssertEreport(parsetree->canSetTag, MOD_OPT, "");
/*
* Step 1
@ -2733,11 +2748,12 @@ List* QueryRewrite(Query* parsetree)
/*
* Step 2
*
* Apply all the RIR rules on each query
* Apply all the RIR rules on each query
*
* This is also a handy place to mark each query with the original queryId
*/
results = NIL;
foreach (l, querylist) {
Query* query = (Query*)lfirst(l);
@ -3270,4 +3286,4 @@ List* QueryRewriteCTAS(Query* parsetree)
}
}
}
#endif
#endif

View File

@ -33,7 +33,7 @@
#include "utils/snapmgr.h"
/*
* Guts of rule deletion.
* Deletes an existing rewrite rule.
*/
void RemoveRewriteRuleById(Oid ruleOid)
{
@ -45,12 +45,15 @@ void RemoveRewriteRuleById(Oid ruleOid)
Oid eventRelationOid;
/*
* Open the pg_rewrite relation.
* Open the pg_rewrite relation, and impose an RowExclusiveLock.
*
* RewriteRelationId is external. The caller specifies a specific
* relation by setting its value.
*/
RewriteRelation = heap_open(RewriteRelationId, RowExclusiveLock);
/*
* Find the tuple for the target rule.
* Fetch the tuple for the target rule.
*/
ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(ruleOid));
@ -58,6 +61,9 @@ void RemoveRewriteRuleById(Oid ruleOid)
tuple = systable_getnext(rcscan);
/*
* If the fetch fails, error information is reported
*/
if (!HeapTupleIsValid(tuple))
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("could not find tuple for rule %u", ruleOid)));
@ -76,14 +82,15 @@ void RemoveRewriteRuleById(Oid ruleOid)
systable_endscan(rcscan);
heap_close(RewriteRelation, RowExclusiveLock);
/*
* Issue shared-inval notice to force all backends (including me!) to
* update relcache entries with the new rule set.
*/
heap_close(RewriteRelation, RowExclusiveLock);
CacheInvalidateRelcache(event_relation);
/* Close rel, but keep lock till commit... */
heap_close(event_relation, NoLock);
}
}

View File

@ -31,7 +31,12 @@
#include "utils/snapmgr.h"
/*
* Is there a rule by the given name?
* IsDefinedRewriteRule()---
*
* @Description: Verifies that a relationship has an rewrite rule by a given name.
* @Param[IN] owningRel: Oid of a specified relation.
* @Param[IN] ruleName: Name of the rewrite rule.
* @Return[OUT]: A bool value representing the validation result.
*/
bool IsDefinedRewriteRule(Oid owningRel, const char* ruleName)
{
@ -90,11 +95,15 @@ void SetRelationRuleStatus(Oid relationId, bool relHasRules, bool relIsBecomingV
}
/*
* Find rule oid.
* get_rewrite_oid()---
*
* If missing_ok is false, throw an error if rule name not found. If
* true, just return InvalidOid.
*/
* @Description: Find the Oid of a rewrite rule by given its name and rel Oid.
* @Param[IN] relid: Oid of a specified relation.
* @Param[IN] ruleName: Name of the rewrite rule.
* @Param[IN] missing_ok: If missing_ok is false, throw an error if rule name
* not found. If true, just return InvalidOid.
* @Return[OUT]: Rule Oid.
*/
Oid get_rewrite_oid(Oid relid, const char* rulename, bool missing_ok)
{
HeapTuple tuple;
@ -115,6 +124,17 @@ Oid get_rewrite_oid(Oid relid, const char* rulename, bool missing_ok)
return ruleoid;
}
/*
* get_rewrite_rulename()---
*
* @Description: Like get_rewrite_oid(), find the name of a rewrite rule by
* given its Oid and relid. Relid is specified by the caller by setting
* the value of RewriteRelationId, which is an external variable.
* @Param[IN] ruleid: Oid of the specified rewrite rule.
* @Param[IN] missing_ok: If missing_ok is false, throw an error if rule Oid
* not found. If true, just return InvalidOid.
* @Return[OUT]: Rule name.
*/
char* get_rewrite_rulename(Oid ruleid, bool missing_ok)
{
ScanKeyData entry;
@ -146,10 +166,16 @@ char* get_rewrite_rulename(Oid ruleid, bool missing_ok)
}
/*
* input parameter relid is ev_class, ev_type is pg_rewrite->ev_type, CMD_UTILITY means notify, copy, alter rule,
* rel_has_rule()---
*
* @Description: Given a specific relation and check if it has defined rewriting rule of ev_type.
* @Param[IN] relid: ev_class, Oid of the specified relation.
* @Param[IN] ev_type: CmdType, transfer it to char beacuse it is char in system catalog pg_rewrite.
* @Return[OUT]: A bool value representing the validation result.
*
* Note: ev_type is pg_rewrite->ev_type, CMD_UTILITY means notify, copy, alter rule,
* latter two is only used in timeseries table redistribution
* ev_type is CmdType, transfer it to char beacuse it is char in system catalog pg_rewrite
*/
*/
bool rel_has_rule(Oid relid, char ev_type)
{
bool has_rule = false;
@ -172,13 +198,20 @@ bool rel_has_rule(Oid relid, char ev_type)
}
/*
* Find rule oid, given only a rule name but no rel OID.
* get_rewrite_oid_without_relid()---
*
* If there's more than one, it's an error. If there aren't any, that's an
* @Description: Find rule oid, given only a rule name but no rel OID.
* @Param[IN] ruleName: Name of the rewrite rule.
* @Param[IN] reloid: A pointer to Oid List of all relations.
* @Param[IN] missing_ok: If missing_ok is false, throw an error if rule Oid
* not found. If true, just return InvalidOid.
* @Return[OUT]: Rule Oid or InvalidOid if not found.
*
* Note: If there's more than one, it's an error. If there aren't any, that's an
* error, too. In general, this should be avoided - it is provided to support
* syntax that is compatible with pre-7.3 versions of PG, where rule names
* were unique across the entire database.
*/
*/
Oid get_rewrite_oid_without_relid(const char* rulename, Oid* reloid, bool missing_ok)
{
Relation RewriteRelation;
@ -214,4 +247,4 @@ Oid get_rewrite_oid_without_relid(const char* rulename, Oid* reloid, bool missin
heap_close(RewriteRelation, AccessShareLock);
return ruleoid;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff