diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 069adf46af5..c2c521bbfea 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.57 2005/03/29 00:16:57 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.58 2005/03/29 17:58:49 tgl Exp $ * * DESCRIPTION * These routines take the parse tree and pick out the @@ -154,6 +154,15 @@ examine_parameter_list(List *parameter, Oid languageOid, errmsg("functions cannot have more than %d arguments", FUNC_MAX_ARGS))); + if (fp->mode == FUNC_PARAM_OUT) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("CREATE FUNCTION / OUT parameters are not implemented"))); + if (fp->mode == FUNC_PARAM_INOUT) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("CREATE FUNCTION / INOUT parameters are not implemented"))); + toid = LookupTypeName(t); if (OidIsValid(toid)) { diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 92f7168ae9f..c2130e370d4 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.298 2005/03/14 00:19:36 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.299 2005/03/29 17:58:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1888,6 +1888,7 @@ _copyFunctionParameter(FunctionParameter *from) COPY_STRING_FIELD(name); COPY_NODE_FIELD(argType); + COPY_SCALAR_FIELD(mode); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index cbd99dab720..bcf8c363937 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.237 2005/03/14 00:19:36 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.238 2005/03/29 17:58:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -949,6 +949,7 @@ _equalFunctionParameter(FunctionParameter *a, FunctionParameter *b) { COMPARE_STRING_FIELD(name); COMPARE_NODE_FIELD(argType); + COMPARE_SCALAR_FIELD(mode); return true; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index a88262d4328..62497957263 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.484 2005/03/14 00:19:36 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.485 2005/03/29 17:58:50 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -114,6 +114,8 @@ static void doNegateFloat(Value *v); TypeName *typnam; FunctionParameter *fun_param; + FunctionParameterMode fun_param_mode; + FuncWithArgs *funwithargs; DefElem *defelt; SortBy *sortby; JoinExpr *jexpr; @@ -206,7 +208,7 @@ static void doNegateFloat(Value *v); %type privilege %type privileges privilege_list %type privilege_target -%type function_with_argtypes +%type function_with_argtypes %type function_with_argtypes_list %type TriggerOneEvent @@ -233,9 +235,10 @@ static void doNegateFloat(Value *v); %type createfunc_opt_item common_func_opt_item %type func_arg +%type arg_class %type func_return func_type aggr_argtype -%type arg_class TriggerForType OptTemp +%type TriggerForType OptTemp %type OnCommitOption %type OptWithOids WithOidsAs @@ -3177,7 +3180,7 @@ function_with_argtypes: FuncWithArgs *n = makeNode(FuncWithArgs); n->funcname = $1; n->funcargs = extractArgTypes($2); - $$ = (Node *)n; + $$ = n; } ; @@ -3295,7 +3298,13 @@ func_args_list: | func_args_list ',' func_arg { $$ = lappend($1, $3); } ; -/* We can catch over-specified arguments here if we want to, +/* + * The style with arg_class first is SQL99 standard, but Oracle puts + * param_name first; accept both since it's likely people will try both + * anyway. Don't bother trying to save productions by letting arg_class + * have an empty alternative ... you'll get shift/reduce conflicts. + * + * We can catch over-specified arguments here if we want to, * but for now better to silently swallow typmod, etc. * - thomas 2000-03-22 */ @@ -3305,6 +3314,23 @@ func_arg: FunctionParameter *n = makeNode(FunctionParameter); n->name = $2; n->argType = $3; + n->mode = $1; + $$ = n; + } + | param_name arg_class func_type + { + FunctionParameter *n = makeNode(FunctionParameter); + n->name = $1; + n->argType = $3; + n->mode = $2; + $$ = n; + } + | param_name func_type + { + FunctionParameter *n = makeNode(FunctionParameter); + n->name = $1; + n->argType = $2; + n->mode = FUNC_PARAM_IN; $$ = n; } | arg_class func_type @@ -3312,26 +3338,24 @@ func_arg: FunctionParameter *n = makeNode(FunctionParameter); n->name = NULL; n->argType = $2; + n->mode = $1; + $$ = n; + } + | func_type + { + FunctionParameter *n = makeNode(FunctionParameter); + n->name = NULL; + n->argType = $1; + n->mode = FUNC_PARAM_IN; $$ = n; } ; -arg_class: IN_P { $$ = FALSE; } - | OUT_P - { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("CREATE FUNCTION / OUT parameters are not implemented"))); - $$ = TRUE; - } - | INOUT - { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("CREATE FUNCTION / INOUT parameters are not implemented"))); - $$ = FALSE; - } - | /*EMPTY*/ { $$ = FALSE; } +/* INOUT is SQL99 standard, IN OUT is for Oracle compatibility */ +arg_class: IN_P { $$ = FUNC_PARAM_IN; } + | OUT_P { $$ = FUNC_PARAM_OUT; } + | INOUT { $$ = FUNC_PARAM_INOUT; } + | IN_P OUT_P { $$ = FUNC_PARAM_INOUT; } ; /* @@ -3458,7 +3482,7 @@ AlterFunctionStmt: ALTER FUNCTION function_with_argtypes alterfunc_opt_list opt_restrict { AlterFunctionStmt *n = makeNode(AlterFunctionStmt); - n->func = (FuncWithArgs *) $3; + n->func = $3; n->actions = $4; $$ = (Node *) n; } @@ -3561,7 +3585,7 @@ CreateCastStmt: CREATE CAST '(' Typename AS Typename ')' CreateCastStmt *n = makeNode(CreateCastStmt); n->sourcetype = $4; n->targettype = $6; - n->func = (FuncWithArgs *) $10; + n->func = $10; n->context = (CoercionContext) $11; $$ = (Node *)n; } @@ -8299,9 +8323,9 @@ check_func_name(List *names) /* extractArgTypes() * Given a list of FunctionParameter nodes, extract a list of just the - * argument types (TypeNames). Most of the productions using func_args - * don't currently want the full FunctionParameter data, so we use this - * rather than having two sets of productions. + * argument types (TypeNames) for input parameters only. This is what + * is needed to look up an existing function, which is what is wanted by + * the productions that use this call. */ static List * extractArgTypes(List *parameters) @@ -8313,7 +8337,8 @@ extractArgTypes(List *parameters) { FunctionParameter *p = (FunctionParameter *) lfirst(i); - result = lappend(result, p->argType); + if (p->mode != FUNC_PARAM_OUT) /* keep if IN or INOUT */ + result = lappend(result, p->argType); } return result; } diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 8cf274b14ce..a6a79e3a4fa 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.274 2005/03/14 00:19:37 neilc Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.275 2005/03/29 17:58:51 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -899,6 +899,11 @@ typedef struct PrivGrantee char *groupname; } PrivGrantee; +/* + * Note: FuncWithArgs carries only the types of the input parameters of the + * function. So it is sufficient to identify an existing function, but it + * is not enough info to define a function nor to call it. + */ typedef struct FuncWithArgs { NodeTag type; @@ -1389,12 +1394,20 @@ typedef struct CreateFunctionStmt List *withClause; /* a list of DefElem */ } CreateFunctionStmt; +typedef enum FunctionParameterMode +{ + /* the assigned enum values appear in pg_proc, don't change 'em! */ + FUNC_PARAM_IN = 'i', /* input only */ + FUNC_PARAM_OUT = 'o', /* output only */ + FUNC_PARAM_INOUT = 'b' /* both */ +} FunctionParameterMode; + typedef struct FunctionParameter { NodeTag type; char *name; /* parameter name, or NULL if not given */ TypeName *argType; /* TypeName for parameter type */ - /* someday add IN/OUT/INOUT indicator here */ + FunctionParameterMode mode; /* IN/OUT/INOUT */ } FunctionParameter; typedef struct AlterFunctionStmt