]> granicus.if.org Git - postgresql/commitdiff
Add pretty-printing variants of pg_get_viewdef and related functions.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 30 Jul 2003 22:56:24 +0000 (22:56 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 30 Jul 2003 22:56:24 +0000 (22:56 +0000)
Patch from Andreas Pflug.

doc/src/sgml/func.sgml
src/backend/utils/adt/ruleutils.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h

index d5a528e1c381a6a469abfbaab3e61b9bb345c6ab..dc06faacbb440e94d88af00c8c756f1acf041bce 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.161 2003/07/29 00:03:17 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.162 2003/07/30 22:56:23 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -6494,10 +6494,9 @@ SET search_path TO <replaceable>schema</> <optional>, <replaceable>schema</>, ..
 
    <para>
     The function <function>current_setting</function> yields the
-    current value of the setting <parameter>setting_name</parameter>,
-    as part of a query result. It corresponds to the
-    <acronym>SQL</acronym> command <command>SHOW</command>.  An
-    example:
+    current value of the setting <parameter>setting_name</parameter>.
+    It corresponds to the <acronym>SQL</acronym> command
+    <command>SHOW</command>.  An example:
 <programlisting>
 SELECT current_setting('datestyle');
 
@@ -6832,6 +6831,10 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
     <primary>pg_get_constraintdef</primary>
    </indexterm>
 
+   <indexterm zone="functions-misc">
+    <primary>pg_get_expr</primary>
+   </indexterm>
+
    <indexterm zone="functions-misc">
     <primary>pg_get_userbyid</primary>
    </indexterm>
@@ -6846,7 +6849,16 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
    <function>pg_get_constraintdef</function> respectively
    reconstruct the creating command for a view, rule, index, or
    constraint.  (Note that this is a decompiled reconstruction, not
-   the verbatim text of the command.)
+   the original text of the command.)  Most of these come in two
+   variants, one of which can optionally <quote>pretty-print</> the result.
+   The pretty-printed form is more readable but is less likely to be
+   interpreted the same way by future versions of <productname>PostgreSQL</>;
+   avoid using pretty-printed output for dump purposes.
+   Passing <literal>false</> for the pretty-print parameter yields the
+   same result as the variant that does not have the parameter at all.
+   <function>pg_get_expr</function> decompiles the internal form of an
+   individual expression, such as the default value for a column.  It
+   may be useful when examining the contents of system catalogs.
    <function>pg_get_userbyid</function>
    extracts a user's name given a user ID number.
   </para>
@@ -6864,21 +6876,43 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
        <entry><type>text</type></entry>
        <entry>get <command>CREATE VIEW</> command for view (<emphasis>deprecated</emphasis>)</entry>
       </row>
+      <row>
+       <entry><literal><function>pg_get_viewdef</function>(<parameter>view_name</parameter>, <parameter>pretty_bool</>)</literal></entry>
+       <entry><type>text</type></entry>
+       <entry>get <command>CREATE VIEW</> command for view (<emphasis>deprecated</emphasis>)</entry>
+      </row>
       <row>
        <entry><literal><function>pg_get_viewdef</function>(<parameter>view_oid</parameter>)</literal></entry>
        <entry><type>text</type></entry>
        <entry>get <command>CREATE VIEW</> command for view</entry>
       </row>
+      <row>
+       <entry><literal><function>pg_get_viewdef</function>(<parameter>view_oid</parameter>, <parameter>pretty_bool</>)</literal></entry>
+       <entry><type>text</type></entry>
+       <entry>get <command>CREATE VIEW</> command for view</entry>
+      </row>
       <row>
        <entry><literal><function>pg_get_ruledef</function>(<parameter>rule_oid</parameter>)</literal></entry>
        <entry><type>text</type></entry>
        <entry>get <command>CREATE RULE</> command for rule</entry>
       </row>
+      <row>
+       <entry><literal><function>pg_get_ruledef</function>(<parameter>rule_oid</parameter>, <parameter>pretty_bool</>)</literal></entry>
+       <entry><type>text</type></entry>
+       <entry>get <command>CREATE RULE</> command for rule</entry>
+      </row>
       <row>
        <entry><literal><function>pg_get_indexdef</function>(<parameter>index_oid</parameter>)</literal></entry>
        <entry><type>text</type></entry>
        <entry>get <command>CREATE INDEX</> command for index</entry>
       </row>
+      <row>
+       <entry><literal><function>pg_get_indexdef</function>(<parameter>index_oid</parameter>, <parameter>column_no</>, <parameter>pretty_bool</>)</literal></entry>
+       <entry><type>text</type></entry>
+       <entry>get <command>CREATE INDEX</> command for index,
+       or definition of just one index column when
+       <parameter>column_no</> is not zero</entry>
+      </row>
       <row>
        <entry><function>pg_get_triggerdef</function>(<parameter>trigger_oid</parameter>)</entry>
        <entry><type>text</type></entry>
@@ -6889,6 +6923,23 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
        <entry><type>text</type></entry>
        <entry>get definition of a constraint</entry>
       </row>
+      <row>
+       <entry><literal><function>pg_get_constraintdef</function>(<parameter>constraint_oid</parameter>, <parameter>pretty_bool</>)</literal></entry>
+       <entry><type>text</type></entry>
+       <entry>get definition of a constraint</entry>
+      </row>
+      <row>
+       <entry><literal><function>pg_get_expr</function>(<parameter>expr_text</parameter>, <parameter>relation_oid</>)</literal></entry>
+       <entry><type>text</type></entry>
+       <entry>decompile internal form of an expression, assuming that any Vars
+       in it refer to the relation indicated by the second parameter</entry>
+      </row>
+      <row>
+       <entry><literal><function>pg_get_expr</function>(<parameter>expr_text</parameter>, <parameter>relation_oid</>, <parameter>pretty_bool</>)</literal></entry>
+       <entry><type>text</type></entry>
+       <entry>decompile internal form of an expression, assuming that any Vars
+       in it refer to the relation indicated by the second parameter</entry>
+      </row>
       <row>
        <entry><literal><function>pg_get_userbyid</function>(<parameter>userid</parameter>)</literal></entry>
        <entry><type>name</type></entry>
index 8f896084954af143173578233df52b9477ab48e4..1213fae86f770806fa5b286d4e698f0fa1f803d2 100644 (file)
@@ -3,7 +3,7 @@
  *                             back to source text
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.146 2003/07/27 04:53:09 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.147 2003/07/30 22:56:23 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
 #include "utils/lsyscache.h"
 
 
+/* ----------
+ * Pretty formatting constants
+ * ----------
+ */
+
+/* Indent counts */
+#define PRETTYINDENT_STD        8
+#define PRETTYINDENT_JOIN      13
+#define PRETTYINDENT_JOIN_ON    (PRETTYINDENT_JOIN-PRETTYINDENT_STD)
+#define PRETTYINDENT_VAR        4
+
+/* Pretty flags */
+#define PRETTYFLAG_PAREN        1
+#define PRETTYFLAG_INDENT       2
+
+/* macro to test if pretty action needed */
+#define PRETTY_PAREN(context)   ((context)->prettyFlags & PRETTYFLAG_PAREN)
+#define PRETTY_INDENT(context)  ((context)->prettyFlags & PRETTYFLAG_INDENT)
+
+
 /* ----------
  * Local data types
  * ----------
@@ -81,6 +101,8 @@ typedef struct
 {
        StringInfo      buf;                    /* output buffer to append to */
        List       *namespaces;         /* List of deparse_namespace nodes */
+       int                     prettyFlags;    /* enabling of pretty-print functions */
+       int                     indentLevel;    /* current indent level for prettyprint */
        bool            varprefix;              /* TRUE to print prefixes on Vars */
 } deparse_context;
 
@@ -123,13 +145,24 @@ static char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_c
  * as a parameter, and append their text output to its contents.
  * ----------
  */
-static text *pg_do_getviewdef(Oid viewoid);
+static char *deparse_expression_pretty(Node *expr, List *dpcontext,
+                                                                          bool forceprefix, bool showimplicit,
+                                                                          int prettyFlags, int startIndent);
+static text *pg_do_getviewdef(Oid viewoid, int prettyFlags);
 static void decompile_column_index_array(Datum column_index_array, Oid relId,
                                                         StringInfo buf);
-static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
-static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
+static Datum pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
+static Datum pg_get_indexdef_worker(Oid indexrelid, int colno,
+                                                                       int prettyFlags);
+static Datum pg_get_constraintdef_worker(Oid constraintId, int prettyFlags);
+static Datum pg_get_expr_worker(text *expr, Oid relid, char *relname,
+                                                               int prettyFlags);
+static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
+                                                int prettyFlags);
+static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
+                                                int prettyFlags);
 static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
-                         TupleDesc resultDesc);
+                         TupleDesc resultDesc, int prettyFlags, int startIndent);
 static void get_select_query_def(Query *query, deparse_context *context,
                                         TupleDesc resultDesc);
 static void get_insert_query_def(Query *query, deparse_context *context);
@@ -148,6 +181,11 @@ static void get_names_for_var(Var *var, deparse_context *context,
                                  char **schemaname, char **refname, char **attname);
 static RangeTblEntry *find_rte_by_refname(const char *refname,
                                        deparse_context *context);
+static const char *get_simple_binary_op_name(OpExpr *expr);
+static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
+static void appendStringInfoSpaces(StringInfo buf, int count);
+static void appendContextKeyword(deparse_context *context, const char *str,
+                                                int indentBefore, int indentAfter, int indentPlus);
 static void get_rule_expr(Node *node, deparse_context *context,
                                                  bool showimplicit);
 static void get_oper_expr(OpExpr *expr, deparse_context *context);
@@ -184,6 +222,26 @@ Datum
 pg_get_ruledef(PG_FUNCTION_ARGS)
 {
        Oid                     ruleoid = PG_GETARG_OID(0);
+
+       return pg_get_ruledef_worker(ruleoid, 0);
+}
+
+
+Datum
+pg_get_ruledef_ext(PG_FUNCTION_ARGS)
+{
+       Oid                     ruleoid = PG_GETARG_OID(0);
+       bool            pretty = PG_GETARG_BOOL(1);
+       int                     prettyFlags;
+
+       prettyFlags = pretty ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
+       return pg_get_ruledef_worker(ruleoid, prettyFlags);
+}
+
+
+static Datum
+pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
+{
        text       *ruledef;
        Datum           args[1];
        char            nulls[1];
@@ -241,7 +299,7 @@ pg_get_ruledef(PG_FUNCTION_ARGS)
         * Get the rules definition and put it into executors memory
         */
        initStringInfo(&buf);
-       make_ruledef(&buf, ruletup, rulettc);
+       make_ruledef(&buf, ruletup, rulettc, prettyFlags);
        len = buf.len + VARHDRSZ;
        ruledef = SPI_palloc(len);
        VARATT_SIZEP(ruledef) = len;
@@ -273,7 +331,22 @@ pg_get_viewdef(PG_FUNCTION_ARGS)
        Oid                     viewoid = PG_GETARG_OID(0);
        text       *ruledef;
 
-       ruledef = pg_do_getviewdef(viewoid);
+       ruledef = pg_do_getviewdef(viewoid, 0);
+       PG_RETURN_TEXT_P(ruledef);
+}
+
+
+Datum
+pg_get_viewdef_ext(PG_FUNCTION_ARGS)
+{
+       /* By OID */
+       Oid                     viewoid = PG_GETARG_OID(0);
+       bool            pretty = PG_GETARG_BOOL(1);
+       text       *ruledef;
+       int                     prettyFlags;
+
+       prettyFlags = pretty ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
+       ruledef = pg_do_getviewdef(viewoid, prettyFlags);
        PG_RETURN_TEXT_P(ruledef);
 }
 
@@ -290,7 +363,28 @@ pg_get_viewdef_name(PG_FUNCTION_ARGS)
                                                                                                                 "get_viewdef"));
        viewoid = RangeVarGetRelid(viewrel, false);
 
-       ruledef = pg_do_getviewdef(viewoid);
+       ruledef = pg_do_getviewdef(viewoid, 0);
+       PG_RETURN_TEXT_P(ruledef);
+}
+
+
+Datum
+pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
+{
+       /* By qualified name */
+       text       *viewname = PG_GETARG_TEXT_P(0);
+       bool            pretty = PG_GETARG_BOOL(1);
+       int                     prettyFlags;
+       RangeVar   *viewrel;
+       Oid                     viewoid;
+       text       *ruledef;
+
+       prettyFlags = pretty ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
+       viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname,
+                                                                                                                "get_viewdef"));
+       viewoid = RangeVarGetRelid(viewrel, false);
+
+       ruledef = pg_do_getviewdef(viewoid, prettyFlags);
        PG_RETURN_TEXT_P(ruledef);
 }
 
@@ -298,7 +392,7 @@ pg_get_viewdef_name(PG_FUNCTION_ARGS)
  * Common code for by-OID and by-name variants of pg_get_viewdef
  */
 static text *
-pg_do_getviewdef(Oid viewoid)
+pg_do_getviewdef(Oid viewoid, int prettyFlags)
 {
        text       *ruledef;
        Datum           args[2];
@@ -353,7 +447,7 @@ pg_do_getviewdef(Oid viewoid)
                 */
                ruletup = SPI_tuptable->vals[0];
                rulettc = SPI_tuptable->tupdesc;
-               make_viewdef(&buf, ruletup, rulettc);
+               make_viewdef(&buf, ruletup, rulettc, prettyFlags);
        }
        len = buf.len + VARHDRSZ;
        ruledef = SPI_palloc(len);
@@ -521,12 +615,35 @@ pg_get_triggerdef(PG_FUNCTION_ARGS)
 
 /* ----------
  * get_indexdef                        - Get the definition of an index
+ *
+ * In the extended version, there is a colno argument as well as pretty bool.
+ *     if colno == 0, we want a complete index definition.
+ *     if colno > 0, we only want the Nth index key's variable or expression.
  * ----------
  */
 Datum
 pg_get_indexdef(PG_FUNCTION_ARGS)
 {
        Oid                     indexrelid = PG_GETARG_OID(0);
+
+       return pg_get_indexdef_worker(indexrelid, 0, 0);
+}
+
+Datum
+pg_get_indexdef_ext(PG_FUNCTION_ARGS)
+{
+       Oid                     indexrelid = PG_GETARG_OID(0);
+       int32       colno = PG_GETARG_INT32(1);
+       bool            pretty = PG_GETARG_BOOL(2);
+       int                     prettyFlags;
+
+       prettyFlags = pretty ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
+       return pg_get_indexdef_worker(indexrelid, colno, prettyFlags);
+}
+
+static Datum
+pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
+{
        text       *indexdef;
        HeapTuple       ht_idx;
        HeapTuple       ht_idxrel;
@@ -607,7 +724,9 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
         * never be schema-qualified, but the indexed rel's name may be.
         */
        initStringInfo(&buf);
-       appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
+
+       if (!colno)
+           appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
                                         idxrec->indisunique ? "UNIQUE " : "",
                                         quote_identifier(NameStr(idxrelrec->relname)),
                                         generate_relation_name(indrelid),
@@ -621,7 +740,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
        {
                AttrNumber      attnum = idxrec->indkey[keyno];
 
-               appendStringInfo(&buf, sep);
+               if (!colno)
+                   appendStringInfo(&buf, sep);
                sep = ", ";
 
                if (attnum != 0)
@@ -630,7 +750,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
                        char       *attname;
 
                        attname = get_relid_attribute_name(indrelid, attnum);
-                       appendStringInfo(&buf, "%s", quote_identifier(attname));
+                       if (!colno || colno == keyno+1)
+                           appendStringInfo(&buf, "%s", quote_identifier(attname));
                        keycoltype = get_atttype(indrelid, attnum);
                }
                else
@@ -643,54 +764,63 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
                        indexkey = (Node *) lfirst(indexprs);
                        indexprs = lnext(indexprs);
                        /* Deparse */
-                       str = deparse_expression(indexkey, context, false, false);
-                       /* Need parens if it's not a bare function call */
-                       if (indexkey && IsA(indexkey, FuncExpr) &&
-                               ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
-                               appendStringInfo(&buf, "%s", str);
-                       else
-                               appendStringInfo(&buf, "(%s)", str);
+                       str = deparse_expression_pretty(indexkey, context, false, false,
+                                                                                       prettyFlags, 0);
+                       if (!colno || colno == keyno+1)
+                       {
+                           /* Need parens if it's not a bare function call */
+                           if (indexkey && IsA(indexkey, FuncExpr) &&
+                                       ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
+                                       appendStringInfo(&buf, "%s", str);
+                           else
+                                       appendStringInfo(&buf, "(%s)", str);
+                       }
                        keycoltype = exprType(indexkey);
                }
 
                /*
                 * Add the operator class name
                 */
-               get_opclass_name(idxrec->indclass[keyno], keycoltype,
+               if (!colno)
+                   get_opclass_name(idxrec->indclass[keyno], keycoltype,
                                                 &buf);
        }
 
-       appendStringInfoChar(&buf, ')');
-
-       /*
-        * If it's a partial index, decompile and append the predicate
-        */
-       if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
+       if (!colno)
        {
-               Node       *node;
-               Datum           predDatum;
-               bool            isnull;
-               char       *predString;
+           appendStringInfoChar(&buf, ')');
+
+           /*
+            * If it's a partial index, decompile and append the predicate
+            */
+           if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
+           {
+                       Node       *node;
+                       Datum           predDatum;
+                       bool            isnull;
+                       char       *predString;
+
+                       /* Convert text string to node tree */
+                       predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
+                                                                               Anum_pg_index_indpred, &isnull);
+                       Assert(!isnull);
+                       predString = DatumGetCString(DirectFunctionCall1(textout,
+                                                                                                                        predDatum));
+                       node = (Node *) stringToNode(predString);
+                       pfree(predString);
 
-               /* Convert text string to node tree */
-               predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
-                                                                       Anum_pg_index_indpred, &isnull);
-               Assert(!isnull);
-               predString = DatumGetCString(DirectFunctionCall1(textout,
-                                                                                                                predDatum));
-               node = (Node *) stringToNode(predString);
-               pfree(predString);
-
-               /*
-                * If top level is a List, assume it is an implicit-AND structure,
-                * and convert to explicit AND.  This is needed for partial index
-                * predicates.
-                */
-               if (node && IsA(node, List))
-                       node = (Node *) make_ands_explicit((List *) node);
-               /* Deparse */
-               str = deparse_expression(node, context, false, false);
-               appendStringInfo(&buf, " WHERE %s", str);
+                       /*
+                        * If top level is a List, assume it is an implicit-AND structure,
+                        * and convert to explicit AND.  This is needed for partial index
+                        * predicates.
+                        */
+                       if (node && IsA(node, List))
+                               node = (Node *) make_ands_explicit((List *) node);
+                       /* Deparse */
+                       str = deparse_expression_pretty(node, context, false, false,
+                                                                                       prettyFlags, 0);
+                       appendStringInfo(&buf, " WHERE %s", str);
+           }
        }
 
        /*
@@ -721,6 +851,25 @@ Datum
 pg_get_constraintdef(PG_FUNCTION_ARGS)
 {
        Oid                     constraintId = PG_GETARG_OID(0);
+
+       return pg_get_constraintdef_worker(constraintId, 0);
+}
+
+Datum
+pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
+{
+       Oid                     constraintId = PG_GETARG_OID(0);
+       bool            pretty = PG_GETARG_BOOL(1);
+       int                     prettyFlags;
+
+       prettyFlags = pretty ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
+       return pg_get_constraintdef_worker(constraintId, prettyFlags);
+}
+
+
+static Datum
+pg_get_constraintdef_worker(Oid constraintId, int prettyFlags)
+{
        text       *result;
        StringInfoData buf;
        int                     len;
@@ -934,7 +1083,8 @@ pg_get_constraintdef(PG_FUNCTION_ARGS)
                                        context = deparse_context_for(get_typname(conForm->contypid),
                                                                                                  InvalidOid);
 
-                               consrc = deparse_expression(expr, context, false, false);
+                               consrc = deparse_expression_pretty(expr, context, false, false,
+                                                                                                  prettyFlags, 0);
 
                                /* Append the constraint source */
                                appendStringInfoString(&buf, consrc); 
@@ -1012,20 +1162,46 @@ decompile_column_index_array(Datum column_index_array, Oid relId,
 Datum
 pg_get_expr(PG_FUNCTION_ARGS)
 {
-       text       *expr = PG_GETARG_TEXT_P(0);
-       Oid                     relid = PG_GETARG_OID(1);
-       text       *result;
-       Node       *node;
-       List       *context;
-       char       *exprstr;
+       text    *expr = PG_GETARG_TEXT_P(0);
+       Oid     relid = PG_GETARG_OID(1);
        char       *relname;
-       char       *str;
 
        /* Get the name for the relation */
        relname = get_rel_name(relid);
        if (relname == NULL)
                PG_RETURN_NULL();               /* should we raise an error? */
 
+       return pg_get_expr_worker(expr, relid, relname, 0);
+}
+
+Datum
+pg_get_expr_ext(PG_FUNCTION_ARGS)
+{
+       text    *expr = PG_GETARG_TEXT_P(0);
+       Oid     relid = PG_GETARG_OID(1);
+       bool            pretty = PG_GETARG_BOOL(2);
+       int                     prettyFlags;
+       char       *relname;
+
+       prettyFlags = pretty ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
+
+       /* Get the name for the relation */
+       relname = get_rel_name(relid);
+       if (relname == NULL)
+               PG_RETURN_NULL();               /* should we raise an error? */
+
+       return pg_get_expr_worker(expr, relid, relname, prettyFlags);
+}
+
+static Datum
+pg_get_expr_worker(text *expr, Oid relid, char *relname, int prettyFlags)
+{
+       text       *result;
+       Node       *node;
+       List       *context;
+       char       *exprstr;
+       char       *str;
+
        /* Convert input TEXT object to C string */
        exprstr = DatumGetCString(DirectFunctionCall1(textout,
                                                                                                  PointerGetDatum(expr)));
@@ -1043,7 +1219,8 @@ pg_get_expr(PG_FUNCTION_ARGS)
 
        /* Deparse */
        context = deparse_context_for(relname, relid);
-       str = deparse_expression(node, context, false, false);
+       str = deparse_expression_pretty(node, context, false, false,
+                                                                       prettyFlags, 0);
 
        /* Pass the result back as TEXT */
        result = DatumGetTextP(DirectFunctionCall1(textin,
@@ -1093,6 +1270,19 @@ pg_get_userbyid(PG_FUNCTION_ARGS)
 /* ----------
  * deparse_expression                  - General utility for deparsing expressions
  *
+ * calls deparse_expression_pretty with all prettyPrinting disabled
+ */
+char *
+deparse_expression(Node *expr, List *dpcontext,
+                                  bool forceprefix, bool showimplicit)
+{
+    return deparse_expression_pretty(expr, dpcontext, forceprefix,
+                                                                        showimplicit, 0, 0);
+}
+
+/* ----------
+ * deparse_expression_pretty   - General utility for deparsing expressions
+ *
  * expr is the node tree to be deparsed.  It must be a transformed expression
  * tree (ie, not the raw output of gram.y).
  *
@@ -1102,13 +1292,16 @@ pg_get_userbyid(PG_FUNCTION_ARGS)
  * forceprefix is TRUE to force all Vars to be prefixed with their table names.
  *
  * showimplicit is TRUE to force all implicit casts to be shown explicitly.
+ * 
+ * tries to pretty up the output according to prettyFlags and startIndent.
  *
  * The result is a palloc'd string.
  * ----------
  */
 char *
-deparse_expression(Node *expr, List *dpcontext,
-                                  bool forceprefix, bool showimplicit)
+deparse_expression_pretty(Node *expr, List *dpcontext,
+                                                 bool forceprefix, bool showimplicit,
+                                                 int prettyFlags, int startIndent)
 {
        StringInfoData buf;
        deparse_context context;
@@ -1117,6 +1310,8 @@ deparse_expression(Node *expr, List *dpcontext,
        context.buf = &buf;
        context.namespaces = dpcontext;
        context.varprefix = forceprefix;
+       context.prettyFlags = prettyFlags;
+       context.indentLevel = startIndent;
 
        get_rule_expr(expr, &context, showimplicit);
 
@@ -1269,7 +1464,8 @@ deparse_context_for_subplan(const char *name, List *tlist,
  * ----------
  */
 static void
-make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
+make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
+                        int prettyFlags)
 {
        char       *rulename;
        char            ev_type;
@@ -1323,9 +1519,14 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
        /*
         * Build the rules definition text
         */
-       appendStringInfo(buf, "CREATE RULE %s AS ON ",
+       appendStringInfo(buf, "CREATE RULE %s AS",
                                         quote_identifier(rulename));
 
+       if (prettyFlags & PRETTYFLAG_INDENT)
+           appendStringInfoString(buf, "\n    ON ");
+       else
+           appendStringInfoString(buf, " ON ");
+
        /* The event the rule is fired for */
        switch (ev_type)
        {
@@ -1370,6 +1571,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
                deparse_context context;
                deparse_namespace dpns;
 
+               if (prettyFlags & PRETTYFLAG_INDENT)
+                   appendStringInfoString(buf, "\n  ");
                appendStringInfo(buf, " WHERE ");
 
                qual = stringToNode(ev_qual);
@@ -1391,6 +1594,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
                context.buf = buf;
                context.namespaces = makeList1(&dpns);
                context.varprefix = (length(query->rtable) != 1);
+               context.prettyFlags = prettyFlags;
+               context.indentLevel = PRETTYINDENT_STD;
                dpns.rtable = query->rtable;
                dpns.outer_varno = dpns.inner_varno = 0;
                dpns.outer_rte = dpns.inner_rte = NULL;
@@ -1414,8 +1619,11 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
                foreach(action, actions)
                {
                        query = (Query *) lfirst(action);
-                       get_query_def(query, buf, NIL, NULL);
-                       appendStringInfo(buf, "; ");
+                       get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
+                       if (prettyFlags)
+                           appendStringInfo(buf, ";\n");
+                       else
+                           appendStringInfo(buf, "; ");
                }
                appendStringInfo(buf, ");");
        }
@@ -1428,7 +1636,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
                Query      *query;
 
                query = (Query *) lfirst(actions);
-               get_query_def(query, buf, NIL, NULL);
+               get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
                appendStringInfo(buf, ";");
        }
 }
@@ -1440,7 +1648,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
  * ----------
  */
 static void
-make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
+make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
+                        int prettyFlags)
 {
        Query      *query;
        char            ev_type;
@@ -1494,7 +1703,8 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
 
        ev_relation = heap_open(ev_class, AccessShareLock);
 
-       get_query_def(query, buf, NIL, RelationGetDescr(ev_relation));
+       get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),
+                                 prettyFlags, 0);
        appendStringInfo(buf, ";");
 
        heap_close(ev_relation, AccessShareLock);
@@ -1510,7 +1720,7 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
  */
 static void
 get_query_def(Query *query, StringInfo buf, List *parentnamespace,
-                         TupleDesc resultDesc)
+                         TupleDesc resultDesc, int prettyFlags, int startIndent)
 {
        deparse_context context;
        deparse_namespace dpns;
@@ -1519,6 +1729,9 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace,
        context.namespaces = lcons(&dpns, parentnamespace);
        context.varprefix = (parentnamespace != NIL ||
                                                 length(query->rtable) != 1);
+       context.prettyFlags = prettyFlags;
+       context.indentLevel = startIndent;
+
        dpns.rtable = query->rtable;
        dpns.outer_varno = dpns.inner_varno = 0;
        dpns.outer_rte = dpns.inner_rte = NULL;
@@ -1590,7 +1803,8 @@ get_select_query_def(Query *query, deparse_context *context,
        /* Add the ORDER BY clause if given */
        if (query->sortClause != NIL)
        {
-               appendStringInfo(buf, " ORDER BY ");
+               appendContextKeyword(context, " ORDER BY ",
+                                                                -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
                sep = "";
                foreach(l, query->sortClause)
                {
@@ -1619,12 +1833,14 @@ get_select_query_def(Query *query, deparse_context *context,
        /* Add the LIMIT clause if given */
        if (query->limitOffset != NULL)
        {
-               appendStringInfo(buf, " OFFSET ");
+               appendContextKeyword(context, " OFFSET ",
+                                                        -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
                get_rule_expr(query->limitOffset, context, false);
        }
        if (query->limitCount != NULL)
        {
-               appendStringInfo(buf, " LIMIT ");
+               appendContextKeyword(context, " LIMIT ",
+                                                        -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
                if (IsA(query->limitCount, Const) &&
                        ((Const *) query->limitCount)->constisnull)
                        appendStringInfo(buf, "ALL");
@@ -1645,6 +1861,11 @@ get_basic_select_query(Query *query, deparse_context *context,
        /*
         * Build up the query string - first we say SELECT
         */
+       if (PRETTY_INDENT(context))
+       {
+           context->indentLevel += PRETTYINDENT_STD;
+           appendStringInfoChar(buf, ' ');
+       }
        appendStringInfo(buf, "SELECT");
 
        /* Add the DISTINCT clause if given */
@@ -1724,14 +1945,16 @@ get_basic_select_query(Query *query, deparse_context *context,
        /* Add the WHERE clause if given */
        if (query->jointree->quals != NULL)
        {
-               appendStringInfo(buf, " WHERE ");
+               appendContextKeyword(context, " WHERE ",
+                                                        -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
                get_rule_expr(query->jointree->quals, context, false);
        }
 
        /* Add the GROUP BY clause if given */
        if (query->groupClause != NULL)
        {
-               appendStringInfo(buf, " GROUP BY ");
+               appendContextKeyword(context, " GROUP BY ",
+                                                        -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
                sep = "";
                foreach(l, query->groupClause)
                {
@@ -1747,7 +1970,8 @@ get_basic_select_query(Query *query, deparse_context *context,
        /* Add the HAVING clause if given */
        if (query->havingQual != NULL)
        {
-               appendStringInfo(buf, " HAVING ");
+               appendContextKeyword(context, " HAVING ",
+                                                        -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
                get_rule_expr(query->havingQual, context, false);
        }
 }
@@ -1765,35 +1989,71 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context,
                Query      *subquery = rte->subquery;
 
                Assert(subquery != NULL);
-               get_query_def(subquery, buf, context->namespaces, resultDesc);
+               get_query_def(subquery, buf, context->namespaces, resultDesc,
+                                         context->prettyFlags, context->indentLevel);
        }
        else if (IsA(setOp, SetOperationStmt))
        {
                SetOperationStmt *op = (SetOperationStmt *) setOp;
+               bool need_paren;
+
+               need_paren = (PRETTY_PAREN(context) ?
+                                         !IsA(op->rarg, RangeTblRef) : true);
+
+               if (!PRETTY_PAREN(context))
+                   appendStringInfoString(buf, "((");
 
-               appendStringInfo(buf, "((");
                get_setop_query(op->larg, query, context, resultDesc);
+
+               if (!PRETTY_PAREN(context))
+                   appendStringInfoChar(buf, ')');
+               if (!PRETTY_INDENT(context))
+                   appendStringInfoChar(buf, ' ');
                switch (op->op)
                {
                        case SETOP_UNION:
-                               appendStringInfo(buf, ") UNION ");
+                               appendContextKeyword(context, "UNION ",
+                                                                        -PRETTYINDENT_STD, 0, 0);
                                break;
                        case SETOP_INTERSECT:
-                               appendStringInfo(buf, ") INTERSECT ");
+                               appendContextKeyword(context, "INTERSECT ",
+                                                                        -PRETTYINDENT_STD, 0, 0);
                                break;
                        case SETOP_EXCEPT:
-                               appendStringInfo(buf, ") EXCEPT ");
+                               appendContextKeyword(context, "EXCEPT ",
+                                                                        -PRETTYINDENT_STD, 0, 0);
                                break;
                        default:
                                elog(ERROR, "unrecognized set op: %d",
                                         (int) op->op);
                }
                if (op->all)
-                       appendStringInfo(buf, "ALL (");
+                       appendStringInfo(buf, "ALL ");
+
+               if (PRETTY_INDENT(context))
+                   appendStringInfoChar(buf, '\n');
+
+               if (PRETTY_PAREN(context))
+               {
+                   if (need_paren)
+                   {
+                               appendStringInfoChar(buf, '(');
+                               if (PRETTY_INDENT(context))
+                                       appendStringInfoChar(buf, '\n');
+                   }
+               }
                else
-                       appendStringInfo(buf, "(");
+                   appendStringInfoChar(buf, '(');
+
                get_setop_query(op->rarg, query, context, resultDesc);
-               appendStringInfo(buf, "))");
+
+               if (PRETTY_PAREN(context))
+               {
+                   if (need_paren)
+                               appendStringInfoChar(buf, ')');
+               }
+               else
+                   appendStringInfoString(buf, "))");
        }
        else
        {
@@ -1866,6 +2126,12 @@ get_insert_query_def(Query *query, deparse_context *context)
         */
        rte = rt_fetch(query->resultRelation, query->rtable);
        Assert(rte->rtekind == RTE_RELATION);
+
+       if (PRETTY_INDENT(context))
+       {
+           context->indentLevel += PRETTYINDENT_STD;
+           appendStringInfoChar(buf, ' ');
+       }
        appendStringInfo(buf, "INSERT INTO %s",
                                         generate_relation_name(rte->relid));
 
@@ -1887,7 +2153,8 @@ get_insert_query_def(Query *query, deparse_context *context)
        /* Add the VALUES or the SELECT */
        if (select_rte == NULL)
        {
-               appendStringInfo(buf, "VALUES (");
+               appendContextKeyword(context, "VALUES (",
+                                                        -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
                sep = "";
                foreach(l, query->targetList)
                {
@@ -1903,7 +2170,8 @@ get_insert_query_def(Query *query, deparse_context *context)
                appendStringInfoChar(buf, ')');
        }
        else
-               get_query_def(select_rte->subquery, buf, NIL, NULL);
+               get_query_def(select_rte->subquery, buf, NIL, NULL,
+                                         context->prettyFlags, context->indentLevel);
 }
 
 
@@ -1924,6 +2192,11 @@ get_update_query_def(Query *query, deparse_context *context)
         */
        rte = rt_fetch(query->resultRelation, query->rtable);
        Assert(rte->rtekind == RTE_RELATION);
+       if (PRETTY_INDENT(context))
+       {
+           appendStringInfoChar(buf, ' ');
+           context->indentLevel += PRETTYINDENT_STD;
+       }
        appendStringInfo(buf, "UPDATE %s%s SET ",
                                         only_marker(rte),
                                         generate_relation_name(rte->relid));
@@ -1957,7 +2230,8 @@ get_update_query_def(Query *query, deparse_context *context)
        /* Finally add a WHERE clause if given */
        if (query->jointree->quals != NULL)
        {
-               appendStringInfo(buf, " WHERE ");
+               appendContextKeyword(context, " WHERE ",
+                                                        -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
                get_rule_expr(query->jointree->quals, context, false);
        }
 }
@@ -1978,6 +2252,11 @@ get_delete_query_def(Query *query, deparse_context *context)
         */
        rte = rt_fetch(query->resultRelation, query->rtable);
        Assert(rte->rtekind == RTE_RELATION);
+       if (PRETTY_INDENT(context))
+       {
+           context->indentLevel += PRETTYINDENT_STD;
+           appendStringInfoChar(buf, ' ');
+       }
        appendStringInfo(buf, "DELETE FROM %s%s",
                                         only_marker(rte),
                                         generate_relation_name(rte->relid));
@@ -1985,7 +2264,8 @@ get_delete_query_def(Query *query, deparse_context *context)
        /* Add a WHERE clause if given */
        if (query->jointree->quals != NULL)
        {
-               appendStringInfo(buf, " WHERE ");
+               appendContextKeyword(context, " WHERE ",
+                                                        -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
                get_rule_expr(query->jointree->quals, context, false);
        }
 }
@@ -2004,6 +2284,8 @@ get_utility_query_def(Query *query, deparse_context *context)
        {
                NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
 
+               appendContextKeyword(context, "",
+                                                        0, PRETTYINDENT_STD, 1);
                appendStringInfo(buf, "NOTIFY %s",
                                   quote_qualified_identifier(stmt->relation->schemaname,
                                                                                          stmt->relation->relname));
@@ -2145,6 +2427,285 @@ find_rte_by_refname(const char *refname, deparse_context *context)
 }
 
 
+/*
+ * get_simple_binary_op_name
+ *
+ * helper function for isSimpleNode
+ * will return single char binary operator name, or NULL if it's not
+ */
+static const char *
+get_simple_binary_op_name(OpExpr *expr)
+{
+       List       *args = expr->args;
+
+       if (length(args) == 2)
+       {
+               /* binary operator */
+               Node       *arg1 = (Node *) lfirst(args);
+               Node       *arg2 = (Node *) lsecond(args);
+               const char *op;
+
+               op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
+               if (strlen(op) == 1)
+                   return op;
+       }
+       return NULL;
+}
+
+
+/*
+ * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
+ *
+ *  true   : simple in the context of parent node's type
+ *  false  : not simple
+ */
+static bool
+isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
+{
+    if (!node)
+               return false;
+
+    switch (nodeTag(node))
+    {
+               case T_Var:
+               case T_Const:
+               case T_Param:
+               case T_CoerceToDomainValue:
+               case T_SetToDefault:
+                       /* single words: always simple */
+                       return true;
+
+               case T_ArrayRef:
+               case T_ArrayExpr:
+               case T_CoalesceExpr:
+               case T_NullIfExpr:
+               case T_Aggref:
+               case T_FuncExpr:
+                       /* function-like: name(..) or name[..] */
+                       return true;
+
+        /* CASE keywords act as parentheses */
+               case T_CaseExpr:
+                       return true;
+
+               case T_FieldSelect:
+                       /*
+                        * appears simple since . has top precedence, unless parent is
+                        * T_FieldSelect itself!
+                        */
+                       return (IsA(parentNode, FieldSelect) ? false : true);
+
+               case T_CoerceToDomain:
+                       /* maybe simple, check args */
+                       return isSimpleNode((Node*) ((CoerceToDomain*)node)->arg,
+                                                               node, prettyFlags);
+               case T_RelabelType:
+                       return isSimpleNode((Node*) ((RelabelType*)node)->arg,
+                                                               node, prettyFlags);
+
+               case T_OpExpr:
+               {
+                       /* depends on parent node type; needs further checking */
+                       if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
+                       {
+                               const char *op;
+                               const char *parentOp;
+                               bool            is_lopriop;
+                               bool            is_hipriop;
+                               bool            is_lopriparent;
+                               bool            is_hipriparent;
+
+                               op = get_simple_binary_op_name((OpExpr*) node);
+                               if (!op)
+                                       return false;
+
+                               /* We know only the basic operators + - and * / % */
+                               is_lopriop = (strchr("+-", *op) != NULL);
+                               is_hipriop = (strchr("*/%", *op) != NULL);
+                               if (!(is_lopriop || is_hipriop))
+                                       return false;
+
+                               parentOp = get_simple_binary_op_name((OpExpr*) parentNode);
+                               if (!parentOp)
+                                       return false;
+
+                               is_lopriparent = (strchr("+-", *parentOp) != NULL);
+                               is_hipriparent = (strchr("*/%", *parentOp) != NULL);
+                               if (!(is_lopriparent || is_hipriparent))
+                                       return false;
+
+                               if (is_hipriop && is_lopriparent)
+                                       return true; /* op binds tighter than parent */
+
+                               if (is_lopriop && is_hipriparent)
+                                       return false;
+
+                               /*
+                                * Operators are same priority --- can skip parens only
+                                * if we have (a - b) - c, not a - (b - c).
+                                */
+                               if (node == (Node *) lfirst(((OpExpr *) parentNode)->args))
+                                       return true;
+
+                               return false;
+                       }
+            /* else do the same stuff as for T_SubLink et al. */
+                       /* FALL THROUGH */
+               }
+
+               case T_SubLink:
+               case T_NullTest:
+               case T_BooleanTest:
+               case T_DistinctExpr:
+                       switch (nodeTag(parentNode))
+                       {
+                               case T_FuncExpr:
+                               {
+                                       /* special handling for casts */
+                                       CoercionForm    type = ((FuncExpr*)parentNode)->funcformat;
+
+                                       if (type == COERCE_EXPLICIT_CAST ||
+                                               type == COERCE_IMPLICIT_CAST)
+                                               return false;
+                    return true;      /* own parentheses */
+                               }
+                               case T_BoolExpr:      /* lower precedence */
+                               case T_ArrayRef:      /* other separators */
+                               case T_ArrayExpr:     /* other separators */
+                               case T_CoalesceExpr:  /* own parentheses */
+                               case T_NullIfExpr:    /* other separators */
+                               case T_Aggref:        /* own parentheses */
+                               case T_CaseExpr:      /* other separators */
+                                       return true;
+                               default:
+                                       return false;
+                       }
+
+               case T_BoolExpr:
+                       switch (nodeTag(parentNode))
+                       {
+                               case T_BoolExpr:
+                                       if (prettyFlags & PRETTYFLAG_PAREN)
+                                       {
+                                               BoolExprType type;
+                                               BoolExprType parentType;
+
+                                               type = ((BoolExpr*)node)->boolop;
+                                               parentType = ((BoolExpr*)parentNode)->boolop;
+                                               switch (type)
+                                               {
+                                                       case NOT_EXPR:
+                                                       case AND_EXPR:
+                                                               if (parentType == AND_EXPR || parentType == OR_EXPR)
+                                                                       return true;
+                                                               break;
+                                                       case OR_EXPR:
+                                                               if (parentType == OR_EXPR)
+                                                                       return true;
+                                                               break;
+                                               }
+                                       }
+                                       return false;
+                               case T_FuncExpr:
+                               {
+                                       /* special handling for casts */
+                                       CoercionForm type=((FuncExpr*)parentNode)->funcformat;
+
+                                       if (type == COERCE_EXPLICIT_CAST ||
+                                               type == COERCE_IMPLICIT_CAST)
+                                               return false;
+                    return true;      /* own parentheses */
+                               }
+                               case T_ArrayRef:      /* other separators */
+                               case T_ArrayExpr:     /* other separators */
+                               case T_CoalesceExpr:  /* own parentheses */
+                               case T_NullIfExpr:    /* other separators */
+                               case T_Aggref:        /* own parentheses */
+                               case T_CaseExpr:      /* other separators */
+                                       return true;
+                               default:
+                                       return false;
+                       }
+
+               default:
+                       break;
+    }
+    /* those we don't know: in dubio complexo */
+    return false;
+}
+
+
+/*
+ * appendStringInfoSpaces - append spaces to buffer
+ */
+static void
+appendStringInfoSpaces(StringInfo buf, int count)
+{
+    while (count-- > 0)
+               appendStringInfoChar(buf, ' ');
+}
+
+/*
+ * appendContextKeyword - append a keyword to buffer
+ *
+ * If prettyPrint is enabled, perform a line break, and adjust indentation.
+ * Otherwise, just append the keyword.
+ */
+static void
+appendContextKeyword(deparse_context *context, const char *str,
+                                        int indentBefore, int indentAfter, int indentPlus)
+{
+    if (PRETTY_INDENT(context))
+    {
+               context->indentLevel += indentBefore;
+               if (context->indentLevel < 0)
+                       context->indentLevel = 0;
+
+               appendStringInfoChar(context->buf, '\n');
+               appendStringInfoSpaces(context->buf,
+                                                          context->indentLevel + indentPlus);
+    }
+
+    appendStringInfoString(context->buf, str);
+
+    if (PRETTY_INDENT(context))
+    {
+               context->indentLevel += indentAfter;
+               if (context->indentLevel < 0)
+                       context->indentLevel = 0;
+    }
+}
+
+/*
+ * get_rule_expr_paren  - deparse expr using get_rule_expr, 
+ * embracing the string with parentheses if necessary for prettyPrint.
+ *
+ * Never embrace if prettyFlags=0, because it's done in the calling node.
+ *
+ * Any node that does *not* embrace its argument node by sql syntax (with
+ * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
+ * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
+ * added.
+ */
+static void
+get_rule_expr_paren(Node *node, deparse_context *context, 
+                                       bool showimplicit, Node *parentNode)
+{
+       bool need_paren;
+
+       need_paren = PRETTY_PAREN(context) &&
+               !isSimpleNode(node, parentNode, context->prettyFlags);
+
+       if (need_paren)
+           appendStringInfoChar(context->buf, '(');
+
+       get_rule_expr(node, context, showimplicit);
+
+       if (need_paren)
+           appendStringInfoChar(context->buf, ')');
+}
+
+
 /* ----------
  * get_rule_expr                       - Parse back an expression
  *
@@ -2300,11 +2861,13 @@ get_rule_expr(Node *node, deparse_context *context,
                                Node       *arg1 = (Node *) lfirst(args);
                                Node       *arg2 = (Node *) lsecond(args);
 
-                               appendStringInfoChar(buf, '(');
-                               get_rule_expr(arg1, context, true);
+                               if (!PRETTY_PAREN(context))
+                                   appendStringInfoChar(buf, '(');
+                               get_rule_expr_paren(arg1, context, true, node);
                                appendStringInfo(buf, " IS DISTINCT FROM ");
-                               get_rule_expr(arg2, context, true);
-                               appendStringInfoChar(buf, ')');
+                               get_rule_expr_paren(arg2, context, true, node);
+                               if (!PRETTY_PAREN(context))
+                                   appendStringInfoChar(buf, ')');
                        }
                        break;
 
@@ -2315,15 +2878,18 @@ get_rule_expr(Node *node, deparse_context *context,
                                Node       *arg1 = (Node *) lfirst(args);
                                Node       *arg2 = (Node *) lsecond(args);
 
-                               appendStringInfoChar(buf, '(');
-                               get_rule_expr(arg1, context, true);
+                               if (!PRETTY_PAREN(context))
+                                   appendStringInfoChar(buf, '(');
+                               get_rule_expr_paren(arg1, context, true, node);
                                appendStringInfo(buf, " %s %s (",
                                                                 generate_operator_name(expr->opno,
                                                                                                                exprType(arg1),
                                                                                get_element_type(exprType(arg2))),
                                                                 expr->useOr ? "ANY" : "ALL");
-                               get_rule_expr(arg2, context, true);
-                               appendStringInfo(buf, "))");
+                               get_rule_expr_paren(arg2, context, true, node);
+                               appendStringInfoChar(buf, ')');
+                               if (!PRETTY_PAREN(context))
+                                   appendStringInfoChar(buf, ')');
                        }
                        break;
 
@@ -2335,33 +2901,43 @@ get_rule_expr(Node *node, deparse_context *context,
                                switch (expr->boolop)
                                {
                                        case AND_EXPR:
-                                               appendStringInfoChar(buf, '(');
-                                               get_rule_expr((Node *) lfirst(args), context, false);
+                                               if (!PRETTY_PAREN(context))
+                                                   appendStringInfoChar(buf, '(');
+                                               get_rule_expr_paren((Node *) lfirst(args), context,
+                                                                                       false, node);
                                                while ((args = lnext(args)) != NIL)
                                                {
                                                        appendStringInfo(buf, " AND ");
-                                                       get_rule_expr((Node *) lfirst(args), context,
-                                                                                 false);
+                                                       get_rule_expr_paren((Node *) lfirst(args), context,
+                                                                                               false, node);
                                                }
-                                               appendStringInfoChar(buf, ')');
+                                               if (!PRETTY_PAREN(context))
+                                                   appendStringInfoChar(buf, ')');
                                                break;
 
                                        case OR_EXPR:
-                                               appendStringInfoChar(buf, '(');
-                                               get_rule_expr((Node *) lfirst(args), context, false);
+                                               if (!PRETTY_PAREN(context))
+                                                   appendStringInfoChar(buf, '(');
+                                               get_rule_expr_paren((Node *) lfirst(args), context,
+                                                                                       false, node);
                                                while ((args = lnext(args)) != NIL)
                                                {
                                                        appendStringInfo(buf, " OR ");
-                                                       get_rule_expr((Node *) lfirst(args), context,
-                                                                                 false);
+                                                       get_rule_expr_paren((Node *) lfirst(args), context,
+                                                                                               false, node);
                                                }
-                                               appendStringInfoChar(buf, ')');
+                                               if (!PRETTY_PAREN(context))
+                                                   appendStringInfoChar(buf, ')');
                                                break;
 
                                        case NOT_EXPR:
-                                               appendStringInfo(buf, "(NOT ");
-                                               get_rule_expr((Node *) lfirst(args), context, false);
-                                               appendStringInfoChar(buf, ')');
+                                               if (!PRETTY_PAREN(context))
+                                                   appendStringInfoChar(buf, '(');
+                                               appendStringInfo(buf, "NOT ");
+                                               get_rule_expr_paren((Node *) lfirst(args), context,
+                                                                                       false, node);
+                                               if (!PRETTY_PAREN(context))
+                                                   appendStringInfoChar(buf, ')');
                                                break;
 
                                        default:
@@ -2409,9 +2985,12 @@ get_rule_expr(Node *node, deparse_context *context,
                                 * arg.fieldname, but most cases where FieldSelect is used
                                 * are *not* simple.  So, always use parenthesized syntax.
                                 */
-                               appendStringInfoChar(buf, '(');
-                               get_rule_expr((Node *) fselect->arg, context, true);
-                               appendStringInfo(buf, ").%s", quote_identifier(fieldname));
+                               if (!PRETTY_PAREN(context))
+                                   appendStringInfoChar(buf, '(');
+                               get_rule_expr_paren((Node *) fselect->arg, context, true, node);
+                               if (!PRETTY_PAREN(context))
+                                   appendStringInfoChar(buf, ')');
+                               appendStringInfo(buf, ".%s", quote_identifier(fieldname));
                        }
                        break;
 
@@ -2424,7 +3003,7 @@ get_rule_expr(Node *node, deparse_context *context,
                                        !showimplicit)
                                {
                                        /* don't show the implicit cast */
-                                       get_rule_expr(arg, context, showimplicit);
+                                       get_rule_expr_paren(arg, context, showimplicit, node);
                                }
                                else
                                {
@@ -2436,9 +3015,12 @@ get_rule_expr(Node *node, deparse_context *context,
                                         */
                                        arg = strip_type_coercion(arg, relabel->resulttype);
 
-                                       appendStringInfoChar(buf, '(');
-                                       get_rule_expr(arg, context, showimplicit);
-                                       appendStringInfo(buf, ")::%s",
+                                       if (!PRETTY_PAREN(context))
+                                           appendStringInfoChar(buf, '(');
+                                       get_rule_expr_paren(arg, context, showimplicit, node);
+                                       if (!PRETTY_PAREN(context))
+                                           appendStringInfoChar(buf, ')');
+                                       appendStringInfo(buf, "::%s",
                                                        format_type_with_typemod(relabel->resulttype,
                                                                                                         relabel->resulttypmod));
                                }
@@ -2450,19 +3032,29 @@ get_rule_expr(Node *node, deparse_context *context,
                                CaseExpr   *caseexpr = (CaseExpr *) node;
                                List       *temp;
 
-                               appendStringInfo(buf, "CASE");
+                               appendContextKeyword(context, "CASE",
+                                                                        0, PRETTYINDENT_VAR, 0);
                                foreach(temp, caseexpr->args)
                                {
                                        CaseWhen   *when = (CaseWhen *) lfirst(temp);
 
-                                       appendStringInfo(buf, " WHEN ");
+                                       if (!PRETTY_INDENT(context))
+                                               appendStringInfoChar(buf, ' ');
+                                       appendContextKeyword(context, "WHEN ",
+                                                                                0, 0, 0);
                                        get_rule_expr((Node *) when->expr, context, false);
                                        appendStringInfo(buf, " THEN ");
                                        get_rule_expr((Node *) when->result, context, true);
                                }
-                               appendStringInfo(buf, " ELSE ");
+                               if (!PRETTY_INDENT(context))
+                                   appendStringInfoChar(buf, ' ');
+                               appendContextKeyword(context, "ELSE ",
+                                                                        0, 0, 0);
                                get_rule_expr((Node *) caseexpr->defresult, context, true);
-                               appendStringInfo(buf, " END");
+                               if (!PRETTY_INDENT(context))
+                                   appendStringInfoChar(buf, ' ');
+                               appendContextKeyword(context, "END",
+                                                                        -PRETTYINDENT_VAR, 0, 0);
                        }
                        break;
 
@@ -2530,20 +3122,23 @@ get_rule_expr(Node *node, deparse_context *context,
                        {
                                NullTest   *ntest = (NullTest *) node;
 
-                               appendStringInfo(buf, "(");
-                               get_rule_expr((Node *) ntest->arg, context, true);
+                               if (!PRETTY_PAREN(context))
+                                   appendStringInfoChar(buf, '(');
+                               get_rule_expr_paren((Node *) ntest->arg, context, true, node);
                                switch (ntest->nulltesttype)
                                {
                                        case IS_NULL:
-                                               appendStringInfo(buf, " IS NULL)");
+                                               appendStringInfo(buf, " IS NULL");
                                                break;
                                        case IS_NOT_NULL:
-                                               appendStringInfo(buf, " IS NOT NULL)");
+                                               appendStringInfo(buf, " IS NOT NULL");
                                                break;
                                        default:
                                                elog(ERROR, "unrecognized nulltesttype: %d",
                                                         (int) ntest->nulltesttype);
                                }
+                               if (!PRETTY_PAREN(context))
+                                   appendStringInfoChar(buf, ')');
                        }
                        break;
 
@@ -2551,32 +3146,35 @@ get_rule_expr(Node *node, deparse_context *context,
                        {
                                BooleanTest *btest = (BooleanTest *) node;
 
-                               appendStringInfo(buf, "(");
-                               get_rule_expr((Node *) btest->arg, context, false);
+                               if (!PRETTY_PAREN(context))
+                                   appendStringInfoChar(buf, '(');
+                               get_rule_expr_paren((Node *) btest->arg, context, false, node);
                                switch (btest->booltesttype)
                                {
                                        case IS_TRUE:
-                                               appendStringInfo(buf, " IS TRUE)");
+                                               appendStringInfo(buf, " IS TRUE");
                                                break;
                                        case IS_NOT_TRUE:
-                                               appendStringInfo(buf, " IS NOT TRUE)");
+                                               appendStringInfo(buf, " IS NOT TRUE");
                                                break;
                                        case IS_FALSE:
-                                               appendStringInfo(buf, " IS FALSE)");
+                                               appendStringInfo(buf, " IS FALSE");
                                                break;
                                        case IS_NOT_FALSE:
-                                               appendStringInfo(buf, " IS NOT FALSE)");
+                                               appendStringInfo(buf, " IS NOT FALSE");
                                                break;
                                        case IS_UNKNOWN:
-                                               appendStringInfo(buf, " IS UNKNOWN)");
+                                               appendStringInfo(buf, " IS UNKNOWN");
                                                break;
                                        case IS_NOT_UNKNOWN:
-                                               appendStringInfo(buf, " IS NOT UNKNOWN)");
+                                               appendStringInfo(buf, " IS NOT UNKNOWN");
                                                break;
                                        default:
                                                elog(ERROR, "unrecognized booltesttype: %d",
                                                         (int) btest->booltesttype);
                                }
+                               if (!PRETTY_PAREN(context))
+                                   appendStringInfoChar(buf, ')');
                        }
                        break;
 
@@ -2598,9 +3196,12 @@ get_rule_expr(Node *node, deparse_context *context,
                                }
                                else
                                {
-                                       appendStringInfoChar(buf, '(');
-                                       get_rule_expr(arg, context, false);
-                                       appendStringInfo(buf, ")::%s",
+                                       if (!PRETTY_PAREN(context))
+                                           appendStringInfoChar(buf, '(');
+                                       get_rule_expr_paren(arg, context, false, node);
+                                       if (!PRETTY_PAREN(context))
+                                           appendStringInfoChar(buf, ')');
+                                       appendStringInfo(buf, "::%s",
                                                        format_type_with_typemod(ctest->resulttype,
                                                                                                         ctest->resulttypmod));
                                }
@@ -2632,19 +3233,19 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
        Oid                     opno = expr->opno;
        List       *args = expr->args;
 
-       appendStringInfoChar(buf, '(');
+       if (!PRETTY_PAREN(context))
+           appendStringInfoChar(buf, '(');
        if (length(args) == 2)
        {
                /* binary operator */
                Node       *arg1 = (Node *) lfirst(args);
                Node       *arg2 = (Node *) lsecond(args);
-
-               get_rule_expr(arg1, context, true);
+               get_rule_expr_paren(arg1, context, true, (Node*)expr);
                appendStringInfo(buf, " %s ",
                                                 generate_operator_name(opno,
                                                                                                exprType(arg1),
                                                                                                exprType(arg2)));
-               get_rule_expr(arg2, context, true);
+               get_rule_expr_paren(arg2, context, true, (Node*)expr);
        }
        else
        {
@@ -2666,10 +3267,10 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
                                                                 generate_operator_name(opno,
                                                                                                                InvalidOid,
                                                                                                                exprType(arg)));
-                               get_rule_expr(arg, context, true);
+                               get_rule_expr_paren(arg, context, true, (Node*)expr);
                                break;
                        case 'r':
-                               get_rule_expr(arg, context, true);
+                               get_rule_expr_paren(arg, context, true, (Node*)expr);
                                appendStringInfo(buf, " %s",
                                                                 generate_operator_name(opno,
                                                                                                                exprType(arg),
@@ -2680,7 +3281,8 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
                }
                ReleaseSysCache(tp);
        }
-       appendStringInfoChar(buf, ')');
+       if (!PRETTY_PAREN(context))
+           appendStringInfoChar(buf, ')');
 }
 
 /*
@@ -2703,7 +3305,8 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
         */
        if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
        {
-               get_rule_expr((Node *) lfirst(expr->args), context, showimplicit);
+               get_rule_expr_paren((Node *) lfirst(expr->args), context,
+                                                       showimplicit, (Node*)expr);
                return;
        }
 
@@ -2729,9 +3332,12 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
                 */
                arg = strip_type_coercion(arg, rettype);
 
-               appendStringInfoChar(buf, '(');
-               get_rule_expr(arg, context, showimplicit);
-               appendStringInfo(buf, ")::%s",
+               if (!PRETTY_PAREN(context))
+                   appendStringInfoChar(buf, '(');
+               get_rule_expr_paren(arg, context, showimplicit, (Node*)expr);
+               if (!PRETTY_PAREN(context))
+                   appendStringInfoChar(buf, ')');
+               appendStringInfo(buf, "::%s",
                                                 format_type_with_typemod(rettype, coercedTypmod));
 
                return;
@@ -3052,7 +3658,8 @@ get_sublink_expr(SubLink *sublink, deparse_context *context)
        if (need_paren)
                appendStringInfoChar(buf, '(');
 
-       get_query_def(query, buf, context->namespaces, NULL);
+       get_query_def(query, buf, context->namespaces, NULL,
+                                 context->prettyFlags, context->indentLevel);
 
        if (need_paren)
                appendStringInfo(buf, "))");
@@ -3069,7 +3676,7 @@ static void
 get_from_clause(Query *query, deparse_context *context)
 {
        StringInfo      buf = context->buf;
-       char       *sep;
+       bool            first = true;
        List       *l;
 
        /*
@@ -3079,8 +3686,6 @@ get_from_clause(Query *query, deparse_context *context)
         * sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW
         * and OLD.
         */
-       sep = " FROM ";
-
        foreach(l, query->jointree->fromlist)
        {
                Node       *jtnode = (Node *) lfirst(l);
@@ -3098,9 +3703,16 @@ get_from_clause(Query *query, deparse_context *context)
                                continue;
                }
 
-               appendStringInfo(buf, sep);
+               if (first)
+               {
+                   appendContextKeyword(context, " FROM ",
+                                                                -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
+                       first = false;
+               }
+               else
+                   appendStringInfoString(buf, ", ");
+
                get_from_clause_item(jtnode, query, context);
-               sep = ", ";
        }
 }
 
@@ -3127,7 +3739,8 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
                        case RTE_SUBQUERY:
                                /* Subquery RTE */
                                appendStringInfoChar(buf, '(');
-                               get_query_def(rte->subquery, buf, context->namespaces, NULL);
+                               get_query_def(rte->subquery, buf, context->namespaces, NULL, 
+                                                         context->prettyFlags, context->indentLevel);
                                appendStringInfoChar(buf, ')');
                                break;
                        case RTE_FUNCTION:
@@ -3149,7 +3762,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
                        {
                                List       *col;
 
-                               appendStringInfo(buf, "(");
+                               appendStringInfoChar(buf, '(');
                                foreach(col, rte->alias->colnames)
                                {
                                        if (col != rte->alias->colnames)
@@ -3183,36 +3796,105 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
        else if (IsA(jtnode, JoinExpr))
        {
                JoinExpr   *j = (JoinExpr *) jtnode;
+               bool need_paren_on_right;
+
+               need_paren_on_right = PRETTY_PAREN(context) &&
+                       !IsA(j->rarg, RangeTblRef);
+
+               if (!PRETTY_PAREN(context) || j->alias != NULL)
+                   appendStringInfoChar(buf, '(');
 
-               appendStringInfoChar(buf, '(');
                get_from_clause_item(j->larg, query, context);
+
                if (j->isNatural)
-                       appendStringInfo(buf, " NATURAL");
-               switch (j->jointype)
                {
-                       case JOIN_INNER:
-                               if (j->quals)
-                                       appendStringInfo(buf, " JOIN ");
-                               else
-                                       appendStringInfo(buf, " CROSS JOIN ");
-                               break;
-                       case JOIN_LEFT:
-                               appendStringInfo(buf, " LEFT JOIN ");
-                               break;
-                       case JOIN_FULL:
-                               appendStringInfo(buf, " FULL JOIN ");
-                               break;
-                       case JOIN_RIGHT:
-                               appendStringInfo(buf, " RIGHT JOIN ");
-                               break;
-                       case JOIN_UNION:
-                               appendStringInfo(buf, " UNION JOIN ");
-                               break;
-                       default:
-                               elog(ERROR, "unrecognized join type: %d",
-                                        (int) j->jointype);
+                   if (!PRETTY_INDENT(context))
+                               appendStringInfoChar(buf, ' ');
+                   switch (j->jointype)
+                   {
+                               case JOIN_INNER:
+                                       if (j->quals)
+                                               appendContextKeyword(context, "NATURAL JOIN ",
+                                                                                        -PRETTYINDENT_JOIN,
+                                                                                        PRETTYINDENT_JOIN, 0);
+                                       else
+                                               appendContextKeyword(context, "NATURAL CROSS JOIN ",
+                                                                                        -PRETTYINDENT_JOIN,
+                                                                                        PRETTYINDENT_JOIN, 0);
+                                       break;
+                               case JOIN_LEFT:
+                                       appendContextKeyword(context, "NATURAL LEFT JOIN ",
+                                                                                -PRETTYINDENT_JOIN,
+                                                                                PRETTYINDENT_JOIN, 0);
+                                       break;
+                               case JOIN_FULL:
+                                       appendContextKeyword(context, "NATURAL FULL JOIN ",
+                                                                                -PRETTYINDENT_JOIN,
+                                                                                PRETTYINDENT_JOIN, 0);
+                                       break;
+                               case JOIN_RIGHT:
+                                       appendContextKeyword(context, "NATURAL RIGHT JOIN ",
+                                                                                -PRETTYINDENT_JOIN,
+                                                                                PRETTYINDENT_JOIN, 0);
+                                       break;
+                               case JOIN_UNION:
+                                       appendContextKeyword(context, "NATURAL UNION JOIN ",
+                                                                                -PRETTYINDENT_JOIN,
+                                                                                PRETTYINDENT_JOIN, 0);
+                                       break;
+                               default:
+                                       elog(ERROR, "unrecognized join type: %d",
+                                                (int) j->jointype);
+                   }
+               }
+               else
+               {
+                   switch (j->jointype)
+                   {
+                               case JOIN_INNER:
+                                       if (j->quals)
+                                               appendContextKeyword(context, " JOIN ",
+                                                                                        -PRETTYINDENT_JOIN,
+                                                                                        PRETTYINDENT_JOIN, 2);
+                                       else
+                                               appendContextKeyword(context, " CROSS JOIN ",
+                                                                                        -PRETTYINDENT_JOIN,
+                                                                                        PRETTYINDENT_JOIN, 1);
+                                       break;
+                               case JOIN_LEFT:
+                                       appendContextKeyword(context, " LEFT JOIN ",
+                                                                                -PRETTYINDENT_JOIN,
+                                                                                PRETTYINDENT_JOIN, 2);
+                                       break;
+                               case JOIN_FULL:
+                                       appendContextKeyword(context, " FULL JOIN ",
+                                                                                -PRETTYINDENT_JOIN,
+                                                                                PRETTYINDENT_JOIN, 2);
+                                       break;
+                               case JOIN_RIGHT:
+                                       appendContextKeyword(context, " RIGHT JOIN ",
+                                                                                -PRETTYINDENT_JOIN,
+                                                                                PRETTYINDENT_JOIN, 2);
+                                       break;
+                               case JOIN_UNION:
+                                       appendContextKeyword(context, " UNION JOIN ",
+                                                                                -PRETTYINDENT_JOIN,
+                                                                                PRETTYINDENT_JOIN, 2);
+                                       break;
+                               default:
+                                       elog(ERROR, "unrecognized join type: %d",
+                                                (int) j->jointype);
+                   }
                }
+
+               if (need_paren_on_right)
+                   appendStringInfoChar(buf, '(');
                get_from_clause_item(j->rarg, query, context);
+               if (need_paren_on_right)
+                   appendStringInfoChar(buf, ')');
+
+               context->indentLevel -= PRETTYINDENT_JOIN_ON;
+
                if (!j->isNatural)
                {
                        if (j->using)
@@ -3225,18 +3907,23 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
                                        if (col != j->using)
                                                appendStringInfo(buf, ", ");
                                        appendStringInfo(buf, "%s",
-                                                                 quote_identifier(strVal(lfirst(col))));
+                                                                        quote_identifier(strVal(lfirst(col))));
                                }
                                appendStringInfoChar(buf, ')');
                        }
                        else if (j->quals)
                        {
-                               appendStringInfo(buf, " ON (");
+                               appendStringInfo(buf, " ON ");
+                               if (!PRETTY_PAREN(context))
+                                   appendStringInfoChar(buf, '(');
                                get_rule_expr(j->quals, context, false);
-                               appendStringInfoChar(buf, ')');
+                               if (!PRETTY_PAREN(context))
+                                   appendStringInfoChar(buf, ')');
                        }
                }
-               appendStringInfoChar(buf, ')');
+               if (!PRETTY_PAREN(context) || j->alias != NULL)
+                   appendStringInfoChar(buf, ')');
+
                /* Yes, it's correct to put alias after the right paren ... */
                if (j->alias != NULL)
                {
@@ -3246,13 +3933,13 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
                        {
                                List       *col;
 
-                               appendStringInfo(buf, "(");
+                               appendStringInfoChar(buf, '(');
                                foreach(col, j->alias->colnames)
                                {
                                        if (col != j->alias->colnames)
                                                appendStringInfo(buf, ", ");
                                        appendStringInfo(buf, "%s",
-                                                                 quote_identifier(strVal(lfirst(col))));
+                                                                        quote_identifier(strVal(lfirst(col))));
                                }
                                appendStringInfoChar(buf, ')');
                        }
index f5fb059517b21fd2d42b6e4b67fcad25c1942b75..21ed3fbf90d8ceddde3bbeb801488ea463208222 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.203 2003/07/29 17:21:27 tgl Exp $
+ * $Id: catversion.h,v 1.204 2003/07/30 22:56:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200307291
+#define CATALOG_VERSION_NO     200307301
 
 #endif
index b1f16c2d4214b2630297c9d8b3ae0f25802305ea..e41817a0e3f3665c0ca4a5ec8dbeaa9477d12b9d 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.309 2003/07/01 00:04:38 tgl Exp $
+ * $Id: pg_proc.h,v 1.310 2003/07/30 22:56:24 tgl Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -3405,6 +3405,20 @@ DESCR("I/O");
 DATA(insert OID = 2503 (  anyarray_send                   PGNSP PGUID 12 f f t f s 1 17 "2277"  anyarray_send - _null_ ));
 DESCR("I/O");
 
+/* System-view support functions with pretty-print option */
+DATA(insert OID = 2504 (  pg_get_ruledef          PGNSP PGUID 12 f f t f s 2 25 "26 16"  pg_get_ruledef_ext - _null_ ));
+DESCR("source text of a rule with pretty-print option");
+DATA(insert OID = 2505 (  pg_get_viewdef          PGNSP PGUID 12 f f t f s 2 25 "25 16"  pg_get_viewdef_name_ext - _null_ ));
+DESCR("select statement of a view with pretty-print option");
+DATA(insert OID = 2506 (  pg_get_viewdef          PGNSP PGUID 12 f f t f s 2 25 "26 16"  pg_get_viewdef_ext - _null_ ));
+DESCR("select statement of a view with pretty-print option");
+DATA(insert OID = 2507 (  pg_get_indexdef         PGNSP PGUID 12 f f t f s 3 25 "26 23 16"  pg_get_indexdef_ext - _null_ ));
+DESCR("index description (full create statement or single expression) with pretty-print option");
+DATA(insert OID = 2508 (  pg_get_constraintdef PGNSP PGUID 12 f f t f s 2 25 "26 16"  pg_get_constraintdef_ext - _null_ ));
+DESCR("constraint description with pretty-print option");
+DATA(insert OID = 2509 (  pg_get_expr             PGNSP PGUID 12 f f t f s 3 25 "25 26 16"     pg_get_expr_ext - _null_ ));
+DESCR("deparse an encoded expression with pretty-print option");
+
 
 /*
  * Symbolic values for provolatile column: these indicate whether the result
index 52b67ac88a937ea3cd0152bdec4910ee210a5022..f2164590a36e0f091930e75972ab696da46e4cf2 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.223 2003/06/27 00:33:26 tgl Exp $
+ * $Id: builtins.h,v 1.224 2003/07/30 22:56:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -441,13 +441,19 @@ extern char *format_operator(Oid operator_oid);
 
 /* ruleutils.c */
 extern Datum pg_get_ruledef(PG_FUNCTION_ARGS);
+extern Datum pg_get_ruledef_ext(PG_FUNCTION_ARGS);
 extern Datum pg_get_viewdef(PG_FUNCTION_ARGS);
+extern Datum pg_get_viewdef_ext(PG_FUNCTION_ARGS);
 extern Datum pg_get_viewdef_name(PG_FUNCTION_ARGS);
+extern Datum pg_get_viewdef_name_ext(PG_FUNCTION_ARGS);
 extern Datum pg_get_indexdef(PG_FUNCTION_ARGS);
+extern Datum pg_get_indexdef_ext(PG_FUNCTION_ARGS);
 extern Datum pg_get_triggerdef(PG_FUNCTION_ARGS);
 extern Datum pg_get_constraintdef(PG_FUNCTION_ARGS);
+extern Datum pg_get_constraintdef_ext(PG_FUNCTION_ARGS);
 extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
 extern Datum pg_get_expr(PG_FUNCTION_ARGS);
+extern Datum pg_get_expr_ext(PG_FUNCTION_ARGS);
 extern char *deparse_expression(Node *expr, List *dpcontext,
                                   bool forceprefix, bool showimplicit);
 extern List *deparse_context_for(const char *aliasname, Oid relid);