summaryrefslogtreecommitdiff
path: root/src/backend/parser/gram.y
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/gram.y')
-rw-r--r--src/backend/parser/gram.y89
1 files changed, 85 insertions, 4 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 70bbe940af..39e52099f4 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.617 2008/07/16 01:30:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.618 2008/07/18 03:32:52 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -112,6 +112,8 @@ static Node *doNegate(Node *n, int location);
static void doNegateFloat(Value *v);
static Node *makeAArrayExpr(List *elements);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args);
+static List *mergeTableFuncParameters(List *func_args, List *columns);
+static TypeName *TableFuncTypeName(List *columns);
%}
@@ -253,13 +255,13 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
TableFuncElementList opt_type_modifiers
prep_type_clause
execute_param_clause using_clause returning_clause
- enum_val_list
+ enum_val_list table_func_column_list
%type <range> OptTempTableName
%type <into> into_clause create_as_target
%type <defelt> createfunc_opt_item common_func_opt_item
-%type <fun_param> func_arg
+%type <fun_param> func_arg table_func_column
%type <fun_param_mode> arg_class
%type <typnam> func_return func_type
@@ -4119,6 +4121,19 @@ CreateFunctionStmt:
$$ = (Node *)n;
}
| CREATE opt_or_replace FUNCTION func_name func_args
+ RETURNS TABLE '(' table_func_column_list ')' createfunc_opt_list opt_definition
+ {
+ CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
+ n->replace = $2;
+ n->funcname = $4;
+ n->parameters = mergeTableFuncParameters($5, $9);
+ n->returnType = TableFuncTypeName($9);
+ n->returnType->location = @7;
+ n->options = $11;
+ n->withClause = $12;
+ $$ = (Node *)n;
+ }
+ | CREATE opt_or_replace FUNCTION func_name func_args
createfunc_opt_list opt_definition
{
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
@@ -4338,6 +4353,27 @@ opt_definition:
| /*EMPTY*/ { $$ = NIL; }
;
+table_func_column: param_name func_type
+ {
+ FunctionParameter *n = makeNode(FunctionParameter);
+ n->name = $1;
+ n->argType = $2;
+ n->mode = FUNC_PARAM_TABLE;
+ $$ = n;
+ }
+ ;
+
+table_func_column_list:
+ table_func_column
+ {
+ $$ = list_make1($1);
+ }
+ | table_func_column_list ',' table_func_column
+ {
+ $$ = lappend($1, $3);
+ }
+ ;
+
/*****************************************************************************
* ALTER FUNCTION
*
@@ -9678,7 +9714,7 @@ extractArgTypes(List *parameters)
{
FunctionParameter *p = (FunctionParameter *) lfirst(i);
- if (p->mode != FUNC_PARAM_OUT) /* keep if IN, INOUT, VARIADIC */
+ if (p->mode != FUNC_PARAM_OUT && p->mode != FUNC_PARAM_TABLE)
result = lappend(result, p->argType);
}
return result;
@@ -9862,6 +9898,51 @@ parser_init(void)
}
/*
+ * Merge the input and output parameters of a table function.
+ */
+static List *
+mergeTableFuncParameters(List *func_args, List *columns)
+{
+ ListCell *lc;
+
+ /* Explicit OUT and INOUT parameters shouldn't be used in this syntax */
+ foreach(lc, func_args)
+ {
+ FunctionParameter *p = (FunctionParameter *) lfirst(lc);
+
+ if (p->mode != FUNC_PARAM_IN && p->mode != FUNC_PARAM_VARIADIC)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("OUT and INOUT arguments aren't allowed in TABLE functions")));
+ }
+
+ return list_concat(func_args, columns);
+}
+
+/*
+ * Determine return type of a TABLE function. A single result column
+ * returns setof that column's type; otherwise return setof record.
+ */
+static TypeName *
+TableFuncTypeName(List *columns)
+{
+ TypeName *result;
+
+ if (list_length(columns) == 1)
+ {
+ FunctionParameter *p = (FunctionParameter *) linitial(columns);
+
+ result = (TypeName *) copyObject(p->argType);
+ }
+ else
+ result = SystemTypeName("record");
+
+ result->setof = true;
+
+ return result;
+}
+
+/*
* Must undefine base_yylex before including scan.c, since we want it
* to create the function base_yylex not filtered_base_yylex.
*/