/* * op_error - utility routine to complain about an unresolvable operator */ static void op_error(ParseState *pstate, List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult, int location) { if (fdresult == FUNCDETAIL_MULTIPLE) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("operator is not unique: %s", op_signature_string(op, oprkind, arg1, arg2)), errhint("Could not choose a best candidate operator. " "You might need to add explicit type casts."), parser_errposition(pstate, location))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator does not exist: %s", op_signature_string(op, oprkind, arg1, arg2)), (!arg1 || !arg2) ? errhint("No operator matches the given name and argument type. " "You might need to add an explicit type cast.") : errhint("No operator matches the given name and argument types. " "You might need to add explicit type casts."), parser_errposition(pstate, location))); }
/* * 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); /* 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 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); }
/* * LookupOperName * Given a possibly-qualified operator name and exact input datatypes, * look up the operator. * * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for * a postfix op. * * If the operator name is not schema-qualified, it is sought in the current * namespace search path. * * If the operator is not found, we return InvalidOid if noError is true, * else raise an error. pstate and location are used only to report the * error position; pass NULL/-1 if not available. */ Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location) { Oid result; result = OpernameGetOprid(opername, oprleft, oprright); if (OidIsValid(result)) return result; /* we don't use op_error here because only an exact match is wanted */ if (!noError) { char oprkind; if (!OidIsValid(oprleft)) oprkind = 'l'; else if (!OidIsValid(oprright)) oprkind = 'r'; else oprkind = 'b'; ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator does not exist: %s", op_signature_string(opername, oprkind, oprleft, oprright)), parser_errposition(pstate, location))); } return InvalidOid; }
/* * Transform a ParamRef using fixed parameter types. */ static Node * fixed_paramref_hook(ParseState *pstate, ParamRef *pref) { FixedParamState *parstate = (FixedParamState *) pstate->p_ref_hook_state; int paramno = pref->number; Param *param; /* Check parameter number is valid */ if (paramno <= 0 || paramno > parstate->numParams || !OidIsValid(parstate->paramTypes[paramno - 1])) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("there is no parameter $%d", paramno), parser_errposition(pstate, pref->location))); param = makeNode(Param); param->paramkind = PARAM_EXTERN; param->paramid = paramno; param->paramtype = parstate->paramTypes[paramno - 1]; param->paramtypmod = -1; param->paramcollid = get_typcollation(param->paramtype); param->location = pref->location; return (Node *) param; }
/* compatible_oper() * given an opname and input datatypes, find a compatible binary operator * * This is tighter than oper() because it will not return an operator that * requires coercion of the input datatypes (but binary-compatible operators * are accepted). Otherwise, the semantics are the same. */ Operator compatible_oper(ParseState *pstate, List *op, Oid arg1, Oid arg2, bool noError, int location) { Operator optup; Form_pg_operator opform; /* oper() will find the best available match */ optup = oper(pstate, op, arg1, arg2, noError, location); if (optup == (Operator) NULL) return (Operator) NULL; /* must be noError case */ /* but is it good enough? */ opform = (Form_pg_operator) GETSTRUCT(optup); if (IsBinaryCoercible(arg1, opform->oprleft) && IsBinaryCoercible(arg2, opform->oprright)) return optup; /* nope... */ ReleaseSysCache(optup); if (!noError) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator requires run-time type coercion: %s", op_signature_string(op, 'b', arg1, arg2)), parser_errposition(pstate, location))); return (Operator) NULL; }
/* * 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); }
/* * CREATE COLLATION */ ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists) { char *collName; Oid collNamespace; AclResult aclresult; ListCell *pl; DefElem *fromEl = NULL; DefElem *localeEl = NULL; DefElem *lccollateEl = NULL; DefElem *lcctypeEl = NULL; DefElem *providerEl = NULL; DefElem *versionEl = NULL; char *collcollate = NULL; char *collctype = NULL; char *collproviderstr = NULL; int collencoding; char collprovider = 0; char *collversion = NULL; Oid newoid; ObjectAddress address; collNamespace = QualifiedNameGetCreationNamespace(names, &collName); aclresult = pg_namespace_aclcheck(collNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(collNamespace)); foreach(pl, parameters) { DefElem *defel = lfirst_node(DefElem, pl); DefElem **defelp; if (pg_strcasecmp(defel->defname, "from") == 0) defelp = &fromEl; else if (pg_strcasecmp(defel->defname, "locale") == 0) defelp = &localeEl; else if (pg_strcasecmp(defel->defname, "lc_collate") == 0) defelp = &lccollateEl; else if (pg_strcasecmp(defel->defname, "lc_ctype") == 0) defelp = &lcctypeEl; else if (pg_strcasecmp(defel->defname, "provider") == 0) defelp = &providerEl; else if (pg_strcasecmp(defel->defname, "version") == 0) defelp = &versionEl; else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("collation attribute \"%s\" not recognized", defel->defname), parser_errposition(pstate, defel->location))); break; } *defelp = defel; }
/* * Traverse a fully-analyzed tree to verify that parameter symbols * match their types. We need this because some Params might still * be UNKNOWN, if there wasn't anything to force their coercion, * and yet other instances seen later might have gotten coerced. */ static bool check_parameter_resolution_walker(Node *node, ParseState *pstate) { if (node == NULL) return false; if (IsA(node, Param)) { Param *param = (Param *) node; if (param->paramkind == PARAM_EXTERN) { VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state; int paramno = param->paramid; if (paramno <= 0 || /* shouldn't happen, but... */ paramno > *parstate->numParams) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("there is no parameter $%d", paramno), parser_errposition(pstate, param->location))); if (param->paramtype != (*parstate->paramTypes)[paramno - 1]) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_PARAMETER), errmsg("could not determine data type of parameter $%d", paramno), parser_errposition(pstate, param->location))); } return false; } if (IsA(node, Query)) { /* Recurse into RTE subquery or not-yet-planned sublink subquery */ return query_tree_walker((Query *) node, check_parameter_resolution_walker, (void *) pstate, 0); } return expression_tree_walker(node, check_parameter_resolution_walker, (void *) pstate); }
/* * Transform a ParamRef using variable parameter types. * * The only difference here is we must enlarge the parameter type array * as needed. */ static Node * variable_paramref_hook(ParseState *pstate, ParamRef *pref) { VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state; int paramno = pref->number; Oid *pptype; Param *param; /* Check parameter number is in range */ if (paramno <= 0 || paramno > INT_MAX / sizeof(Oid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("there is no parameter $%d", paramno), parser_errposition(pstate, pref->location))); if (paramno > *parstate->numParams) { /* Need to enlarge param array */ if (*parstate->paramTypes) *parstate->paramTypes = (Oid *) repalloc(*parstate->paramTypes, paramno * sizeof(Oid)); else *parstate->paramTypes = (Oid *) palloc(paramno * sizeof(Oid)); /* Zero out the previously-unreferenced slots */ MemSet(*parstate->paramTypes + *parstate->numParams, 0, (paramno - *parstate->numParams) * sizeof(Oid)); *parstate->numParams = paramno; } /* Locate param's slot in array */ pptype = &(*parstate->paramTypes)[paramno - 1]; /* If not seen before, initialize to UNKNOWN type */ if (*pptype == InvalidOid) *pptype = UNKNOWNOID; param = makeNode(Param); param->paramkind = PARAM_EXTERN; param->paramid = paramno; param->paramtype = *pptype; param->paramtypmod = -1; param->paramcollid = get_typcollation(param->paramtype); param->location = pref->location; return (Node *) param; }
/* * Parse a function call * * For historical reasons, Postgres tries to treat the notations tab.col * and col(tab) as equivalent: if a single-argument function call has an * argument of complex type and the (unqualified) function name matches * any attribute of the type, we take it as a column projection. Conversely * a function of a single complex-type argument can be written like a * column reference, allowing functions to act like computed columns. * * Hence, both cases come through here. The is_column parameter tells us * which syntactic construct is actually being dealt with, but this is * intended to be used only to deliver an appropriate error message, * not to affect the semantics. When is_column is true, we should have * a single argument (the putative table), unqualified function name * equal to the column name, and no aggregate decoration. * * The argument expressions (in fargs) must have been transformed already. */ Node * ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, List *agg_order, bool agg_star, bool agg_distinct, bool is_column, WindowSpec *over, int location, Node *agg_filter) { Oid rettype = InvalidOid; Oid funcid = InvalidOid; ListCell *l; ListCell *nextl; Node *first_arg = NULL; int nargs; Oid actual_arg_types[FUNC_MAX_ARGS]; Oid *declared_arg_types = NULL; Node *retval = NULL; bool retset = false; bool retstrict = false; bool retordered = false; FuncDetailCode fdresult; /* * Most of the rest of the parser just assumes that functions do not have * more than FUNC_MAX_ARGS parameters. We have to test here to protect * against array overruns, etc. Of course, this may not be a function, * but the test doesn't hurt. */ if (list_length(fargs) > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("cannot pass more than %d arguments to a function", FUNC_MAX_ARGS), parser_errposition(pstate, location))); /* * Perform the FILTER -> CASE transform. * FUNC(expr) FILTER (WHERE cond) => FUNC(CASE WHEN cond THEN expr END) * This must be done for every parameter of the function and special handling * is needed for FUNC(*). * * For this to be a valid transform we must assume that NULLs passed into * the function will not change the result. This assumption is not valid * for count(*), which is why we need special processing for this case. If * it is not a valid assumption for other cases we may need to rethink how * we implement FILTER. */ if (agg_filter) { List *newfargs = NULL; if (agg_star || !fargs) { /* * FUNC(*) => assume that datatype doesn't matter * By converting agg_star into a conditional constant boolean * expression we get the correct results for count(*) since it * will then supress the NULLs returned by the CASE statement. */ CaseExpr *c = makeNode(CaseExpr); CaseWhen *w = makeNode(CaseWhen); A_Const *a = makeNode(A_Const); a->val.type = T_Integer; a->val.val.ival = 1; /* Actual value shouldn't matter */ w->expr = (Expr *) agg_filter; w->result = (Expr *) a; c->casetype = InvalidOid; /* will analyze in a moment */ c->arg = (Expr *) NULL; c->defresult = (Expr *) NULL; c->args = list_make1(w); newfargs = list_make1(c); /* * Since we haven't checked the compatability of our function with * agg_star we can not clear the local bit yet, otherwise we would * loose track of the fact that this was an agg_star operation prior * to transformation. */ } else { Assert(fargs && list_length(fargs) > 0); foreach(l, fargs) { CaseExpr *c = makeNode(CaseExpr); CaseWhen *w = makeNode(CaseWhen); w->expr = (Expr *) agg_filter; w->result = (Expr *) lfirst(l); c->casetype = InvalidOid; /* will analyze in a moment */ c->arg = (Expr *) NULL; c->defresult = (Expr *) NULL; c->args = list_make1(w); if (newfargs) lappend(newfargs, c); else newfargs = list_make1(c); } } fargs = transformExpressionList(pstate, newfargs); }
/* * make_scalar_array_op() * Build expression tree for "scalar op ANY/ALL (array)" construct. */ Expr * make_scalar_array_op(ParseState *pstate, List *opname, bool useOr, Node *ltree, Node *rtree, int location) { Oid ltypeId, rtypeId, atypeId, res_atypeId; Operator tup; Form_pg_operator opform; Oid actual_arg_types[2]; Oid declared_arg_types[2]; List *args; Oid rettype; ScalarArrayOpExpr *result; ltypeId = exprType(ltree); atypeId = exprType(rtree); /* * The right-hand input of the operator will be the element type of the * array. However, if we currently have just an untyped literal on the * right, stay with that and hope we can resolve the operator. */ if (atypeId == UNKNOWNOID) rtypeId = UNKNOWNOID; else { rtypeId = get_base_element_type(atypeId); if (!OidIsValid(rtypeId)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires array on right side"), parser_errposition(pstate, location))); } /* Now resolve the operator */ tup = oper(pstate, opname, ltypeId, rtypeId, false, location); opform = (Form_pg_operator) GETSTRUCT(tup); /* Check it's not a shell */ if (!RegProcedureIsValid(opform->oprcode)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator is only a shell: %s", op_signature_string(opname, opform->oprkind, opform->oprleft, opform->oprright)), parser_errposition(pstate, location))); args = list_make2(ltree, rtree); actual_arg_types[0] = ltypeId; actual_arg_types[1] = rtypeId; declared_arg_types[0] = opform->oprleft; declared_arg_types[1] = opform->oprright; /* * enforce consistency with polymorphic argument and return types, * possibly adjusting return type or declared_arg_types (which will be * used as the cast destination by make_fn_arguments) */ rettype = enforce_generic_type_consistency(actual_arg_types, declared_arg_types, 2, opform->oprresult, false); /* * Check that operator result is boolean */ if (rettype != BOOLOID) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires operator to yield boolean"), parser_errposition(pstate, location))); if (get_func_retset(opform->oprcode)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires operator not to return a set"), parser_errposition(pstate, location))); /* * Now switch back to the array type on the right, arranging for any * needed cast to be applied. Beware of polymorphic operators here; * enforce_generic_type_consistency may or may not have replaced a * polymorphic type with a real one. */ if (IsPolymorphicType(declared_arg_types[1])) { /* assume the actual array type is OK */ res_atypeId = atypeId; } else { res_atypeId = get_array_type(declared_arg_types[1]); if (!OidIsValid(res_atypeId)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find array type for data type %s", format_type_be(declared_arg_types[1])), parser_errposition(pstate, location))); } actual_arg_types[1] = atypeId; declared_arg_types[1] = res_atypeId; /* perform the necessary typecasting of arguments */ make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); /* and build the expression node */ result = makeNode(ScalarArrayOpExpr); result->opno = oprid(tup); result->opfuncid = opform->oprcode; result->useOr = useOr; /* inputcollid will be set by parse_collate.c */ result->args = args; result->location = location; ReleaseSysCache(tup); return (Expr *) result; }
/* * make_op() * Operator expression construction. * * Transform operator expression ensuring type compatibility. * This is where some type conversion happens. * * As with coerce_type, pstate may be NULL if no special unknown-Param * processing is wanted. */ Expr * make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree, int location) { Oid ltypeId, rtypeId; Operator tup; Form_pg_operator opform; Oid actual_arg_types[2]; Oid declared_arg_types[2]; int nargs; List *args; Oid rettype; OpExpr *result; /* Select the operator */ if (rtree == NULL) { /* right operator */ ltypeId = exprType(ltree); rtypeId = InvalidOid; tup = right_oper(pstate, opname, ltypeId, false, location); } else if (ltree == NULL) { /* left operator */ rtypeId = exprType(rtree); ltypeId = InvalidOid; tup = left_oper(pstate, opname, rtypeId, false, location); } else { /* otherwise, binary operator */ ltypeId = exprType(ltree); rtypeId = exprType(rtree); tup = oper(pstate, opname, ltypeId, rtypeId, false, location); } opform = (Form_pg_operator) GETSTRUCT(tup); /* Check it's not a shell */ if (!RegProcedureIsValid(opform->oprcode)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator is only a shell: %s", op_signature_string(opname, opform->oprkind, opform->oprleft, opform->oprright)), parser_errposition(pstate, location))); /* Do typecasting and build the expression tree */ if (rtree == NULL) { /* right operator */ args = list_make1(ltree); actual_arg_types[0] = ltypeId; 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; nargs = 1; } else { /* otherwise, binary operator */ args = list_make2(ltree, rtree); actual_arg_types[0] = ltypeId; actual_arg_types[1] = rtypeId; declared_arg_types[0] = opform->oprleft; declared_arg_types[1] = opform->oprright; nargs = 2; } /* * enforce consistency with polymorphic argument and return types, * possibly adjusting return type or declared_arg_types (which will be * used as the cast destination by make_fn_arguments) */ rettype = enforce_generic_type_consistency(actual_arg_types, declared_arg_types, nargs, opform->oprresult, false); /* perform the necessary typecasting of arguments */ make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); /* and build the expression node */ result = makeNode(OpExpr); 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; ReleaseSysCache(tup); return (Expr *) result; }
/* * Coerce a Param to a query-requested datatype, in the varparams case. */ static Node * variable_coerce_param_hook(ParseState *pstate, Param *param, Oid targetTypeId, int32 targetTypeMod, int location) { if (param->paramkind == PARAM_EXTERN && param->paramtype == UNKNOWNOID) { /* * Input is a Param of previously undetermined type, and we want to * update our knowledge of the Param's type. */ VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state; Oid *paramTypes = *parstate->paramTypes; int paramno = param->paramid; if (paramno <= 0 || /* shouldn't happen, but... */ paramno > *parstate->numParams) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("there is no parameter $%d", paramno), parser_errposition(pstate, param->location))); if (paramTypes[paramno - 1] == UNKNOWNOID) { /* We've successfully resolved the type */ paramTypes[paramno - 1] = targetTypeId; } else if (paramTypes[paramno - 1] == targetTypeId) { /* We previously resolved the type, and it matches */ } else { /* Ooops */ ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_PARAMETER), errmsg("inconsistent types deduced for parameter $%d", paramno), errdetail("%s versus %s", format_type_be(paramTypes[paramno - 1]), format_type_be(targetTypeId)), parser_errposition(pstate, param->location))); } param->paramtype = targetTypeId; /* * Note: it is tempting here to set the Param's paramtypmod to * targetTypeMod, but that is probably unwise because we have no * infrastructure that enforces that the value delivered for a Param * will match any particular typmod. Leaving it -1 ensures that a * run-time length check/coercion will occur if needed. */ param->paramtypmod = -1; /* * This module always sets a Param's collation to be the default for * its datatype. If that's not what you want, you should be using * the more general parser substitution hooks. */ param->paramcollid = get_typcollation(param->paramtype); /* Use the leftmost of the param's and coercion's locations */ if (location >= 0 && (param->location < 0 || location < param->location)) param->location = location; return (Node *) param; } /* Else signal to proceed with normal coercion */ return NULL; }
/* * init_params: process the options list of CREATE or ALTER SEQUENCE, * and store the values into appropriate fields of *new. Also set * *owned_by to any OWNED BY option, or to NIL if there is none. * * If isInit is true, fill any unspecified options with default values; * otherwise, do not change existing options that aren't explicitly overridden. */ static void init_params(ParseState *pstate, List *options, bool isInit, Form_pg_sequence seqform, Form_pg_sequence_data seqdataform, List **owned_by) { DefElem *start_value = NULL; DefElem *restart_value = NULL; DefElem *increment_by = NULL; DefElem *max_value = NULL; DefElem *min_value = NULL; DefElem *cache_value = NULL; DefElem *is_cycled = NULL; ListCell *option; *owned_by = NIL; foreach(option, options) { DefElem *defel = (DefElem *) lfirst(option); if (strcmp(defel->defname, "increment") == 0) { if (increment_by) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"), parser_errposition(pstate, defel->location))); increment_by = defel; } else if (strcmp(defel->defname, "start") == 0) { if (start_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"), parser_errposition(pstate, defel->location))); start_value = defel; } else if (strcmp(defel->defname, "restart") == 0) { if (restart_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"), parser_errposition(pstate, defel->location))); restart_value = defel; } else if (strcmp(defel->defname, "maxvalue") == 0) { if (max_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"), parser_errposition(pstate, defel->location))); max_value = defel; } else if (strcmp(defel->defname, "minvalue") == 0) { if (min_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"), parser_errposition(pstate, defel->location))); min_value = defel; } else if (strcmp(defel->defname, "cache") == 0) { if (cache_value) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"), parser_errposition(pstate, defel->location))); cache_value = defel; } else if (strcmp(defel->defname, "cycle") == 0) { if (is_cycled) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"), parser_errposition(pstate, defel->location))); is_cycled = defel; } else if (strcmp(defel->defname, "owned_by") == 0) { if (*owned_by) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"), parser_errposition(pstate, defel->location))); *owned_by = defGetQualifiedName(defel); } else elog(ERROR, "option \"%s\" not recognized", defel->defname); }
/* * Parse a function call * * For historical reasons, Postgres tries to treat the notations tab.col * and col(tab) as equivalent: if a single-argument function call has an * argument of complex type and the (unqualified) function name matches * any attribute of the type, we take it as a column projection. Conversely * a function of a single complex-type argument can be written like a * column reference, allowing functions to act like computed columns. * * Hence, both cases come through here. The is_column parameter tells us * which syntactic construct is actually being dealt with, but this is * intended to be used only to deliver an appropriate error message, * not to affect the semantics. When is_column is true, we should have * a single argument (the putative table), unqualified function name * equal to the column name, and no aggregate or variadic decoration. * Also, when is_column is true, we return NULL on failure rather than * reporting a no-such-function error. * * The argument expressions (in fargs) must have been transformed already. * But the agg_order expressions, if any, have not been. */ Node * ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, List *agg_order, bool agg_star, bool agg_distinct, bool func_variadic, WindowDef *over, bool is_column, int location) { Oid rettype; Oid funcid; ListCell *l; ListCell *nextl; Node *first_arg = NULL; int nargs; int nargsplusdefs; Oid actual_arg_types[FUNC_MAX_ARGS]; Oid *declared_arg_types; List *argnames; List *argdefaults; Node *retval; bool retset; int nvargs; FuncDetailCode fdresult; /* * Most of the rest of the parser just assumes that functions do not have * more than FUNC_MAX_ARGS parameters. We have to test here to protect * against array overruns, etc. Of course, this may not be a function, * but the test doesn't hurt. */ if (list_length(fargs) > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg_plural("cannot pass more than %d argument to a function", "cannot pass more than %d arguments to a function", FUNC_MAX_ARGS, FUNC_MAX_ARGS), parser_errposition(pstate, location))); /* * Extract arg type info in preparation for function lookup. * * If any arguments are Param markers of type VOID, we discard them from * the parameter list. This is a hack to allow the JDBC driver to not * have to distinguish "input" and "output" parameter symbols while * parsing function-call constructs. We can't use foreach() because we * may modify the list ... */ nargs = 0; for (l = list_head(fargs); l != NULL; l = nextl) { Node *arg = lfirst(l); Oid argtype = exprType(arg); nextl = lnext(l); if (argtype == VOIDOID && IsA(arg, Param) &&!is_column) { fargs = list_delete_ptr(fargs, arg); continue; } actual_arg_types[nargs++] = argtype; } /* * Check for named arguments; if there are any, build a list of names. * * We allow mixed notation (some named and some not), but only with all * the named parameters after all the unnamed ones. So the name list * corresponds to the last N actual parameters and we don't need any extra * bookkeeping to match things up. */ argnames = NIL; foreach(l, fargs) { Node *arg = lfirst(l); if (IsA(arg, NamedArgExpr)) { NamedArgExpr *na = (NamedArgExpr *) arg; ListCell *lc; /* Reject duplicate arg names */ foreach(lc, argnames) { if (strcmp(na->name, (char *) lfirst(lc)) == 0) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("argument name \"%s\" used more than once", na->name), parser_errposition(pstate, na->location))); } argnames = lappend(argnames, na->name); } else { if (argnames != NIL)
if (strcmp(na->name, (char *) lfirst(lc)) == 0) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("argument name \"%s\" used more than once", na->name), parser_errposition(pstate, na->location))); } argnames = lappend(argnames, na->name); } else { if (argnames != NIL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("positional argument cannot follow named argument"), parser_errposition(pstate, exprLocation(arg)))); } } if (fargs) { first_arg = linitial(fargs); Assert(first_arg != NULL); } /* * Check for column projection: if function has one argument, and that * argument is of complex type, and function name is not qualified, then * the "function call" could be a projection. We also check that there * wasn't any aggregate or variadic decoration, nor an argument name. */
/* * Parse a function call * * For historical reasons, Postgres tries to treat the notations tab.col * and col(tab) as equivalent: if a single-argument function call has an * argument of complex type and the (unqualified) function name matches * any attribute of the type, we take it as a column projection. Conversely * a function of a single complex-type argument can be written like a * column reference, allowing functions to act like computed columns. * * Hence, both cases come through here. The is_column parameter tells us * which syntactic construct is actually being dealt with, but this is * intended to be used only to deliver an appropriate error message, * not to affect the semantics. When is_column is true, we should have * a single argument (the putative table), unqualified function name * equal to the column name, and no aggregate or variadic decoration. * * The argument expressions (in fargs) must have been transformed already. */ Node * ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, bool agg_star, bool agg_distinct, bool func_variadic, WindowDef *over, bool is_column, int location) { Oid rettype; Oid funcid; ListCell *l; ListCell *nextl; Node *first_arg = NULL; int nargs; int nargsplusdefs; Oid actual_arg_types[FUNC_MAX_ARGS]; Oid *declared_arg_types; List *argdefaults; Node *retval; bool retset; int nvargs; FuncDetailCode fdresult; /* * Most of the rest of the parser just assumes that functions do not have * more than FUNC_MAX_ARGS parameters. We have to test here to protect * against array overruns, etc. Of course, this may not be a function, * but the test doesn't hurt. */ if (list_length(fargs) > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg_plural("cannot pass more than %d argument to a function", "cannot pass more than %d arguments to a function", FUNC_MAX_ARGS, FUNC_MAX_ARGS), parser_errposition(pstate, location))); /* * Extract arg type info in preparation for function lookup. * * If any arguments are Param markers of type VOID, we discard them from * the parameter list. This is a hack to allow the JDBC driver to not * have to distinguish "input" and "output" parameter symbols while * parsing function-call constructs. We can't use foreach() because we * may modify the list ... */ nargs = 0; for (l = list_head(fargs); l != NULL; l = nextl) { Node *arg = lfirst(l); Oid argtype = exprType(arg); nextl = lnext(l); if (argtype == VOIDOID && IsA(arg, Param) &&!is_column) { fargs = list_delete_ptr(fargs, arg); continue; } actual_arg_types[nargs++] = argtype; } if (fargs) { first_arg = linitial(fargs); Assert(first_arg != NULL); } /* * Check for column projection: if function has one argument, and that * argument is of complex type, and function name is not qualified, then * the "function call" could be a projection. We also check that there * wasn't any aggregate or variadic decoration. */ if (nargs == 1 && !agg_star && !agg_distinct && over == NULL && !func_variadic && list_length(funcname) == 1) { Oid argtype = actual_arg_types[0]; if (argtype == RECORDOID || ISCOMPLEX(argtype)) { retval = ParseComplexProjection(pstate, strVal(linitial(funcname)), first_arg, location); if (retval) return retval; /* * If ParseComplexProjection doesn't recognize it as a projection, * just press on. */ } } /* * Okay, it's not a column projection, so it must really be a function. * func_get_detail looks up the function in the catalogs, does * disambiguation for polymorphic functions, handles inheritance, and * returns the funcid and type and set or singleton status of the * function's return value. It also returns the true argument types to * the function. In the case of a variadic function call, the reported * "true" types aren't really what is in pg_proc: the variadic argument is * replaced by a suitable number of copies of its element type. We'll fix * it up below. We may also have to deal with default arguments. */ fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types, !func_variadic, true, &funcid, &rettype, &retset, &nvargs, &declared_arg_types, &argdefaults); if (fdresult == FUNCDETAIL_COERCION) { /* * We interpreted it as a type coercion. coerce_type can handle these * cases, so why duplicate code... */ return coerce_type(pstate, linitial(fargs), actual_arg_types[0], rettype, -1, COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location); } else if (fdresult == FUNCDETAIL_NORMAL) { /* * Normal function found; was there anything indicating it must be an * aggregate? */ if (agg_star) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("%s(*) specified, but %s is not an aggregate function", NameListToString(funcname), NameListToString(funcname)), parser_errposition(pstate, location))); if (agg_distinct) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("DISTINCT specified, but %s is not an aggregate function", NameListToString(funcname)), parser_errposition(pstate, location))); if (over) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("OVER specified, but %s is not a window function nor an aggregate function", NameListToString(funcname)), parser_errposition(pstate, location))); } else if (!(fdresult == FUNCDETAIL_AGGREGATE || fdresult == FUNCDETAIL_WINDOWFUNC)) { /* * Oops. Time to die. * * If we are dealing with the attribute notation rel.function, give an * error message that is appropriate for that case. */ if (is_column) { Assert(nargs == 1); Assert(list_length(funcname) == 1); unknown_attribute(pstate, first_arg, strVal(linitial(funcname)), location); } /* * Else generate a detailed complaint for a function */ if (fdresult == FUNCDETAIL_MULTIPLE) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("function %s is not unique", func_signature_string(funcname, nargs, actual_arg_types)), errhint("Could not choose a best candidate function. " "You might need to add explicit type casts."), parser_errposition(pstate, location))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function %s does not exist", func_signature_string(funcname, nargs, actual_arg_types)), errhint("No function matches the given name and argument types. " "You might need to add explicit type casts."), parser_errposition(pstate, location))); } /* * If there are default arguments, we have to include their types in * actual_arg_types for the purpose of checking generic type consistency. * However, we do NOT put them into the generated parse node, because * their actual values might change before the query gets run. The * planner has to insert the up-to-date values at plan time. */ nargsplusdefs = nargs; foreach(l, argdefaults) { Node *expr = (Node *) lfirst(l); /* probably shouldn't happen ... */ if (nargsplusdefs >= FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg_plural("cannot pass more than %d argument to a function", "cannot pass more than %d arguments to a function", FUNC_MAX_ARGS, FUNC_MAX_ARGS), parser_errposition(pstate, location))); actual_arg_types[nargsplusdefs++] = exprType(expr); }
/* * Transform the subscript expressions. */ foreach(idx, indirection) { A_Indices *ai = castNode(A_Indices, lfirst(idx)); Node *subexpr; 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 if (!ai->is_slice) { /* Make a constant 1 */ subexpr = (Node *) makeConst(INT4OID, -1, InvalidOid, sizeof(int32), Int32GetDatum(1), false, true); /* pass by value */ } else { /* Slice with omitted lower bound, put NULL into the list */ subexpr = NULL; } lowerIndexpr = lappend(lowerIndexpr, subexpr); } else Assert(ai->lidx == NULL && !ai->is_slice); if (ai->uidx) { 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)))); } else { /* Slice with omitted upper bound, put NULL into the list */ Assert(isSlice && ai->is_slice); subexpr = NULL; } upperIndexpr = lappend(upperIndexpr, subexpr); }
/* * make_scalar_array_op() * Build expression tree for "scalar op ANY/ALL (array)" construct. */ Expr * make_scalar_array_op(ParseState *pstate, List *opname, bool useOr, Node *ltree, Node *rtree, int location) { Oid ltypeId, rtypeId, atypeId, res_atypeId; Operator tup; Form_pg_operator opform; Oid actual_arg_types[2]; Oid declared_arg_types[2]; List *args; Oid rettype; ScalarArrayOpExpr *result; ltypeId = exprType(ltree); atypeId = exprType(rtree); /* * The right-hand input of the operator will be the element type of the * array. However, if we currently have just an untyped literal on the * right, stay with that and hope we can resolve the operator. */ if (atypeId == UNKNOWNOID) rtypeId = UNKNOWNOID; else { rtypeId = get_element_type(atypeId); if (!OidIsValid(rtypeId)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires array on right side"), errOmitLocation(true), parser_errposition(pstate, location))); } /* Now resolve the operator */ tup = oper(pstate, opname, ltypeId, rtypeId, false, location); opform = (Form_pg_operator) GETSTRUCT(tup); args = list_make2(ltree, rtree); actual_arg_types[0] = ltypeId; actual_arg_types[1] = rtypeId; declared_arg_types[0] = opform->oprleft; declared_arg_types[1] = opform->oprright; /* * enforce consistency with ANYARRAY and ANYELEMENT argument and return * types, possibly adjusting return type or declared_arg_types (which will * be used as the cast destination by make_fn_arguments) */ rettype = enforce_generic_type_consistency(actual_arg_types, declared_arg_types, 2, opform->oprresult); /* * Check that operator result is boolean */ if (rettype != BOOLOID) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires operator to yield boolean"), errOmitLocation(true), parser_errposition(pstate, location))); if (get_func_retset(opform->oprcode)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires operator not to return a set"), errOmitLocation(true), parser_errposition(pstate, location))); /* * Now switch back to the array type on the right, arranging for any * needed cast to be applied. */ res_atypeId = get_array_type(declared_arg_types[1]); if (!OidIsValid(res_atypeId)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find array type for data type %s", format_type_be(declared_arg_types[1])), errOmitLocation(true), parser_errposition(pstate, location))); actual_arg_types[1] = atypeId; declared_arg_types[1] = res_atypeId; /* perform the necessary typecasting of arguments */ make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); /* and build the expression node */ result = makeNode(ScalarArrayOpExpr); result->opno = oprid(tup); result->opfuncid = InvalidOid; result->useOr = useOr; result->args = args; ReleaseOperator(tup); return (Expr *) result; }