Add a WINDOW attribute to CREATE FUNCTION, and teach pg_dump about it,
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 31 Dec 2008 02:25:06 +0000 (02:25 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 31 Dec 2008 02:25:06 +0000 (02:25 +0000)
so that user-defined window functions are possible.  For the moment you'll
have to write them in C, for lack of any interface to the WindowObject API
in the available PLs, but it's better than no support at all.

There was some debate about the best syntax for this.  I ended up choosing
the "it's an attribute" position --- the other approach will inevitably be
more work, and the likely market for user-defined window functions is
probably too small to justify it.

doc/src/sgml/ref/create_function.sgml
src/backend/catalog/pg_aggregate.c
src/backend/catalog/pg_proc.c
src/backend/commands/functioncmds.c
src/backend/commands/proclang.c
src/backend/parser/gram.y
src/backend/utils/adt/ruleutils.c
src/bin/pg_dump/pg_dump.c
src/include/catalog/pg_proc_fn.h

index 6c3a9ebc7e590ae477bed9cae70234e66e68da2a..70baae396e1d83c617f02a2e95c6d44ca59e6efe 100644 (file)
@@ -25,6 +25,7 @@ CREATE [ OR REPLACE ] FUNCTION
     [ RETURNS <replaceable class="parameter">rettype</replaceable>
       | RETURNS TABLE ( <replaceable class="parameter">colname</replaceable> <replaceable class="parameter">coltype</replaceable> [, ...] ) ]
   { LANGUAGE <replaceable class="parameter">langname</replaceable>
+    | WINDOW
     | IMMUTABLE | STABLE | VOLATILE
     | CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
     | [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
@@ -241,6 +242,20 @@ CREATE [ OR REPLACE ] FUNCTION
      </listitem>
     </varlistentry>
 
+    <varlistentry>
+     <term><literal>WINDOW</literal></term>
+
+     <listitem>
+      <para>
+       <literal>WINDOW</literal> indicates that the function is a
+       <firstterm>window function</> rather than a plain function.
+       This is currently only useful for functions written in C.
+       The <literal>WINDOW</> attribute cannot be changed when
+       replacing an existing function definition.
+      </para>
+     </listitem>
+    </varlistentry>
+
     <varlistentry>
      <term><literal>IMMUTABLE</literal></term>
      <term><literal>STABLE</literal></term>
index d2bcaa344df7bc41ace11ccdb5b41b1789d79db5..140554481d804f417af1b19ed39410f743ab9175 100644 (file)
@@ -217,6 +217,7 @@ AggregateCreate(const char *aggName,
                                                          "aggregate_dummy",            /* placeholder proc */
                                                          NULL,         /* probin */
                                                          true,         /* isAgg */
+                                                         false,        /* isWindowFunc */
                                                          false,        /* security invoker (currently not
                                                                                 * definable for agg) */
                                                          false,        /* isStrict (not needed for agg) */
index 310bcc6b4d43f097ba2f766e23e6ac81b0eadade..aae510f5b020401d32fad3c0794621e766a38842 100644 (file)
@@ -53,7 +53,7 @@ static bool match_prosrc_to_literal(const char *prosrc, const char *literal,
  *
  * Note: allParameterTypes, parameterModes, parameterNames, and proconfig
  * are either arrays of the proper types or NULL.  We declare them Datum,
- * not "ArrayType *", to avoid importing array.h into pg_proc.h.
+ * not "ArrayType *", to avoid importing array.h into pg_proc_fn.h.
  * ----------------------------------------------------------------
  */
 Oid
@@ -67,6 +67,7 @@ ProcedureCreate(const char *procedureName,
                                const char *prosrc,
                                const char *probin,
                                bool isAgg,
+                               bool isWindowFunc,
                                bool security_definer,
                                bool isStrict,
                                char volatility,
@@ -80,8 +81,6 @@ ProcedureCreate(const char *procedureName,
                                float4 prorows)
 {
        Oid                     retval;
-       /* XXX we don't currently have a way to make new window functions */
-       bool            isWindowFunc = false;
        int                     parameterCount;
        int                     allParamCount;
        Oid                *allParams;
index 399544f1ff6fffdec6da6c3053d18d001e082af9..7b694c78494a27b2fcc79f501a7ca609965aa5c3 100644 (file)
@@ -503,6 +503,7 @@ static void
 compute_attributes_sql_style(List *options,
                                                         List **as,
                                                         char **language,
+                                                        bool *windowfunc_p,
                                                         char *volatility_p,
                                                         bool *strict_p,
                                                         bool *security_definer,
@@ -513,6 +514,7 @@ compute_attributes_sql_style(List *options,
        ListCell   *option;
        DefElem    *as_item = NULL;
        DefElem    *language_item = NULL;
+       DefElem    *windowfunc_item = NULL;
        DefElem    *volatility_item = NULL;
        DefElem    *strict_item = NULL;
        DefElem    *security_item = NULL;
@@ -540,6 +542,14 @@ compute_attributes_sql_style(List *options,
                                                 errmsg("conflicting or redundant options")));
                        language_item = defel;
                }
+               else if (strcmp(defel->defname, "window") == 0)
+               {
+                       if (windowfunc_item)
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_SYNTAX_ERROR),
+                                                errmsg("conflicting or redundant options")));
+                       windowfunc_item = defel;
+               }
                else if (compute_common_attribute(defel,
                                                                                  &volatility_item,
                                                                                  &strict_item,
@@ -578,6 +588,8 @@ compute_attributes_sql_style(List *options,
        }
 
        /* process optional items */
+       if (windowfunc_item)
+               *windowfunc_p = intVal(windowfunc_item->arg);
        if (volatility_item)
                *volatility_p = interpret_func_volatility(volatility_item);
        if (strict_item)
@@ -735,7 +747,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
        ArrayType  *parameterNames;
        List       *parameterDefaults;
        Oid                     requiredResultType;
-       bool            isStrict,
+       bool            isWindowFunc,
+                               isStrict,
                                security;
        char            volatility;
        ArrayType  *proconfig;
@@ -756,6 +769,7 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
                                           get_namespace_name(namespaceId));
 
        /* default attributes */
+       isWindowFunc = false;
        isStrict = false;
        security = false;
        volatility = PROVOLATILE_VOLATILE;
@@ -766,7 +780,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
        /* override attributes from explicit list */
        compute_attributes_sql_style(stmt->options,
                                                                 &as_clause, &language,
-                                                                &volatility, &isStrict, &security,
+                                                                &isWindowFunc, &volatility,
+                                                                &isStrict, &security,
                                                                 &proconfig, &procost, &prorows);
 
        /* Convert language name to canonical case */
@@ -892,6 +907,7 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
                                        prosrc_str, /* converted to text later */
                                        probin_str, /* converted to text later */
                                        false,          /* not an aggregate */
+                                       isWindowFunc,
                                        security,
                                        isStrict,
                                        volatility,
index 64c0d45d25362242d4b421ed0dc5a5c321c261b1..6b664392af45c21f06ad967d74098f2283be7517 100644 (file)
@@ -140,6 +140,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
                                                                                 pltemplate->tmplhandler,
                                                                                 pltemplate->tmpllibrary,
                                                                                 false, /* isAgg */
+                                                                                false, /* isWindowFunc */
                                                                                 false, /* security_definer */
                                                                                 false, /* isStrict */
                                                                                 PROVOLATILE_VOLATILE,
@@ -174,6 +175,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
                                                                                 pltemplate->tmplvalidator,
                                                                                 pltemplate->tmpllibrary,
                                                                                 false, /* isAgg */
+                                                                                false, /* isWindowFunc */
                                                                                 false, /* security_definer */
                                                                                 false, /* isStrict */
                                                                                 PROVOLATILE_VOLATILE,
index 3d8db2e76ba9e98a22ad98de6d0fd3af72e6dad8..ae59261d98608f42bbdeb9a5a021c79f45005b80 100644 (file)
@@ -4801,6 +4801,10 @@ createfunc_opt_item:
                                {
                                        $$ = makeDefElem("language", (Node *)makeString($2));
                                }
+                       | WINDOW
+                               {
+                                       $$ = makeDefElem("window", (Node *)makeInteger(TRUE));
+                               }
                        | common_func_opt_item
                                {
                                        $$ = $1;
index f53d9e63ff4271e18a6071f29e52ccfaa28a4f49..096b0151edbfeae90ef70d5c52891658bbd92f4e 100644 (file)
@@ -1466,6 +1466,8 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
        /* Emit some miscellaneous options on one line */
        oldlen = buf.len;
 
+       if (proc->proiswindow)
+               appendStringInfoString(&buf, " WINDOW");
        switch (proc->provolatile)
        {
                case PROVOLATILE_IMMUTABLE:
index b93eb85bd83b918bc2e1c7967b2a6054d863438f..29b13cf3a973ecf7da54b0195c1ef4dc103ca28f 100644 (file)
@@ -6916,6 +6916,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
        char       *proallargtypes;
        char       *proargmodes;
        char       *proargnames;
+       char       *proiswindow;
        char       *provolatile;
        char       *proisstrict;
        char       *prosecdef;
@@ -6956,7 +6957,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "pg_catalog.pg_get_function_arguments(oid) as funcargs, "
                                                  "pg_catalog.pg_get_function_identity_arguments(oid) as funciargs, "
                                                  "pg_catalog.pg_get_function_result(oid) as funcresult, "
-                                                 "provolatile, proisstrict, prosecdef, "
+                                                 "proiswindow, provolatile, proisstrict, prosecdef, "
                                                  "proconfig, procost, prorows, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
                                                  "FROM pg_catalog.pg_proc "
@@ -6968,6 +6969,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                appendPQExpBuffer(query,
                                                  "SELECT proretset, prosrc, probin, "
                                                  "proallargtypes, proargmodes, proargnames, "
+                                                 "false as proiswindow, "
                                                  "provolatile, proisstrict, prosecdef, "
                                                  "proconfig, procost, prorows, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
@@ -6980,6 +6982,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                appendPQExpBuffer(query,
                                                  "SELECT proretset, prosrc, probin, "
                                                  "proallargtypes, proargmodes, proargnames, "
+                                                 "false as proiswindow, "
                                                  "provolatile, proisstrict, prosecdef, "
                                                  "null as proconfig, 0 as procost, 0 as prorows, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
@@ -6994,6 +6997,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "null as proallargtypes, "
                                                  "null as proargmodes, "
                                                  "proargnames, "
+                                                 "false as proiswindow, "
                                                  "provolatile, proisstrict, prosecdef, "
                                                  "null as proconfig, 0 as procost, 0 as prorows, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
@@ -7008,6 +7012,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "null as proallargtypes, "
                                                  "null as proargmodes, "
                                                  "null as proargnames, "
+                                                 "false as proiswindow, "
                                                  "provolatile, proisstrict, prosecdef, "
                                                  "null as proconfig, 0 as procost, 0 as prorows, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
@@ -7022,9 +7027,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "null as proallargtypes, "
                                                  "null as proargmodes, "
                                                  "null as proargnames, "
+                                                 "false as proiswindow, "
                         "case when proiscachable then 'i' else 'v' end as provolatile, "
                                                  "proisstrict, "
-                                                 "'f'::boolean as prosecdef, "
+                                                 "false as prosecdef, "
                                                  "null as proconfig, 0 as procost, 0 as prorows, "
                  "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
                                                  "FROM pg_proc "
@@ -7038,9 +7044,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "null as proallargtypes, "
                                                  "null as proargmodes, "
                                                  "null as proargnames, "
+                                                 "false as proiswindow, "
                         "case when proiscachable then 'i' else 'v' end as provolatile, "
-                                                 "'f'::boolean as proisstrict, "
-                                                 "'f'::boolean as prosecdef, "
+                                                 "false as proisstrict, "
+                                                 "false as prosecdef, "
                                                  "null as proconfig, 0 as procost, 0 as prorows, "
                  "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
                                                  "FROM pg_proc "
@@ -7077,6 +7084,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
                funcargs = funciargs = funcresult = NULL;
        }
+       proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
        provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
        proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
        prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
@@ -7217,6 +7225,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
        }
 
        appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
+
+       if (proiswindow[0] == 't')
+               appendPQExpBuffer(q, " WINDOW");
+
        if (provolatile[0] != PROVOLATILE_VOLATILE)
        {
                if (provolatile[0] == PROVOLATILE_IMMUTABLE)
index 7a8903893126b46b329b775ba813f8a98d05e161..771b5c5e49d0d67657100d8762470b4f0f03b3cc 100644 (file)
@@ -26,6 +26,7 @@ extern Oid ProcedureCreate(const char *procedureName,
                                const char *prosrc,
                                const char *probin,
                                bool isAgg,
+                               bool isWindowFunc,
                                bool security_definer,
                                bool isStrict,
                                char volatility,