Fix psql's \ev and \sv commands so that they handle view reloptions.
authorDean Rasheed <[email protected]>
Fri, 6 May 2016 11:48:27 +0000 (12:48 +0100)
committerDean Rasheed <[email protected]>
Fri, 6 May 2016 11:48:27 +0000 (12:48 +0100)
Commit 8eb6407aaeb6cbd972839e356b436bb698f51cff added support for
editing and showing view definitions, but neglected to account for
view options such as security_barrier and WITH CHECK OPTION which are
not returned by pg_get_viewdef() and so need special handling.

Author: Dean Rasheed
Reviewed-by: Peter Eisentraut
Discussion: http://www.postgresql.org/message-id/CAEZATCWZjCgKRyM-agE0p8ax15j9uyQoF=qew7D2xB6cF76T8A@mail.gmail.com

src/bin/psql/command.c

index 4fa7760a2a94af2d78fecea6324309a985fdfcc2..87adfce9c114e136cca7fcccbf360fa694972847 100644 (file)
@@ -3274,12 +3274,51 @@ get_create_object_cmd(EditableObjectType obj_type, Oid oid,
             * CREATE for ourselves.  We must fully qualify the view name to
             * ensure the right view gets replaced.  Also, check relation kind
             * to be sure it's a view.
+            *
+            * Starting with 9.2, views may have reloptions (security_barrier)
+            * and from 9.4 onwards they may also have WITH [LOCAL|CASCADED]
+            * CHECK OPTION.  These are not part of the view definition
+            * returned by pg_get_viewdef() and so need to be retrieved
+            * separately.  Materialized views (introduced in 9.3) may have
+            * arbitrary storage parameter reloptions.
             */
-           printfPQExpBuffer(query,
-                             "SELECT nspname, relname, relkind, pg_catalog.pg_get_viewdef(c.oid, true) FROM "
-                "pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n "
-                             "ON c.relnamespace = n.oid WHERE c.oid = %u",
-                             oid);
+           if (pset.sversion >= 90400)
+           {
+               printfPQExpBuffer(query,
+                                 "SELECT nspname, relname, relkind, "
+                                 "pg_catalog.pg_get_viewdef(c.oid, true), "
+                                 "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
+                                 "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
+                                 "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption "
+                                 "FROM pg_catalog.pg_class c "
+                                 "LEFT JOIN pg_catalog.pg_namespace n "
+                               "ON c.relnamespace = n.oid WHERE c.oid = %u",
+                                 oid);
+           }
+           else if (pset.sversion >= 90200)
+           {
+               printfPQExpBuffer(query,
+                                 "SELECT nspname, relname, relkind, "
+                                 "pg_catalog.pg_get_viewdef(c.oid, true), "
+                                 "c.reloptions AS reloptions, "
+                                 "NULL AS checkoption "
+                                 "FROM pg_catalog.pg_class c "
+                                 "LEFT JOIN pg_catalog.pg_namespace n "
+                               "ON c.relnamespace = n.oid WHERE c.oid = %u",
+                                 oid);
+           }
+           else
+           {
+               printfPQExpBuffer(query,
+                                 "SELECT nspname, relname, relkind, "
+                                 "pg_catalog.pg_get_viewdef(c.oid, true), "
+                                 "NULL AS reloptions, "
+                                 "NULL AS checkoption "
+                                 "FROM pg_catalog.pg_class c "
+                                 "LEFT JOIN pg_catalog.pg_namespace n "
+                               "ON c.relnamespace = n.oid WHERE c.oid = %u",
+                                 oid);
+           }
            break;
    }
 
@@ -3304,6 +3343,8 @@ get_create_object_cmd(EditableObjectType obj_type, Oid oid,
                    char       *relname = PQgetvalue(res, 0, 1);
                    char       *relkind = PQgetvalue(res, 0, 2);
                    char       *viewdef = PQgetvalue(res, 0, 3);
+                   char       *reloptions = PQgetvalue(res, 0, 4);
+                   char       *checkoption = PQgetvalue(res, 0, 5);
 
                    /*
                     * If the backend ever supports CREATE OR REPLACE
@@ -3328,11 +3369,33 @@ get_create_object_cmd(EditableObjectType obj_type, Oid oid,
                            break;
                    }
                    appendPQExpBuffer(buf, "%s.", fmtId(nspname));
-                   appendPQExpBuffer(buf, "%s AS\n", fmtId(relname));
-                   appendPQExpBufferStr(buf, viewdef);
+                   appendPQExpBufferStr(buf, fmtId(relname));
+
+                   /* reloptions, if not an empty array "{}" */
+                   if (reloptions != NULL && strlen(reloptions) > 2)
+                   {
+                       appendPQExpBufferStr(buf, "\n WITH (");
+                       if (!appendReloptionsArray(buf, reloptions, "",
+                                                  pset.encoding,
+                                                  standard_strings()))
+                       {
+                           psql_error("Could not parse reloptions array\n");
+                           result = false;
+                       }
+                       appendPQExpBufferStr(buf, ")");
+                   }
+
+                   /* View definition from pg_get_viewdef (a SELECT query) */
+                   appendPQExpBuffer(buf, " AS\n%s", viewdef);
+
                    /* Get rid of the semicolon that pg_get_viewdef appends */
                    if (buf->len > 0 && buf->data[buf->len - 1] == ';')
                        buf->data[--(buf->len)] = '\0';
+
+                   /* WITH [LOCAL|CASCADED] CHECK OPTION */
+                   if (checkoption && checkoption[0] != '\0')
+                       appendPQExpBuffer(buf, "\n WITH %s CHECK OPTION",
+                                         checkoption);
                }
                break;
        }