forked from huawei/openGauss-server
为src/common/backend/parser下文件添加了部分注释 #1
|
|
@ -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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @Description:Analyze 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.
|
||||
* @Return:an 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;
|
||||
}
|
||||
|
||||
|
|
@ -228,6 +253,7 @@ Query* parse_analyze_varparams(Node* parseTree, const char* sourceText, Oid** pa
|
|||
/*
|
||||
* parse_sub_analyze
|
||||
* Entry point for recursively analyzing a sub-statement.
|
||||
* 递归分析子查询的入口函数
|
||||
*/
|
||||
Query* parse_sub_analyze(Node* parseTree, ParseState* parentParseState, CommonTableExpr* parentCTE,
|
||||
bool locked_from_parent, bool resolve_unknowns)
|
||||
|
|
@ -4732,4 +4758,4 @@ static bool checkAllowedTableCombination(ParseState* pstate)
|
|||
Assert(has_ustore || has_else);
|
||||
|
||||
return !(has_ustore && has_else);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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] text:The identifier to be matched.
|
||||
* @param[IN] keywords:A 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* parse_oper.cpp
|
||||
* handle operator things for parser
|
||||
* 处理表达式中的操作符
|
||||
*
|
||||
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
|
|
@ -45,21 +46,24 @@
|
|||
*/
|
||||
|
||||
/* If your search_path is longer than this, sucks to be you ... */
|
||||
// search_path的最大长度
|
||||
#define MAX_CACHED_PATH_LEN 16
|
||||
|
||||
typedef struct OprCacheKey {
|
||||
char oprname[NAMEDATALEN];
|
||||
char oprname[NAMEDATALEN]; // operator名称
|
||||
Oid left_arg; /* Left input OID, or 0 if prefix op */
|
||||
// 左侧操作符的OID,如果这是一个前缀操作符则此项为0.
|
||||
Oid right_arg; /* Right input OID, or 0 if postfix op */
|
||||
Oid search_path[MAX_CACHED_PATH_LEN];
|
||||
// 右侧操作符的OID,如果这是一个后缀操作符则此项为0.
|
||||
Oid search_path[MAX_CACHED_PATH_LEN]; // 搜索路径
|
||||
bool use_a_style_coercion;
|
||||
} 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; // 解决后的OID
|
||||
} OprCacheEntry;
|
||||
|
||||
static Oid binary_oper_exact(List* opname, Oid arg1, Oid arg2, bool use_a_style_coercion);
|
||||
|
|
@ -90,12 +94,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;
|
||||
|
||||
|
|
@ -166,9 +176,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 of '<'
|
||||
Oid eq_opr; // Oid of '='
|
||||
Oid gt_opr; // Oid of '>'
|
||||
bool hashable = false;
|
||||
|
||||
/*
|
||||
|
|
@ -183,9 +193,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 */
|
||||
|
|
@ -681,7 +691,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 +702,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 +741,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 +749,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 +764,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 +772,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 +780,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
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1026,4 +1044,4 @@ void InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
|
|||
if (hash_search(u_sess->parser_cxt.opr_cache_hash, (void*)&hentry->key, HASH_REMOVE, NULL) == NULL)
|
||||
ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("hash table corrupted")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -265,10 +271,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,9 +294,9 @@ 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);
|
||||
}
|
||||
return expression_tree_walker(node, (bool (*)())check_parameter_resolution_walker, (void*)pstate);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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,14 +171,17 @@ 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';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -197,4 +202,4 @@ bool scanner_isspace(char ch)
|
|||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue