From cad509e32bdeceefa01316d49a4e6e7c94639523 Mon Sep 17 00:00:00 2001 From: qbkrr <1195300755@qq.com> Date: Sun, 30 Oct 2022 16:16:36 +0800 Subject: [PATCH 1/2] Delete 'src/common/backend/parser/parse_node.cpp' --- src/common/backend/parser/parse_node.cpp | 548 ----------------------- 1 file changed, 548 deletions(-) delete mode 100644 src/common/backend/parser/parse_node.cpp diff --git a/src/common/backend/parser/parse_node.cpp b/src/common/backend/parser/parse_node.cpp deleted file mode 100644 index 3430ad52e..000000000 --- a/src/common/backend/parser/parse_node.cpp +++ /dev/null @@ -1,548 +0,0 @@ -/* ------------------------------------------------------------------------- - * - * parse_node.cpp - * various routines that make nodes for querytrees - * - * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * Portions Copyright (c) 2021, openGauss Contributors - * - * - * IDENTIFICATION - * src/common/backend/parser/parse_node.cpp - * - * ------------------------------------------------------------------------- - */ -#include "postgres.h" -#include "knl/knl_variable.h" - -#include "access/heapam.h" -#include "catalog/pg_type.h" -#include "mb/pg_wchar.h" -#include "nodes/makefuncs.h" -#include "nodes/nodeFuncs.h" -#include "parser/parsetree.h" -#include "parser/parse_coerce.h" -#include "parser/parse_expr.h" -#include "parser/parse_relation.h" -#include "utils/builtins.h" -#include "utils/int8.h" -#include "utils/lsyscache.h" -#include "utils/syscache.h" -#include "utils/varbit.h" - -static void pcb_error_callback(void* arg); - -/* - * make_parsestate - * Allocate and initialize a new ParseState. - * - * Caller should eventually release the ParseState via free_parsestate(). - */ -ParseState* make_parsestate(ParseState* parentParseState) -{ - ParseState* pstate = NULL; - - pstate = (ParseState*)palloc0(sizeof(ParseState)); - - pstate->parentParseState = parentParseState; - - pstate->isAliasReplace = true; - - /* Fill in fields that don't start at null/false/zero */ - pstate->p_next_resno = 1; - pstate->p_star_start = NIL; - pstate->p_star_end = NIL; - pstate->p_star_only = NIL; - pstate->p_resolve_unknowns = true; - pstate->ignoreplus = false; - pstate->p_plusjoin_rte_info = NULL; - pstate->p_rawdefaultlist = NIL; - - if (parentParseState != NULL) { - pstate->p_sourcetext = parentParseState->p_sourcetext; - /* all hooks are copied from parent */ - pstate->p_pre_columnref_hook = parentParseState->p_pre_columnref_hook; - pstate->p_post_columnref_hook = parentParseState->p_post_columnref_hook; - pstate->p_paramref_hook = parentParseState->p_paramref_hook; - pstate->p_coerce_param_hook = parentParseState->p_coerce_param_hook; - pstate->p_ref_hook_state = parentParseState->p_ref_hook_state; - pstate->p_create_proc_operator_hook = parentParseState->p_create_proc_operator_hook; - pstate->p_create_proc_insert_hook = parentParseState->p_create_proc_insert_hook; - pstate->p_cl_hook_state = parentParseState->p_cl_hook_state; - pstate->p_bind_variable_columnref_hook = parentParseState->p_bind_variable_columnref_hook; - pstate->p_bind_hook_state = parentParseState->p_bind_hook_state; - pstate->p_bind_describe_hook = parentParseState->p_bind_describe_hook; - pstate->p_describeco_hook_state = parentParseState->p_describeco_hook_state; - } - - return pstate; -} - -/* - * free_parsestate - * Release a ParseState and any subsidiary resources. - */ -void free_parsestate(ParseState* pstate) -{ - Assert(pstate != NULL); - /* - * Check that we did not produce too many resnos; at the very least we - * cannot allow more than 2^16, since that would exceed the range of a - * AttrNumber. It seems safest to use MaxTupleAttributeNumber. - */ - if (pstate->p_next_resno - 1 > MaxTupleAttributeNumber) { - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("target lists can have at most %d entries", MaxTupleAttributeNumber))); - } - if (pstate->p_target_relation != NULL) { - heap_close(pstate->p_target_relation, NoLock); - } - pfree_ext(pstate); -} - -/* - * parser_errposition - * Report a parse-analysis-time cursor position, if possible. - * - * This is expected to be used within an ereport() call. The return value - * is a dummy (always 0, in fact). - * - * The locations stored in raw parsetrees are byte offsets into the source - * string. We have to convert them to 1-based character indexes for reporting - * to clients. (We do things this way to avoid unnecessary overhead in the - * normal non-error case: computing character indexes would be much more - * expensive than storing token offsets.) - */ -int parser_errposition(ParseState* pstate, int location) -{ - int pos; - - /* No-op if location was not provided */ - if (location < 0) { - return 0; - } - /* Can't do anything if source text is not available */ - if (pstate == NULL || pstate->p_sourcetext == NULL) { - return 0; - } - /* Convert offset to character number */ - pos = pg_mbstrlen_with_len(pstate->p_sourcetext, location) + 1; - /* And pass it to the ereport mechanism */ - return errposition(pos); -} - -/* - * setup_parser_errposition_callback - * Arrange for non-parser errors to report an error position - * - * Sometimes the parser calls functions that aren't part of the parser - * subsystem and can't reasonably be passed a ParseState; yet we would - * like any errors thrown in those functions to be tagged with a parse - * error location. Use this function to set up an error context stack - * entry that will accomplish that. Usage pattern: - * - * declare a local variable "ParseCallbackState pcbstate" - * ... - * setup_parser_errposition_callback(&pcbstate, pstate, location); - * call function that might throw error; - * cancel_parser_errposition_callback(&pcbstate); - */ -void setup_parser_errposition_callback(ParseCallbackState* pcbstate, ParseState* pstate, int location) -{ - /* Setup error traceback support for ereport() */ - pcbstate->pstate = pstate; - pcbstate->location = location; - pcbstate->errcontext.callback = pcb_error_callback; - pcbstate->errcontext.arg = (void*)pcbstate; - pcbstate->errcontext.previous = t_thrd.log_cxt.error_context_stack; - t_thrd.log_cxt.error_context_stack = &pcbstate->errcontext; -} - -/* - * Cancel a previously-set-up errposition callback. - */ -void cancel_parser_errposition_callback(ParseCallbackState* pcbstate) -{ - /* Pop the error context stack */ - t_thrd.log_cxt.error_context_stack = pcbstate->errcontext.previous; -} - -/* - * Error context callback for inserting parser error location. - * - * Note that this will be called for *any* error occurring while the - * callback is installed. We avoid inserting an irrelevant error location - * if the error is a query cancel --- are there any other important cases? - */ -static void pcb_error_callback(void* arg) -{ - ParseCallbackState* pcbstate = (ParseCallbackState*)arg; - - if (geterrcode() != ERRCODE_QUERY_CANCELED) { - (void)parser_errposition(pcbstate->pstate, pcbstate->location); - } -} - -/* - * For timeseries table to identify hidden column type and return NULL or - * build a Var node for an attribute identified by RTE and attrno for others. - */ -Var* ts_make_var(ParseState* pstate, RangeTblEntry* rte, int attrno, int location) -{ - Oid var_type_id; - int32 type_mod; - Oid var_collid; - int kv_type = ATT_KV_UNDEFINED; - get_rte_attribute_type(rte, attrno, &var_type_id, &type_mod, &var_collid, &kv_type); - if (kv_type == ATT_KV_HIDE) { - return NULL; - } - - Var* result = NULL; - int vnum, sublevels_up; - vnum = RTERangeTablePosn(pstate, rte, &sublevels_up); - result = makeVar(vnum, attrno, var_type_id, type_mod, var_collid, sublevels_up); - result->location = location; - return result; -} - -/* - * make_var - * Build a Var node for an attribute identified by RTE and attrno - */ -Var* make_var(ParseState* pstate, RangeTblEntry* rte, int attrno, int location) -{ - Var* result = NULL; - int vnum, sublevels_up; - Oid vartypeid; - int32 type_mod; - Oid varcollid; - - vnum = RTERangeTablePosn(pstate, rte, &sublevels_up); - get_rte_attribute_type(rte, attrno, &vartypeid, &type_mod, &varcollid); - result = makeVar(vnum, attrno, vartypeid, type_mod, varcollid, sublevels_up); - result->location = location; - return result; -} - -/* - * transformArrayType() - * Identify the types involved in a subscripting operation - * - * On entry, arrayType/arrayTypmod identify the type of the input value - * to be subscripted (which could be a domain type). These are modified - * if necessary to identify the actual array type and typmod, and the - * array's element type is returned. An error is thrown if the input isn't - * an array type. - */ -Oid transformArrayType(Oid* arrayType, int32* arrayTypmod) -{ - Oid origArrayType = *arrayType; - Oid elementType; - HeapTuple type_tuple_array; - Form_pg_type type_struct_array; - - /* - * If the input is a domain, smash to base type, and extract the actual - * typmod to be applied to the base type. Subscripting a domain is an - * operation that necessarily works on the base array type, not the domain - * itself. (Note that we provide no method whereby the creator of a - * domain over an array type could hide its ability to be subscripted.) - */ - *arrayType = getBaseTypeAndTypmod(*arrayType, arrayTypmod); - - /* Get the type tuple for the array */ - type_tuple_array = SearchSysCache1(TYPEOID, ObjectIdGetDatum(*arrayType)); - if (!HeapTupleIsValid(type_tuple_array)) { - ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for type %u", *arrayType))); - } - type_struct_array = (Form_pg_type)GETSTRUCT(type_tuple_array); - - /* needn't check typisdefined since this will fail anyway */ - - elementType = type_struct_array->typelem; - if (elementType == InvalidOid) { - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("cannot subscript type %s because it is not an array", format_type_be(origArrayType)))); - } - ReleaseSysCache(type_tuple_array); - - return elementType; -} - -/* - * transformArraySubscripts() - * Transform array subscripting. This is used for both - * array fetch and array assignment. - * - * In an array fetch, we are given a source array value and we produce an - * expression that represents the result of extracting a single array element - * or an array slice. - * - * In an array assignment, we are given a destination array value plus a - * source value that is to be assigned to a single element or a slice of - * that array. We produce an expression that represents the new array value - * with the source data inserted into the right part of the array. - * - * For both cases, if the source array is of a domain-over-array type, - * the result is of the base array type or its element type; essentially, - * we must fold a domain to its base type before applying subscripting. - * - * pstate Parse state - * arrayBase Already-transformed expression for the array as a whole - * arrayType OID of array's datatype (should match type of arrayBase, - * or be the base type of arrayBase's domain type) - * elementType OID of array's element type (fetch with transformArrayType, - * or pass InvalidOid to do it here) - * arrayTypMod typmod for the array (which is also typmod for the elements) - * indirection Untransformed list of subscripts (must not be NIL) - * assignFrom NULL for array fetch, else transformed expression for source. - */ -ArrayRef* transformArraySubscripts(ParseState* pstate, Node* arrayBase, Oid arrayType, Oid elementType, - int32 arrayTypMod, List* indirection, Node* assignFrom) -{ - bool isSlice = false; - List* upperIndexpr = NIL; - List* lowerIndexpr = NIL; - ListCell* idx = NULL; - ArrayRef* aref = NULL; - bool isIndexByVarchar = false; - - /* - * Caller may or may not have bothered to determine elementType. Note - * that if the caller did do so, arrayType/arrayTypMod must be as modified - * by transformArrayType, ie, smash domain to base type. - */ - if (!OidIsValid(elementType)) { - elementType = transformArrayType(&arrayType, &arrayTypMod); - } - /* - * A list containing only single subscripts refers to a single array - * element. If any of the items are double subscripts (lower:upper), then - * the subscript expression means an array slice operation. In this case, - * we supply a default lower bound of 1 for any items that contain only a - * single subscript. We have to prescan the indirection list to see if - * there are any double subscripts. - */ - foreach (idx, indirection) { - A_Indices* ai = (A_Indices*)lfirst(idx); - - if (ai->lidx != NULL) { - isSlice = true; - break; - } - } - - /* - * Transform the subscript expressions. - */ - foreach (idx, indirection) { - A_Indices* ai = (A_Indices*)lfirst(idx); - Node* subexpr = NULL; - - AssertEreport(IsA(ai, A_Indices), MOD_OPT, ""); - if (isSlice) { - if (ai->lidx) { - subexpr = transformExpr(pstate, ai->lidx); - /* If it's not int4 already, try to coerce */ - subexpr = coerce_to_target_type( - pstate, subexpr, exprType(subexpr), INT4OID, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); - if (subexpr == NULL) { - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("array subscript must have type integer"), - parser_errposition(pstate, exprLocation(ai->lidx)))); - } - } else { - /* Make a constant 1 */ - subexpr = (Node*)makeConst( - INT4OID, -1, InvalidOid, sizeof(int32), Int32GetDatum(1), false, true); /* pass by value */ - } - lowerIndexpr = lappend(lowerIndexpr, subexpr); - } - subexpr = transformExpr(pstate, ai->uidx); - if (get_typecategory(arrayType) == TYPCATEGORY_TABLEOF_VARCHAR) { - isIndexByVarchar = true; - } - if ((nodeTag(arrayBase) == T_Param && ((Param*)arrayBase)->tableOfIndexType == VARCHAROID) - || isIndexByVarchar) { - /* subcript type is varchar */ - subexpr = coerce_to_target_type(pstate, subexpr, exprType(subexpr), - ((Param*)arrayBase)->tableOfIndexType, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); - } else { - /* If it's not int4 already, try to coerce */ - subexpr = coerce_to_target_type( - pstate, subexpr, exprType(subexpr), INT4OID, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); - } - - if (subexpr == NULL) { - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("array subscript must have type integer"), - parser_errposition(pstate, exprLocation(ai->uidx)))); - } - upperIndexpr = lappend(upperIndexpr, subexpr); - } - - /* - * If doing an array store, coerce the source value to the right type. - * (This should agree with the coercion done by transformAssignedExpr.) - */ - if (assignFrom != NULL) { - Oid typesource = exprType(assignFrom); - Oid typeneeded = isSlice ? arrayType : elementType; - Node* newFrom = NULL; - - newFrom = coerce_to_target_type( - pstate, assignFrom, typesource, typeneeded, arrayTypMod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); - if (newFrom == NULL) { - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("array assignment requires type %s" - " but expression is of type %s", - format_type_be(typeneeded), - format_type_be(typesource)), - errhint("You will need to rewrite or cast the expression."), - parser_errposition(pstate, exprLocation(assignFrom)))); - } - assignFrom = newFrom; - } - - /* - * Ready to build the ArrayRef node. - */ - aref = makeNode(ArrayRef); - aref->refarraytype = arrayType; - aref->refelemtype = elementType; - aref->reftypmod = arrayTypMod; - /* refcollid will be set by parse_collate.c */ - aref->refupperindexpr = upperIndexpr; - aref->reflowerindexpr = lowerIndexpr; - aref->refexpr = (Expr*)arrayBase; - aref->refassgnexpr = (Expr*)assignFrom; - - return aref; -} - -/* - * make_const - * - * Convert a Value node (as returned by the grammar) to a Const node - * of the "natural" type for the constant. Note that this routine is - * only used when there is no explicit cast for the constant, so we - * have to guess what type is wanted. - * - * For string literals we produce a constant of type UNKNOWN ---- whose - * representation is the same as cstring, but it indicates to later type - * resolution that we're not sure yet what type it should be considered. - * Explicit "NULL" constants are also typed as UNKNOWN. - * - * For integers and floats we produce int4, int8, or numeric depending - * on the value of the number. XXX We should produce int2 as well, - * but additional cleanup is needed before we can do that; there are - * too many examples that fail if we try. - */ -Const* make_const(ParseState* pstate, Value* value, int location) -{ - Const* con = NULL; - Datum val; - int64 val64; - Oid typid; - int typelen; - bool typebyval = false; - ParseCallbackState pcbstate; - - switch (nodeTag(value)) { - case T_Integer: - val = Int32GetDatum(intVal(value)); - - typid = INT4OID; - typelen = sizeof(int32); - typebyval = true; - break; - - case T_Float: - /* could be an oversize integer as well as a float ... */ - if (scanint8(strVal(value), true, &val64)) { - /* - * It might actually fit in int32. Probably only INT_MIN can - * occur, but we'll code the test generally just to be sure. - */ - int32 val32 = (int32)val64; - - if (val64 == (int64)val32) { - val = Int32GetDatum(val32); - - typid = INT4OID; - typelen = sizeof(int32); - typebyval = true; - } else { - val = Int64GetDatum(val64); - - typid = INT8OID; - typelen = sizeof(int64); - typebyval = FLOAT8PASSBYVAL; /* int8 and float8 alike */ - } - } else { - /* arrange to report location if numeric_in() fails */ - setup_parser_errposition_callback(&pcbstate, pstate, location); - val = DirectFunctionCall3( - numeric_in, CStringGetDatum(strVal(value)), ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1)); - cancel_parser_errposition_callback(&pcbstate); - - typid = NUMERICOID; - typelen = -1; /* variable len */ - typebyval = false; - } - break; - - case T_String: - - /* - * We assume here that UNKNOWN's internal representation is the - * same as CSTRING - */ - val = CStringGetDatum(strVal(value)); - - typid = UNKNOWNOID; /* will be coerced later */ - typelen = -2; /* cstring-style varwidth type */ - typebyval = false; - break; - - case T_BitString: - /* arrange to report location if bit_in() fails */ - setup_parser_errposition_callback(&pcbstate, pstate, location); - val = DirectFunctionCall3( - bit_in, CStringGetDatum(strVal(value)), ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1)); - cancel_parser_errposition_callback(&pcbstate); - typid = BITOID; - typelen = -1; - typebyval = false; - break; - - case T_Null: - /* return a null const */ - con = makeConst(UNKNOWNOID, -1, InvalidOid, -2, (Datum)0, true, false); - con->location = location; - return con; - - default: - ereport(ERROR, - (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("unrecognized node type: %d", (int)nodeTag(value)))); - return NULL; /* keep compiler quiet */ - } - - con = makeConst(typid, - -1, /* typmod -1 is OK for all cases */ - InvalidOid, /* all cases are uncollatable types */ - typelen, - val, - false, - typebyval); - con->location = location; - - return con; -} -- 2.34.1 From 0b0f1f86ba3ed9d6e7aa4e01036b85108d6e9edb Mon Sep 17 00:00:00 2001 From: qbkrr <1195300755@qq.com> Date: Sun, 30 Oct 2022 16:16:49 +0800 Subject: [PATCH 2/2] ADD file via upload --- parse_node.cpp | 551 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 551 insertions(+) create mode 100644 parse_node.cpp diff --git a/parse_node.cpp b/parse_node.cpp new file mode 100644 index 000000000..bc0ee9b9c --- /dev/null +++ b/parse_node.cpp @@ -0,0 +1,551 @@ +/* ------------------------------------------------------------------------- + * + * parse_node.cpp + * various routines that make nodes for querytrees + * + * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * Portions Copyright (c) 2021, openGauss Contributors + * + * + * IDENTIFICATION + * src/common/backend/parser/parse_node.cpp + * + * ------------------------------------------------------------------------- + */ +#include "postgres.h" +#include "knl/knl_variable.h" + +#include "access/heapam.h" +#include "catalog/pg_type.h" +#include "mb/pg_wchar.h" +#include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" +#include "parser/parsetree.h" +#include "parser/parse_coerce.h" +#include "parser/parse_expr.h" +#include "parser/parse_relation.h" +#include "utils/builtins.h" +#include "utils/int8.h" +#include "utils/lsyscache.h" +#include "utils/syscache.h" +#include "utils/varbit.h" + +static void pcb_error_callback(void* arg); + +/* + * make_parsestate + * Allocate and initialize a new ParseState. + * + * Caller should eventually release the ParseState via free_parsestate(). + */ +ParseState* make_parsestate(ParseState* parentParseState)//分配并初始化一个新的ParseState。 +{ + ParseState* pstate = NULL;//数据传入目前状态 初始化一个新状态 + + pstate = (ParseState*)palloc0(sizeof(ParseState));//设置状态的参数值 + + pstate->parentParseState = parentParseState; + + pstate->isAliasReplace = true; + + /* Fill in fields that don't start at null/false/zero */ + pstate->p_next_resno = 1; + pstate->p_star_start = NIL; + pstate->p_star_end = NIL; + pstate->p_star_only = NIL; + pstate->p_resolve_unknowns = true; + pstate->ignoreplus = false; + pstate->p_plusjoin_rte_info = NULL; + pstate->p_rawdefaultlist = NIL; + + if (parentParseState != NULL) { + pstate->p_sourcetext = parentParseState->p_sourcetext;////从父节点复制钩子 + /* all hooks are copied from parent */ + pstate->p_pre_columnref_hook = parentParseState->p_pre_columnref_hook; + pstate->p_post_columnref_hook = parentParseState->p_post_columnref_hook; + pstate->p_paramref_hook = parentParseState->p_paramref_hook; + pstate->p_coerce_param_hook = parentParseState->p_coerce_param_hook; + pstate->p_ref_hook_state = parentParseState->p_ref_hook_state; + pstate->p_create_proc_operator_hook = parentParseState->p_create_proc_operator_hook; + pstate->p_create_proc_insert_hook = parentParseState->p_create_proc_insert_hook; + pstate->p_cl_hook_state = parentParseState->p_cl_hook_state; + pstate->p_bind_variable_columnref_hook = parentParseState->p_bind_variable_columnref_hook; + pstate->p_bind_hook_state = parentParseState->p_bind_hook_state; + pstate->p_bind_describe_hook = parentParseState->p_bind_describe_hook; + pstate->p_describeco_hook_state = parentParseState->p_describeco_hook_state; + } + + return pstate;//数据返回新状态 +} + +/* + * free_parsestate + * Release a ParseState and any subsidiary resources. + */ +void free_parsestate(ParseState* pstate)//释放一个ParseState和任何附属资源。 +{ + Assert(pstate != NULL);//数据传入目前状态->检测状态是否为空 + /* + * Check that we did not produce too many resnos; at the very least we + * cannot allow more than 2^16, since that would exceed the range of a + * AttrNumber. It seems safest to use MaxTupleAttributeNumber. + */ + if (pstate->p_next_resno - 1 > MaxTupleAttributeNumber) {//判断resno的个数是否超出限制,超出则抛出错误 + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("target lists can have at most %d entries", MaxTupleAttributeNumber))); + } + if (pstate->p_target_relation != NULL) {//判断目标关系是否为空,空则关闭堆 + heap_close(pstate->p_target_relation, NoLock); + } + pfree_ext(pstate);//释放资源 +} + +/* + * parser_errposition + * Report a parse-analysis-time cursor position, if possible. + * + * This is expected to be used within an ereport() call. The return value + * is a dummy (always 0, in fact). + * + * The locations stored in raw parsetrees are byte offsets into the source + * string. We have to convert them to 1-based character indexes for reporting + * to clients. (We do things this way to avoid unnecessary overhead in the + * normal non-error case: computing character indexes would be much more + * expensive than storing token offsets.) + */ +int parser_errposition(ParseState* pstate, int location) +{ + int pos; + + /* No-op if location was not provided */ + if (location < 0) { + return 0; + } + /* Can't do anything if source text is not available */ + if (pstate == NULL || pstate->p_sourcetext == NULL) { + return 0; + } + /* Convert offset to character number */ + pos = pg_mbstrlen_with_len(pstate->p_sourcetext, location) + 1; + /* And pass it to the ereport mechanism */ + return errposition(pos); +} + +/* + * setup_parser_errposition_callback + * Arrange for non-parser errors to report an error position + * + * Sometimes the parser calls functions that aren't part of the parser + * subsystem and can't reasonably be passed a ParseState; yet we would + * like any errors thrown in those functions to be tagged with a parse + * error location. Use this function to set up an error context stack + * entry that will accomplish that. Usage pattern: + * + * declare a local variable "ParseCallbackState pcbstate" + * ... + * setup_parser_errposition_callback(&pcbstate, pstate, location); + * call function that might throw error; + * cancel_parser_errposition_callback(&pcbstate); + */ +void setup_parser_errposition_callback(ParseCallbackState* pcbstate, ParseState* pstate, int location) +{ + /* Setup error traceback support for ereport() */ + pcbstate->pstate = pstate; + pcbstate->location = location; + pcbstate->errcontext.callback = pcb_error_callback; + pcbstate->errcontext.arg = (void*)pcbstate; + pcbstate->errcontext.previous = t_thrd.log_cxt.error_context_stack; + t_thrd.log_cxt.error_context_stack = &pcbstate->errcontext; +} + +/* + * Cancel a previously-set-up errposition callback. + */ +void cancel_parser_errposition_callback(ParseCallbackState* pcbstate) +{ + /* Pop the error context stack */ + t_thrd.log_cxt.error_context_stack = pcbstate->errcontext.previous; +} + +/* + * Error context callback for inserting parser error location. + * + * Note that this will be called for *any* error occurring while the + * callback is installed. We avoid inserting an irrelevant error location + * if the error is a query cancel --- are there any other important cases? + */ +static void pcb_error_callback(void* arg) +{ + ParseCallbackState* pcbstate = (ParseCallbackState*)arg; + + if (geterrcode() != ERRCODE_QUERY_CANCELED) { + (void)parser_errposition(pcbstate->pstate, pcbstate->location); + } +} + +/* + * For timeseries table to identify hidden column type and return NULL or + * build a Var node for an attribute identified by RTE and attrno for others. + */ +Var* ts_make_var(ParseState* pstate, RangeTblEntry* rte, int attrno, int location)//对时间序列表识别隐藏的列类型,并返回NULL,或者为一个由RTE识别的属性建立一个Var节点,为其他属性建立attrno节点 +{ + Oid var_type_id; + int32 type_mod; + Oid var_collid; + int kv_type = ATT_KV_UNDEFINED; + get_rte_attribute_type(rte, attrno, &var_type_id, &type_mod, &var_collid, &kv_type);//获取运行时错误属性类型 + if (kv_type == ATT_KV_HIDE) { + return NULL; + } + + Var* result = NULL;//数据初始化 + int vnum, sublevels_up; + vnum = RTERangeTablePosn(pstate, rte, &sublevels_up); + result = makeVar(vnum, attrno, var_type_id, type_mod, var_collid, sublevels_up);//为由运行环境和attrno标识的属性构建一个Var节点 + result->location = location; + return result; +} + +/* + * make_var + * Build a Var node for an attribute identified by RTE and attrno + */ +Var* make_var(ParseState* pstate, RangeTblEntry* rte, int attrno, int location) +{ + Var* result = NULL; + int vnum, sublevels_up; + Oid vartypeid; + int32 type_mod; + Oid varcollid; + + vnum = RTERangeTablePosn(pstate, rte, &sublevels_up); + get_rte_attribute_type(rte, attrno, &vartypeid, &type_mod, &varcollid); + result = makeVar(vnum, attrno, vartypeid, type_mod, varcollid, sublevels_up); + result->location = location; + return result; +} + +/* + * transformArrayType() + * Identify the types involved in a subscripting operation + * + * On entry, arrayType/arrayTypmod identify the type of the input value + * to be subscripted (which could be a domain type). These are modified + * if necessary to identify the actual array type and typmod, and the + * array's element type is returned. An error is thrown if the input isn't + * an array type. + */ + //tips:在输入时,arrayType/arrayTypmod识别要下标的输入值的类型,如果有必要,这些会被修改,以确定实际的数组类型和typmod,并且返回数组的元素类型。 如果输入值不是一个数组类型,就会产生一个错误 +Oid transformArrayType(Oid* arrayType, int32* arrayTypmod)//识别下标操作中涉及的类型。 +{ + Oid origArrayType = *arrayType;//数据传入->数据初始化 + Oid elementType; + HeapTuple type_tuple_array; + Form_pg_type type_struct_array; + + /* + * If the input is a domain, smash to base type, and extract the actual + * typmod to be applied to the base type. Subscripting a domain is an + * operation that necessarily works on the base array type, not the domain + * itself. (Note that we provide no method whereby the creator of a + * domain over an array type could hide its ability to be subscripted.) + */ + *arrayType = getBaseTypeAndTypmod(*arrayType, arrayTypmod);//提取实际模组类型 + + /* Get the type tuple for the array */ + type_tuple_array = SearchSysCache1(TYPEOID, ObjectIdGetDatum(*arrayType));//获取数组的类型元组 + if (!HeapTupleIsValid(type_tuple_array)) { + ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for type %u", *arrayType)));//判断堆积元组是否有效 + } + type_struct_array = (Form_pg_type)GETSTRUCT(type_tuple_array);//获取数组结构 + + /* needn't check typisdefined since this will fail anyway */ + + elementType = type_struct_array->typelem;//获取数组元素结构 + if (elementType == InvalidOid) {//判断是否为数组类型,不是则抛出错误 + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("cannot subscript type %s because it is not an array", format_type_be(origArrayType)))); + } + ReleaseSysCache(type_tuple_array);//释放系统内存 + + return elementType;//返回数组元素类型 +} + +/* + * transformArraySubscripts() + * Transform array subscripting. This is used for both + * array fetch and array assignment. + * + * In an array fetch, we are given a source array value and we produce an + * expression that represents the result of extracting a single array element + * or an array slice. + * + * In an array assignment, we are given a destination array value plus a + * source value that is to be assigned to a single element or a slice of + * that array. We produce an expression that represents the new array value + * with the source data inserted into the right part of the array. + * + * For both cases, if the source array is of a domain-over-array type, + * the result is of the base array type or its element type; essentially, + * we must fold a domain to its base type before applying subscripting. + * + * pstate Parse state + * arrayBase Already-transformed expression for the array as a whole + * arrayType OID of array's datatype (should match type of arrayBase, + * or be the base type of arrayBase's domain type) + * elementType OID of array's element type (fetch with transformArrayType, + * or pass InvalidOid to do it here) + * arrayTypMod typmod for the array (which is also typmod for the elements) + * indirection Untransformed list of subscripts (must not be NIL) + * assignFrom NULL for array fetch, else transformed expression for source. + */ +ArrayRef* transformArraySubscripts(ParseState* pstate, Node* arrayBase, Oid arrayType, Oid elementType,//转换数组的下标,用于数组获取和数组赋值。 + int32 arrayTypMod, List* indirection, Node* assignFrom) +{ + bool isSlice = false; + List* upperIndexpr = NIL; + List* lowerIndexpr = NIL; + ListCell* idx = NULL; + ArrayRef* aref = NULL; + bool isIndexByVarchar = false; + + /* + * Caller may or may not have bothered to determine elementType. Note + * that if the caller did do so, arrayType/arrayTypMod must be as modified + * by transformArrayType, ie, smash domain to base type. + */ + if (!OidIsValid(elementType)) { + elementType = transformArrayType(&arrayType, &arrayTypMod);//数据传入->数据初始化->如果调用者不确定元素类型,即元素类型为无效OID,则转换arrayType/arrayTypMod类型 + } + /* + * A list containing only single subscripts refers to a single array + * element. If any of the items are double subscripts (lower:upper), then + * the subscript expression means an array slice operation. In this case, + * we supply a default lower bound of 1 for any items that contain only a + * single subscript. We have to prescan the indirection list to see if + * there are any double subscripts. + */ + foreach (idx, indirection) { + A_Indices* ai = (A_Indices*)lfirst(idx);//如果索引文件不为空,则标记为已切片 + + if (ai->lidx != NULL) { + isSlice = true; + break; + } + } + + /* + * Transform the subscript expressions. + */ + //tips:在数组获取中,会得到一个源数组值,于是产生一个表达式,代表提取单个数组元素或数组切片的结果。对于这两种情况,如果源数组是域上的数组类型,则结果是基数组类型或其元素类型。 + foreach (idx, indirection) { + A_Indices* ai = (A_Indices*)lfirst(idx); + Node* subexpr = NULL; + + AssertEreport(IsA(ai, A_Indices), MOD_OPT, "");//如果已经切片且索引文件不为空,转换表达式的值 + if (isSlice) { + if (ai->lidx) { + subexpr = transformExpr(pstate, ai->lidx); + /* If it's not int4 already, try to coerce */ + subexpr = coerce_to_target_type( + pstate, subexpr, exprType(subexpr), INT4OID, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); + if (subexpr == NULL) { + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("array subscript must have type integer"), + parser_errposition(pstate, exprLocation(ai->lidx))));//如果执行数组存储,则强制源值为正确的类型 + } + } else { + /* Make a constant 1 */ + subexpr = (Node*)makeConst( + INT4OID, -1, InvalidOid, sizeof(int32), Int32GetDatum(1), false, true); /* pass by value */ + } + lowerIndexpr = lappend(lowerIndexpr, subexpr); + } + subexpr = transformExpr(pstate, ai->uidx); + if (get_typecategory(arrayType) == TYPCATEGORY_TABLEOF_VARCHAR) { + isIndexByVarchar = true; + } + if ((nodeTag(arrayBase) == T_Param && ((Param*)arrayBase)->tableOfIndexType == VARCHAROID) + || isIndexByVarchar) { + /* subcript type is varchar */ + subexpr = coerce_to_target_type(pstate, subexpr, exprType(subexpr), + ((Param*)arrayBase)->tableOfIndexType, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); + } else { + /* If it's not int4 already, try to coerce */ + subexpr = coerce_to_target_type( + pstate, subexpr, exprType(subexpr), INT4OID, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); + } + + if (subexpr == NULL) { + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("array subscript must have type integer"), + parser_errposition(pstate, exprLocation(ai->uidx)))); + } + upperIndexpr = lappend(upperIndexpr, subexpr); + } + + /* + * If doing an array store, coerce the source value to the right type. + * (This should agree with the coercion done by transformAssignedExpr.) + */ + if (assignFrom != NULL) { + Oid typesource = exprType(assignFrom); + Oid typeneeded = isSlice ? arrayType : elementType; + Node* newFrom = NULL; + + newFrom = coerce_to_target_type( + pstate, assignFrom, typesource, typeneeded, arrayTypMod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); + if (newFrom == NULL) { + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("array assignment requires type %s" + " but expression is of type %s", + format_type_be(typeneeded), + format_type_be(typesource)), + errhint("You will need to rewrite or cast the expression."), + parser_errposition(pstate, exprLocation(assignFrom)))); + } + assignFrom = newFrom; + } + + /* + * Ready to build the ArrayRef node. + */ + aref = makeNode(ArrayRef); + aref->refarraytype = arrayType; + aref->refelemtype = elementType; + aref->reftypmod = arrayTypMod; + /* refcollid will be set by parse_collate.c */ + aref->refupperindexpr = upperIndexpr; + aref->reflowerindexpr = lowerIndexpr; + aref->refexpr = (Expr*)arrayBase; + aref->refassgnexpr = (Expr*)assignFrom; + + return aref; +} + +/* + * make_const + * + * Convert a Value node (as returned by the grammar) to a Const node + * of the "natural" type for the constant. Note that this routine is + * only used when there is no explicit cast for the constant, so we + * have to guess what type is wanted. + * + * For string literals we produce a constant of type UNKNOWN ---- whose + * representation is the same as cstring, but it indicates to later type + * resolution that we're not sure yet what type it should be considered. + * Explicit "NULL" constants are also typed as UNKNOWN. + * + * For integers and floats we produce int4, int8, or numeric depending + * on the value of the number. XXX We should produce int2 as well, + * but additional cleanup is needed before we can do that; there are + * too many examples that fail if we try. + */ + // tips:对于整数和浮点数,我们根据数字的值转换为int4、int8或numeric类型。也会转换成int2,但在需要进行额外的处理。 +Const* make_const(ParseState* pstate, Value* value, int location)//当没有明确的常量类型时,使用此函数将一个 Value 节点转换为常量的 “自然 “类型的 Const 节点。 +{ + Const* con = NULL; + Datum val; + int64 val64; + Oid typid; + int typelen; + bool typebyval = false; + ParseCallbackState pcbstate; + + switch (nodeTag(value)) {//数据传入->数据初始化->根据节点类型进行转化 + case T_Integer: + val = Int32GetDatum(intVal(value)); + + typid = INT4OID; + typelen = sizeof(int32); + typebyval = true; + break; + + case T_Float: + /* could be an oversize integer as well as a float ... */ + if (scanint8(strVal(value), true, &val64)) { + /* + * It might actually fit in int32. Probably only INT_MIN can + * occur, but we'll code the test generally just to be sure. + */ + int32 val32 = (int32)val64; + + if (val64 == (int64)val32) { + val = Int32GetDatum(val32); + + typid = INT4OID; + typelen = sizeof(int32); + typebyval = true; + } else { + val = Int64GetDatum(val64); + + typid = INT8OID; + typelen = sizeof(int64); + typebyval = FLOAT8PASSBYVAL; /* int8 and float8 alike */ + } + } else { + /* arrange to report location if numeric_in() fails */ + setup_parser_errposition_callback(&pcbstate, pstate, location); + val = DirectFunctionCall3( + numeric_in, CStringGetDatum(strVal(value)), ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1)); + cancel_parser_errposition_callback(&pcbstate); + + typid = NUMERICOID; + typelen = -1; /* variable len */ + typebyval = false; + } + break; + + case T_String: + + /* + * We assume here that UNKNOWN's internal representation is the + * same as CSTRING + */ + val = CStringGetDatum(strVal(value)); + + typid = UNKNOWNOID; /* will be coerced later */ + typelen = -2; /* cstring-style varwidth type */ + typebyval = false; + break; + + case T_BitString: + /* arrange to report location if bit_in() fails */ + setup_parser_errposition_callback(&pcbstate, pstate, location); + val = DirectFunctionCall3( + bit_in, CStringGetDatum(strVal(value)), ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1)); + cancel_parser_errposition_callback(&pcbstate); + typid = BITOID; + typelen = -1; + typebyval = false; + break; + + case T_Null: + /* return a null const */ + con = makeConst(UNKNOWNOID, -1, InvalidOid, -2, (Datum)0, true, false);//转换为常量的“natural”类型的Const节点 + con->location = location; + return con; + + default: + ereport(ERROR, + (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("unrecognized node type: %d", (int)nodeTag(value)))); + return NULL; /* keep compiler quiet */ + } + + con = makeConst(typid, + -1, /* typmod -1 is OK for all cases */ + InvalidOid, /* all cases are uncollatable types */ + typelen, + val, + false, + typebyval); + con->location = location; + + return con; +} -- 2.34.1