aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/gram.y255
-rw-r--r--src/backend/parser/parse_agg.c11
-rw-r--r--src/backend/parser/parse_expr.c8
-rw-r--r--src/backend/parser/parse_func.c201
4 files changed, 393 insertions, 82 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c301ca465d4..ebfc94f8969 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -253,7 +253,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
AlterCompositeTypeStmt AlterUserMappingStmt
AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt
AlterDefaultPrivilegesStmt DefACLAction
- AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
+ AnalyzeStmt CallStmt ClosePortalStmt ClusterStmt CommentStmt
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
CreateDomainStmt CreateExtensionStmt CreateGroupStmt CreateOpClassStmt
CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
@@ -611,7 +611,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
BOOLEAN_P BOTH BY
- CACHE CALLED CASCADE CASCADED CASE CAST CATALOG_P CHAIN CHAR_P
+ CACHE CALL CALLED CASCADE CASCADED CASE CAST CATALOG_P CHAIN CHAR_P
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
CLUSTER COALESCE COLLATE COLLATION COLUMN COLUMNS COMMENT COMMENTS COMMIT
COMMITTED CONCURRENTLY CONFIGURATION CONFLICT CONNECTION CONSTRAINT
@@ -660,14 +660,14 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
PARALLEL PARSER PARTIAL PARTITION PASSING PASSWORD PLACING PLANS POLICY
POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
- PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROGRAM PUBLICATION
+ PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION
QUOTE
RANGE READ REAL REASSIGN RECHECK RECURSIVE REF REFERENCES REFERENCING
REFRESH REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA
RESET RESTART RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
- ROW ROWS RULE
+ ROUTINE ROUTINES ROW ROWS RULE
SAVEPOINT SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
@@ -845,6 +845,7 @@ stmt :
| AlterTSDictionaryStmt
| AlterUserMappingStmt
| AnalyzeStmt
+ | CallStmt
| CheckPointStmt
| ClosePortalStmt
| ClusterStmt
@@ -942,6 +943,20 @@ stmt :
/*****************************************************************************
*
+ * CALL statement
+ *
+ *****************************************************************************/
+
+CallStmt: CALL func_application
+ {
+ CallStmt *n = makeNode(CallStmt);
+ n->funccall = castNode(FuncCall, $2);
+ $$ = (Node *)n;
+ }
+ ;
+
+/*****************************************************************************
+ *
* Create a new Postgres DBMS role
*
*****************************************************************************/
@@ -4554,6 +4569,24 @@ AlterExtensionContentsStmt:
n->object = (Node *) lcons(makeString($9), $7);
$$ = (Node *)n;
}
+ | ALTER EXTENSION name add_drop PROCEDURE function_with_argtypes
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_PROCEDURE;
+ n->object = (Node *) $6;
+ $$ = (Node *)n;
+ }
+ | ALTER EXTENSION name add_drop ROUTINE function_with_argtypes
+ {
+ AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
+ n->extname = $3;
+ n->action = $4;
+ n->objtype = OBJECT_ROUTINE;
+ n->object = (Node *) $6;
+ $$ = (Node *)n;
+ }
| ALTER EXTENSION name add_drop SCHEMA name
{
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
@@ -6436,6 +6469,22 @@ CommentStmt:
n->comment = $8;
$$ = (Node *) n;
}
+ | COMMENT ON PROCEDURE function_with_argtypes IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_PROCEDURE;
+ n->object = (Node *) $4;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON ROUTINE function_with_argtypes IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_ROUTINE;
+ n->object = (Node *) $4;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
| COMMENT ON RULE name ON any_name IS comment_text
{
CommentStmt *n = makeNode(CommentStmt);
@@ -6614,6 +6663,26 @@ SecLabelStmt:
n->label = $9;
$$ = (Node *) n;
}
+ | SECURITY LABEL opt_provider ON PROCEDURE function_with_argtypes
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_PROCEDURE;
+ n->object = (Node *) $6;
+ n->label = $8;
+ $$ = (Node *) n;
+ }
+ | SECURITY LABEL opt_provider ON ROUTINE function_with_argtypes
+ IS security_label
+ {
+ SecLabelStmt *n = makeNode(SecLabelStmt);
+ n->provider = $3;
+ n->objtype = OBJECT_ROUTINE;
+ n->object = (Node *) $6;
+ n->label = $8;
+ $$ = (Node *) n;
+ }
;
opt_provider: FOR NonReservedWord_or_Sconst { $$ = $2; }
@@ -6977,6 +7046,22 @@ privilege_target:
n->objs = $2;
$$ = n;
}
+ | PROCEDURE function_with_argtypes_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = ACL_OBJECT_PROCEDURE;
+ n->objs = $2;
+ $$ = n;
+ }
+ | ROUTINE function_with_argtypes_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_OBJECT;
+ n->objtype = ACL_OBJECT_ROUTINE;
+ n->objs = $2;
+ $$ = n;
+ }
| DATABASE name_list
{
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
@@ -7057,6 +7142,22 @@ privilege_target:
n->objs = $5;
$$ = n;
}
+ | ALL PROCEDURES IN_P SCHEMA name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
+ n->objtype = ACL_OBJECT_PROCEDURE;
+ n->objs = $5;
+ $$ = n;
+ }
+ | ALL ROUTINES IN_P SCHEMA name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
+ n->objtype = ACL_OBJECT_ROUTINE;
+ n->objs = $5;
+ $$ = n;
+ }
;
@@ -7213,6 +7314,7 @@ DefACLAction:
defacl_privilege_target:
TABLES { $$ = ACL_OBJECT_RELATION; }
| FUNCTIONS { $$ = ACL_OBJECT_FUNCTION; }
+ | ROUTINES { $$ = ACL_OBJECT_FUNCTION; }
| SEQUENCES { $$ = ACL_OBJECT_SEQUENCE; }
| TYPES_P { $$ = ACL_OBJECT_TYPE; }
| SCHEMAS { $$ = ACL_OBJECT_NAMESPACE; }
@@ -7413,6 +7515,18 @@ CreateFunctionStmt:
n->withClause = $7;
$$ = (Node *)n;
}
+ | CREATE opt_or_replace PROCEDURE func_name func_args_with_defaults
+ createfunc_opt_list
+ {
+ CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
+ n->replace = $2;
+ n->funcname = $4;
+ n->parameters = $5;
+ n->returnType = NULL;
+ n->is_procedure = true;
+ n->options = $6;
+ $$ = (Node *)n;
+ }
;
opt_or_replace:
@@ -7830,7 +7944,7 @@ table_func_column_list:
;
/*****************************************************************************
- * ALTER FUNCTION
+ * ALTER FUNCTION / ALTER PROCEDURE / ALTER ROUTINE
*
* RENAME and OWNER subcommands are already provided by the generic
* ALTER infrastructure, here we just specify alterations that can
@@ -7841,6 +7955,23 @@ AlterFunctionStmt:
ALTER FUNCTION function_with_argtypes alterfunc_opt_list opt_restrict
{
AlterFunctionStmt *n = makeNode(AlterFunctionStmt);
+ n->objtype = OBJECT_FUNCTION;
+ n->func = $3;
+ n->actions = $4;
+ $$ = (Node *) n;
+ }
+ | ALTER PROCEDURE function_with_argtypes alterfunc_opt_list opt_restrict
+ {
+ AlterFunctionStmt *n = makeNode(AlterFunctionStmt);
+ n->objtype = OBJECT_PROCEDURE;
+ n->func = $3;
+ n->actions = $4;
+ $$ = (Node *) n;
+ }
+ | ALTER ROUTINE function_with_argtypes alterfunc_opt_list opt_restrict
+ {
+ AlterFunctionStmt *n = makeNode(AlterFunctionStmt);
+ n->objtype = OBJECT_ROUTINE;
n->func = $3;
n->actions = $4;
$$ = (Node *) n;
@@ -7865,6 +7996,8 @@ opt_restrict:
* QUERY:
*
* DROP FUNCTION funcname (arg1, arg2, ...) [ RESTRICT | CASCADE ]
+ * DROP PROCEDURE procname (arg1, arg2, ...) [ RESTRICT | CASCADE ]
+ * DROP ROUTINE routname (arg1, arg2, ...) [ RESTRICT | CASCADE ]
* DROP AGGREGATE aggname (arg1, ...) [ RESTRICT | CASCADE ]
* DROP OPERATOR opname (leftoperand_typ, rightoperand_typ) [ RESTRICT | CASCADE ]
*
@@ -7891,6 +8024,46 @@ RemoveFuncStmt:
n->concurrent = false;
$$ = (Node *)n;
}
+ | DROP PROCEDURE function_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_PROCEDURE;
+ n->objects = $3;
+ n->behavior = $4;
+ n->missing_ok = false;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ | DROP PROCEDURE IF_P EXISTS function_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_PROCEDURE;
+ n->objects = $5;
+ n->behavior = $6;
+ n->missing_ok = true;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ | DROP ROUTINE function_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_ROUTINE;
+ n->objects = $3;
+ n->behavior = $4;
+ n->missing_ok = false;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
+ | DROP ROUTINE IF_P EXISTS function_with_argtypes_list opt_drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = OBJECT_ROUTINE;
+ n->objects = $5;
+ n->behavior = $6;
+ n->missing_ok = true;
+ n->concurrent = false;
+ $$ = (Node *)n;
+ }
;
RemoveAggrStmt:
@@ -8348,6 +8521,15 @@ RenameStmt: ALTER AGGREGATE aggregate_with_argtypes RENAME TO name
n->missing_ok = true;
$$ = (Node *)n;
}
+ | ALTER PROCEDURE function_with_argtypes RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_PROCEDURE;
+ n->object = (Node *) $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
| ALTER PUBLICATION name RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
@@ -8357,6 +8539,15 @@ RenameStmt: ALTER AGGREGATE aggregate_with_argtypes RENAME TO name
n->missing_ok = false;
$$ = (Node *)n;
}
+ | ALTER ROUTINE function_with_argtypes RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_ROUTINE;
+ n->object = (Node *) $3;
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
| ALTER SCHEMA name RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
@@ -8736,6 +8927,22 @@ AlterObjectDependsStmt:
n->extname = makeString($7);
$$ = (Node *)n;
}
+ | ALTER PROCEDURE function_with_argtypes DEPENDS ON EXTENSION name
+ {
+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);
+ n->objectType = OBJECT_PROCEDURE;
+ n->object = (Node *) $3;
+ n->extname = makeString($7);
+ $$ = (Node *)n;
+ }
+ | ALTER ROUTINE function_with_argtypes DEPENDS ON EXTENSION name
+ {
+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);
+ n->objectType = OBJECT_ROUTINE;
+ n->object = (Node *) $3;
+ n->extname = makeString($7);
+ $$ = (Node *)n;
+ }
| ALTER TRIGGER name ON qualified_name DEPENDS ON EXTENSION name
{
AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);
@@ -8851,6 +9058,24 @@ AlterObjectSchemaStmt:
n->missing_ok = false;
$$ = (Node *)n;
}
+ | ALTER PROCEDURE function_with_argtypes SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_PROCEDURE;
+ n->object = (Node *) $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
+ | ALTER ROUTINE function_with_argtypes SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_ROUTINE;
+ n->object = (Node *) $3;
+ n->newschema = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
| ALTER TABLE relation_expr SET SCHEMA name
{
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
@@ -9126,6 +9351,22 @@ AlterOwnerStmt: ALTER AGGREGATE aggregate_with_argtypes OWNER TO RoleSpec
n->newowner = $9;
$$ = (Node *)n;
}
+ | ALTER PROCEDURE function_with_argtypes OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_PROCEDURE;
+ n->object = (Node *) $3;
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
+ | ALTER ROUTINE function_with_argtypes OWNER TO RoleSpec
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_ROUTINE;
+ n->object = (Node *) $3;
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
| ALTER SCHEMA name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
@@ -14689,6 +14930,7 @@ unreserved_keyword:
| BEGIN_P
| BY
| CACHE
+ | CALL
| CALLED
| CASCADE
| CASCADED
@@ -14848,6 +15090,7 @@ unreserved_keyword:
| PRIVILEGES
| PROCEDURAL
| PROCEDURE
+ | PROCEDURES
| PROGRAM
| PUBLICATION
| QUOTE
@@ -14874,6 +15117,8 @@ unreserved_keyword:
| ROLE
| ROLLBACK
| ROLLUP
+ | ROUTINE
+ | ROUTINES
| ROWS
| RULE
| SAVEPOINT
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 64111f315e3..4c4f4cdc3d7 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -508,6 +508,14 @@ check_agglevels_and_constraints(ParseState *pstate, Node *expr)
break;
+ case EXPR_KIND_CALL:
+ if (isAgg)
+ err = _("aggregate functions are not allowed in CALL arguments");
+ else
+ err = _("grouping operations are not allowed in CALL arguments");
+
+ break;
+
/*
* There is intentionally no default: case here, so that the
* compiler will warn if we add a new ParseExprKind without
@@ -883,6 +891,9 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
case EXPR_KIND_PARTITION_EXPRESSION:
err = _("window functions are not allowed in partition key expression");
break;
+ case EXPR_KIND_CALL:
+ err = _("window functions are not allowed in CALL arguments");
+ break;
/*
* There is intentionally no default: case here, so that the
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 86d1da06775..29f9da796fc 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -480,6 +480,7 @@ transformIndirection(ParseState *pstate, A_Indirection *ind)
list_make1(result),
last_srf,
NULL,
+ false,
location);
if (newresult == NULL)
unknown_attribute(pstate, result, strVal(n), location);
@@ -629,6 +630,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
list_make1(node),
pstate->p_last_srf,
NULL,
+ false,
cref->location);
}
break;
@@ -676,6 +678,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
list_make1(node),
pstate->p_last_srf,
NULL,
+ false,
cref->location);
}
break;
@@ -736,6 +739,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
list_make1(node),
pstate->p_last_srf,
NULL,
+ false,
cref->location);
}
break;
@@ -1477,6 +1481,7 @@ transformFuncCall(ParseState *pstate, FuncCall *fn)
targs,
last_srf,
fn,
+ false,
fn->location);
}
@@ -1812,6 +1817,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
case EXPR_KIND_RETURNING:
case EXPR_KIND_VALUES:
case EXPR_KIND_VALUES_SINGLE:
+ case EXPR_KIND_CALL:
/* okay */
break;
case EXPR_KIND_CHECK_CONSTRAINT:
@@ -3462,6 +3468,8 @@ ParseExprKindName(ParseExprKind exprKind)
return "WHEN";
case EXPR_KIND_PARTITION_EXPRESSION:
return "PARTITION BY";
+ case EXPR_KIND_CALL:
+ return "CALL";
/*
* There is intentionally no default: case here, so that the
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index a11843332b0..2f20516e766 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -71,7 +71,7 @@ static Node *ParseComplexProjection(ParseState *pstate, const char *funcname,
*/
Node *
ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
- Node *last_srf, FuncCall *fn, int location)
+ Node *last_srf, FuncCall *fn, bool proc_call, int location)
{
bool is_column = (fn == NULL);
List *agg_order = (fn ? fn->agg_order : NIL);
@@ -263,7 +263,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
actual_arg_types[0], rettype, -1,
COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location);
}
- else if (fdresult == FUNCDETAIL_NORMAL)
+ else if (fdresult == FUNCDETAIL_NORMAL || fdresult == FUNCDETAIL_PROCEDURE)
{
/*
* Normal function found; was there anything indicating it must be an
@@ -306,6 +306,26 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
errmsg("OVER specified, but %s is not a window function nor an aggregate function",
NameListToString(funcname)),
parser_errposition(pstate, location)));
+
+ if (fdresult == FUNCDETAIL_NORMAL && proc_call)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("%s is not a procedure",
+ func_signature_string(funcname, nargs,
+ argnames,
+ actual_arg_types)),
+ errhint("To call a function, use SELECT."),
+ parser_errposition(pstate, location)));
+
+ if (fdresult == FUNCDETAIL_PROCEDURE && !proc_call)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("%s is a procedure",
+ func_signature_string(funcname, nargs,
+ argnames,
+ actual_arg_types)),
+ errhint("To call a procedure, use CALL."),
+ parser_errposition(pstate, location)));
}
else if (fdresult == FUNCDETAIL_AGGREGATE)
{
@@ -635,7 +655,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
check_srf_call_placement(pstate, last_srf, location);
/* build the appropriate output structure */
- if (fdresult == FUNCDETAIL_NORMAL)
+ if (fdresult == FUNCDETAIL_NORMAL || fdresult == FUNCDETAIL_PROCEDURE)
{
FuncExpr *funcexpr = makeNode(FuncExpr);
@@ -1589,6 +1609,8 @@ func_get_detail(List *funcname,
result = FUNCDETAIL_AGGREGATE;
else if (pform->proiswindow)
result = FUNCDETAIL_WINDOWFUNC;
+ else if (pform->prorettype == InvalidOid)
+ result = FUNCDETAIL_PROCEDURE;
else
result = FUNCDETAIL_NORMAL;
ReleaseSysCache(ftup);
@@ -1984,16 +2006,28 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
/*
* LookupFuncWithArgs
- * Like LookupFuncName, but the argument types are specified by a
- * ObjectWithArgs node.
+ *
+ * Like LookupFuncName, but the argument types are specified by a
+ * ObjectWithArgs node. Also, this function can check whether the result is a
+ * function, procedure, or aggregate, based on the objtype argument. Pass
+ * OBJECT_ROUTINE to accept any of them.
+ *
+ * For historical reasons, we also accept aggregates when looking for a
+ * function.
*/
Oid
-LookupFuncWithArgs(ObjectWithArgs *func, bool noError)
+LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool noError)
{
Oid argoids[FUNC_MAX_ARGS];
int argcount;
int i;
ListCell *args_item;
+ Oid oid;
+
+ Assert(objtype == OBJECT_AGGREGATE ||
+ objtype == OBJECT_FUNCTION ||
+ objtype == OBJECT_PROCEDURE ||
+ objtype == OBJECT_ROUTINE);
argcount = list_length(func->objargs);
if (argcount > FUNC_MAX_ARGS)
@@ -2013,90 +2047,100 @@ LookupFuncWithArgs(ObjectWithArgs *func, bool noError)
args_item = lnext(args_item);
}
- return LookupFuncName(func->objname, func->args_unspecified ? -1 : argcount, argoids, noError);
-}
-
-/*
- * LookupAggWithArgs
- * Find an aggregate function from a given ObjectWithArgs node.
- *
- * This is almost like LookupFuncWithArgs, but the error messages refer
- * to aggregates rather than plain functions, and we verify that the found
- * function really is an aggregate.
- */
-Oid
-LookupAggWithArgs(ObjectWithArgs *agg, bool noError)
-{
- Oid argoids[FUNC_MAX_ARGS];
- int argcount;
- int i;
- ListCell *lc;
- Oid oid;
- HeapTuple ftup;
- Form_pg_proc pform;
-
- argcount = list_length(agg->objargs);
- if (argcount > FUNC_MAX_ARGS)
- ereport(ERROR,
- (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
- errmsg_plural("functions cannot have more than %d argument",
- "functions cannot have more than %d arguments",
- FUNC_MAX_ARGS,
- FUNC_MAX_ARGS)));
+ /*
+ * When looking for a function or routine, we pass noError through to
+ * LookupFuncName and let it make any error messages. Otherwise, we make
+ * our own errors for the aggregate and procedure cases.
+ */
+ oid = LookupFuncName(func->objname, func->args_unspecified ? -1 : argcount, argoids,
+ (objtype == OBJECT_FUNCTION || objtype == OBJECT_ROUTINE) ? noError : true);
- i = 0;
- foreach(lc, agg->objargs)
+ if (objtype == OBJECT_FUNCTION)
{
- TypeName *t = (TypeName *) lfirst(lc);
-
- argoids[i] = LookupTypeNameOid(NULL, t, noError);
- i++;
+ /* Make sure it's a function, not a procedure */
+ if (oid && get_func_rettype(oid) == InvalidOid)
+ {
+ if (noError)
+ return InvalidOid;
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("%s is not a function",
+ func_signature_string(func->objname, argcount,
+ NIL, argoids))));
+ }
}
-
- oid = LookupFuncName(agg->objname, argcount, argoids, true);
-
- if (!OidIsValid(oid))
+ else if (objtype == OBJECT_PROCEDURE)
{
- if (noError)
- return InvalidOid;
- if (argcount == 0)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_FUNCTION),
- errmsg("aggregate %s(*) does not exist",
- NameListToString(agg->objname))));
- else
+ if (!OidIsValid(oid))
+ {
+ if (noError)
+ return InvalidOid;
+ else if (func->args_unspecified)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not find a procedure named \"%s\"",
+ NameListToString(func->objname))));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("procedure %s does not exist",
+ func_signature_string(func->objname, argcount,
+ NIL, argoids))));
+ }
+
+ /* Make sure it's a procedure */
+ if (get_func_rettype(oid) != InvalidOid)
+ {
+ if (noError)
+ return InvalidOid;
ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_FUNCTION),
- errmsg("aggregate %s does not exist",
- func_signature_string(agg->objname, argcount,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("%s is not a procedure",
+ func_signature_string(func->objname, argcount,
NIL, argoids))));
+ }
}
-
- /* Make sure it's an aggregate */
- ftup = SearchSysCache1(PROCOID, ObjectIdGetDatum(oid));
- if (!HeapTupleIsValid(ftup)) /* should not happen */
- elog(ERROR, "cache lookup failed for function %u", oid);
- pform = (Form_pg_proc) GETSTRUCT(ftup);
-
- if (!pform->proisagg)
+ else if (objtype == OBJECT_AGGREGATE)
{
- ReleaseSysCache(ftup);
- if (noError)
- return InvalidOid;
- /* we do not use the (*) notation for functions... */
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("function %s is not an aggregate",
- func_signature_string(agg->objname, argcount,
- NIL, argoids))));
- }
+ if (!OidIsValid(oid))
+ {
+ if (noError)
+ return InvalidOid;
+ else if (func->args_unspecified)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not find a aggregate named \"%s\"",
+ NameListToString(func->objname))));
+ else if (argcount == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("aggregate %s(*) does not exist",
+ NameListToString(func->objname))));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("aggregate %s does not exist",
+ func_signature_string(func->objname, argcount,
+ NIL, argoids))));
+ }
- ReleaseSysCache(ftup);
+ /* Make sure it's an aggregate */
+ if (!get_func_isagg(oid))
+ {
+ if (noError)
+ return InvalidOid;
+ /* we do not use the (*) notation for functions... */
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("function %s is not an aggregate",
+ func_signature_string(func->objname, argcount,
+ NIL, argoids))));
+ }
+ }
return oid;
}
-
/*
* check_srf_call_placement
* Verify that a set-returning function is called in a valid place,
@@ -2236,6 +2280,9 @@ check_srf_call_placement(ParseState *pstate, Node *last_srf, int location)
case EXPR_KIND_PARTITION_EXPRESSION:
err = _("set-returning functions are not allowed in partition key expressions");
break;
+ case EXPR_KIND_CALL:
+ err = _("set-returning functions are not allowed in CALL arguments");
+ break;
/*
* There is intentionally no default: case here, so that the