#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.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"
Go to the source code of this file.
Functions | |
static void | pcb_error_callback (void *arg) |
ParseState * | make_parsestate (ParseState *parentParseState) |
void | free_parsestate (ParseState *pstate) |
int | parser_errposition (ParseState *pstate, int location) |
void | setup_parser_errposition_callback (ParseCallbackState *pcbstate, ParseState *pstate, int location) |
void | cancel_parser_errposition_callback (ParseCallbackState *pcbstate) |
Var * | make_var (ParseState *pstate, RangeTblEntry *rte, int attrno, int location) |
Oid | transformArrayType (Oid *arrayType, int32 *arrayTypmod) |
ArrayRef * | transformArraySubscripts (ParseState *pstate, Node *arrayBase, Oid arrayType, Oid elementType, int32 arrayTypMod, List *indirection, Node *assignFrom) |
Const * | make_const (ParseState *pstate, Value *value, int location) |
void cancel_parser_errposition_callback | ( | ParseCallbackState * | pcbstate | ) |
Definition at line 158 of file parse_node.c.
References ParseCallbackState::errcallback, error_context_stack, and ErrorContextCallback::previous.
Referenced by addTargetToGroupList(), addTargetToSortList(), coerce_type(), LookupCollation(), make_const(), parserOpenTable(), transformSetOperationTree(), transformTableLikeClause(), and typenameTypeMod().
{ /* Pop the error context stack */ error_context_stack = pcbstate->errcallback.previous; }
void free_parsestate | ( | ParseState * | pstate | ) |
Definition at line 74 of file parse_node.c.
References ereport, errcode(), errmsg(), ERROR, heap_close, MaxTupleAttributeNumber, NoLock, NULL, ParseState::p_next_resno, ParseState::p_target_relation, and pfree().
Referenced by CreateTrigger(), examine_parameter_list(), inline_function(), parse_analyze(), parse_analyze_varparams(), parse_sub_analyze(), pg_analyze_and_rewrite_params(), transformIndexStmt(), transformInsertStmt(), and transformRuleStmt().
{ /* * 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(pstate); }
Const* make_const | ( | ParseState * | pstate, | |
Value * | value, | |||
int | location | |||
) |
Definition at line 438 of file parse_node.c.
References bit_in(), cancel_parser_errposition_callback(), CStringGetDatum, DirectFunctionCall3, elog, ERROR, Int32GetDatum, Int64GetDatum(), intVal, InvalidOid, Const::location, makeConst(), nodeTag, numeric_in(), ObjectIdGetDatum, scanint8(), setup_parser_errposition_callback(), strVal, T_BitString, T_Float, T_Integer, T_Null, T_String, UNKNOWNOID, and val.
Referenced by transformExprRecurse().
{ Const *con; Datum val; int64 val64; Oid typeid; int typelen; bool typebyval; ParseCallbackState pcbstate; switch (nodeTag(value)) { case T_Integer: val = Int32GetDatum(intVal(value)); typeid = 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); typeid = INT4OID; typelen = sizeof(int32); typebyval = true; } else { val = Int64GetDatum(val64); typeid = 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); typeid = 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)); typeid = 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); typeid = 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: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(value)); return NULL; /* keep compiler quiet */ } con = makeConst(typeid, -1, /* typmod -1 is OK for all cases */ InvalidOid, /* all cases are uncollatable types */ typelen, val, false, typebyval); con->location = location; return con; }
ParseState* make_parsestate | ( | ParseState * | parentParseState | ) |
Definition at line 44 of file parse_node.c.
References ParseState::p_coerce_param_hook, ParseState::p_next_resno, ParseState::p_paramref_hook, ParseState::p_post_columnref_hook, ParseState::p_pre_columnref_hook, ParseState::p_ref_hook_state, ParseState::p_sourcetext, palloc0(), and ParseState::parentParseState.
Referenced by AddRelationNewConstraints(), AlterDomainDefault(), ATPrepAlterColumnType(), CreateTrigger(), DefineDomain(), domainAddConstraint(), EvaluateParams(), examine_parameter_list(), inline_function(), parse_analyze(), parse_analyze_varparams(), parse_sub_analyze(), pg_analyze_and_rewrite_params(), PrepareQuery(), transformAlterTableStmt(), transformCreateStmt(), transformIndexStmt(), transformInsertStmt(), and transformRuleStmt().
{ ParseState *pstate; pstate = palloc0(sizeof(ParseState)); pstate->parentParseState = parentParseState; /* Fill in fields that don't start at null/false/zero */ pstate->p_next_resno = 1; if (parentParseState) { 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; } return pstate; }
Var* make_var | ( | ParseState * | pstate, | |
RangeTblEntry * | rte, | |||
int | attrno, | |||
int | location | |||
) |
Definition at line 186 of file parse_node.c.
References get_rte_attribute_type(), Var::location, makeVar(), and RTERangeTablePosn().
Referenced by scanRTEForColumn(), and transformAssignedExpr().
{ Var *result; 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; }
int parser_errposition | ( | ParseState * | pstate, | |
int | location | |||
) |
Definition at line 108 of file parse_node.c.
References errposition(), NULL, ParseState::p_sourcetext, and pg_mbstrlen_with_len().
Referenced by addRangeTableEntryForCTE(), addRangeTableEntryForFunction(), analyzeCTE(), analyzeCTETargetList(), assign_collations_walker(), check_agg_arguments(), check_agg_arguments_walker(), check_parameter_resolution_walker(), check_ungrouped_columns_walker(), checkExprIsVarFree(), checkInsertTargets(), checkTargetlistEntrySQL92(), checkWellFormedRecursion(), checkWellFormedRecursionWalker(), coerce_to_boolean(), coerce_to_common_type(), coerce_to_specific_type(), colNameToVar(), compatible_oper(), CreateTrigger(), errorMissingColumn(), errorMissingRTE(), ExpandAllTables(), ExpandColumnRefStar(), findTargetlistEntrySQL92(), fixed_paramref_hook(), GetColumnDefCollation(), LookupOperName(), LookupTypeName(), make_distinct_op(), make_op(), make_row_comparison_op(), make_row_distinct_op(), make_scalar_array_op(), op_error(), parseCheckAggregates(), ParseFuncOrColumn(), parser_coercion_errposition(), pcb_error_callback(), plpgsql_post_column_ref(), resolve_column_ref(), scanNameSpaceForRefname(), scanNameSpaceForRelid(), scanRTEForColumn(), select_common_collation(), select_common_type(), TopologicalSort(), transformAExprIn(), transformAExprNullIf(), transformAggregateCall(), transformArrayExpr(), transformArraySubscripts(), transformAssignedExpr(), transformAssignmentIndirection(), transformAssignmentSubscripts(), transformCollateClause(), transformColumnDefinition(), transformColumnRef(), transformColumnType(), transformConstraintAttrs(), transformDistinctClause(), transformDistinctOnClause(), transformIndexConstraint(), transformIndirection(), transformInsertRow(), transformLockingClause(), transformParamRef(), transformSelectStmt(), transformSetOperationStmt(), transformSetOperationTree(), transformSubLink(), transformTableConstraint(), transformUpdateStmt(), transformValuesClause(), transformWindowDefinitions(), transformWindowFuncCall(), transformWithClause(), transformXmlExpr(), transformXmlSerialize(), typenameType(), typenameTypeMod(), unknown_attribute(), variable_coerce_param_hook(), and variable_paramref_hook().
{ 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); }
static void pcb_error_callback | ( | void * | arg | ) | [static] |
Definition at line 172 of file parse_node.c.
References geterrcode(), ParseCallbackState::location, parser_errposition(), and ParseCallbackState::pstate.
{ ParseCallbackState *pcbstate = (ParseCallbackState *) arg; if (geterrcode() != ERRCODE_QUERY_CANCELED) (void) parser_errposition(pcbstate->pstate, pcbstate->location); }
void setup_parser_errposition_callback | ( | ParseCallbackState * | pcbstate, | |
ParseState * | pstate, | |||
int | location | |||
) |
Definition at line 142 of file parse_node.c.
References ErrorContextCallback::arg, ErrorContextCallback::callback, ParseCallbackState::errcallback, error_context_stack, ParseCallbackState::location, ErrorContextCallback::previous, and ParseCallbackState::pstate.
Referenced by addTargetToGroupList(), addTargetToSortList(), coerce_type(), LookupCollation(), make_const(), parserOpenTable(), transformSetOperationTree(), transformTableLikeClause(), and typenameTypeMod().
{ /* Setup error traceback support for ereport() */ pcbstate->pstate = pstate; pcbstate->location = location; pcbstate->errcallback.callback = pcb_error_callback; pcbstate->errcallback.arg = (void *) pcbstate; pcbstate->errcallback.previous = error_context_stack; error_context_stack = &pcbstate->errcallback; }
ArrayRef* transformArraySubscripts | ( | ParseState * | pstate, | |
Node * | arrayBase, | |||
Oid | arrayType, | |||
Oid | elementType, | |||
int32 | arrayTypMod, | |||
List * | indirection, | |||
Node * | assignFrom | |||
) |
Definition at line 278 of file parse_node.c.
References Assert, COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, ereport, errcode(), errhint(), errmsg(), ERROR, exprLocation(), exprType(), format_type_be(), Int32GetDatum, INT4OID, InvalidOid, IsA, lappend(), lfirst, A_Indices::lidx, makeConst(), makeNode, NULL, OidIsValid, ParseState::p_expr_kind, parser_errposition(), ArrayRef::refarraytype, ArrayRef::refassgnexpr, ArrayRef::refelemtype, ArrayRef::refexpr, ArrayRef::reflowerindexpr, ArrayRef::reftypmod, ArrayRef::refupperindexpr, transformArrayType(), transformExpr(), and A_Indices::uidx.
Referenced by transformAssignmentSubscripts(), and transformIndirection().
{ bool isSlice = false; List *upperIndexpr = NIL; List *lowerIndexpr = NIL; ListCell *idx; ArrayRef *aref; /* * 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; Assert(IsA(ai, A_Indices)); if (isSlice) { if (ai->lidx) { subexpr = transformExpr(pstate, ai->lidx, pstate->p_expr_kind); /* 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, pstate->p_expr_kind); /* 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; 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; }
Definition at line 213 of file parse_node.c.
References elog, ereport, errcode(), errmsg(), ERROR, format_type_be(), getBaseTypeAndTypmod(), GETSTRUCT, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum, ReleaseSysCache(), SearchSysCache1, and TYPEOID.
Referenced by transformArraySubscripts(), and transformAssignmentSubscripts().
{ 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)) elog(ERROR, "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; }