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 639647eab3ca2cf4853e0ff7dbc6d048d93d9cf3..ca9eca5138d98b06972fa6a27d3b2ea88138263c 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.83 2008/12/18 18:20:33 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.84 2008/12/31 02:25:03 tgl Exp $
 -->
 
 <refentry id="SQL-CREATEFUNCTION">
@@ -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 414366bc54ec021d32c5c16f0bd46eaea63af22a..8aad4a0ea44c5772c7269ae75a783fef3469d593 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.99 2008/12/18 18:20:33 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.100 2008/12/31 02:25:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 8ff22c23c9ec2593c99bbf156e7c85409a231f84..d11a067a5d92fd9c846c2cf163ae53e7f1aa0c41 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.158 2008/12/28 18:53:54 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.159 2008/12/31 02:25:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 8963f98117813a73b9d38c1cf518bf3bec358d7b..13f1debf6692b28eea7051ea86d3b429f36563f7 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.104 2008/12/28 18:53:55 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.105 2008/12/31 02:25:03 tgl Exp $
  *
  * DESCRIPTION
  *       These routines take the parse tree and pick out the
@@ -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 3188156c4d143a6224edf855138c6d545b62b516..ea37352b4192452d2dbdb19313816e67c025e92b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.82 2008/12/18 18:20:33 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.83 2008/12/31 02:25:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 34dc40a1056dacc198741b912ba84be414cb7789..011041f303770bc1fb4d5c75def0ae52d0fde665 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.649 2008/12/31 00:08:36 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.650 2008/12/31 02:25:04 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -4801,6 +4801,10 @@ createfunc_opt_item:
                                {
                                        $$ = makeDefElem("language", (Node *)makeString($2));
                                }
+                       | WINDOW
+                               {
+                                       $$ = makeDefElem("window", (Node *)makeInteger(TRUE));
+                               }
                        | common_func_opt_item
                                {
                                        $$ = $1;
index 4a44b733cf35d288c8fb7b401c2ef11d38e3b775..f48ee4ae96d5a0ab3be8f01bef92816547a36a72 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.292 2008/12/31 00:08:37 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.293 2008/12/31 02:25:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 ae7233dbf83316f179964715bc2f99a31688c219..b8f6932ded0fb5775ff82711f788436f67e2cfc0 100644 (file)
@@ -12,7 +12,7 @@
  *     by PostgreSQL
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.509 2008/12/19 16:25:18 petere Exp $
+ *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.510 2008/12/31 02:25:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 cab31d45e151bead9f5c14fdade1c18f551da1ec..5941b546fcf6f393a496d3a0372ef02929316d0d 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc_fn.h,v 1.4 2008/12/18 18:20:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc_fn.h,v 1.5 2008/12/31 02:25:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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,