Thread: ruleutils with pretty-print option

ruleutils with pretty-print option

From
Andreas Pflug
Date:
Is there a problem about the archive?
I posted this addition to the patch on July 2, and received it over the
patches mailing list. Still, it doesn't appear in cvs, in "unapplied
patches" or in the mailing list archive! So although that message made
its way through the list server, it didn't end up in the archive, but
was lost.

In the meantime, some changes occurred to cvs, which merged smoothly.
For convenience, the attached diffs against the latest cvs versions.

Regards,
Andreas



Previous message (2003-07-02):

The patch has been updated, the attached files will replace my previous
post completely against ruleutils.c 1.143.

pg_get_indexdef is extended to take 3 arguments:
pg_get_indexdef(index_oid, columnNr_int, prettyOpt_int)

Still, pg_get_indexdef(oid) will deliver the same result as it used to be.
The second parameter selects the nth expression of an index
(1..indnatts). If zero, a complete CREATE INDEX statement is generated
to obtain the previous behaviour.
The third is the pretty-print option as mentioned before.

example:
pg_get_indexdef(12345, 0, 7)  -> CREATE INDEX foo ON bar (numcol,
length(txtcol), intcol2, length(txtcol2))
pg_get_indexdef(12345, 1, 7)  -> numcol
pg_get_indexdef(12345, 2, 7)  -> length(txtcol)

Regards,
Andreas

> The attached patches will add
>    pg_get_ruledef(oid, int)
>    pg_get_viewdef(text, int)
>    pg_get_viewdef(oid, int)
>    pg_get_indexdef(oid, int)
>    pg_get_constraintdef(oid, int)
>    pg_get_expr(text, oid, int)
>
> If the last parameter "pretty-print" is 0, these function will return
> the same result as their original counterparts without that parameter.
> The source is based on ruleutils.c 1.143, and should return exactly
> the same result as before if no pretty-print is selected. My tests
> didn't show any differences for pg_dump output with old or new version.
>
> The pretty-print parameter is evaluated bit-wise.
>
> PRETTY_PAREN      1 - Parentheses are checked; only necessary
> parentheses will be emitted.
>
> PRETTY_INDENT     2 - pretty indentation and line formatting is performed
>
> PRETTY_OPPAREN    4 - For T_BoolExpr operators, AND/OR/NOT precedence
> is checked, for T_OpExpr +-*/%                      precedence is
> checked. If precedence is identified, parentheses are omitted.
>                      This option is only active if PRETTY_PAREN is
> also used.




Index: pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
retrieving revision 1.309
diff -c -r1.309 pg_proc.h
*** pg_proc.h    1 Jul 2003 00:04:38 -0000    1.309
--- pg_proc.h    6 Jul 2003 10:08:23 -0000
***************
*** 3405,3410 ****
--- 3405,3424 ----
  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 23"  pg_get_ruledef - _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 23"  pg_get_viewdef_name - _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 23"  pg_get_viewdef - _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 23"  pg_get_indexdef - _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 23"  pg_get_constraintdef - _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 23"    pg_get_expr - _null_ ));
+ DESCR("deparse an encoded expression with pretty-print option");
+

  /*
   * Symbolic values for provolatile column: these indicate whether the result
Index: ruleutils.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.145
diff -c -r1.145 ruleutils.c
*** ruleutils.c    4 Jul 2003 02:51:34 -0000    1.145
--- ruleutils.c    6 Jul 2003 10:09:51 -0000
***************
*** 71,76 ****
--- 71,97 ----
  #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
+ #define PRETTYFLAG_OPPAREN      4
+
+ /* macro to test if pretty action needed */
+ #define PRETTY_PAREN(context)   (context->prettyFlags & PRETTYFLAG_PAREN)
+ #define PRETTY_INDENT(context)  (context->prettyFlags & PRETTYFLAG_INDENT)
+ #define PRETTY_OPPAREN(context) (context->prettyFlags & PRETTYFLAG_OPPAREN)
+
+
  /* ----------
   * Local data types
   * ----------
***************
*** 81,86 ****
--- 102,109 ----
  {
      StringInfo    buf;            /* output buffer to append to */
      List       *namespaces;        /* List of deparse_namespace nodes */
+         int             prettyFlags;            /* if non-zero, parentheses are minimized. */
+         int             indentLevel;            /* for prettyPrint, we perform indentation and line splitting */
      bool        varprefix;        /* TRUE to print prefixes on Vars */
  } deparse_context;

***************
*** 123,135 ****
   * as a parameter, and append their text output to its contents.
   * ----------
   */
! static text *pg_do_getviewdef(Oid viewoid);
  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 void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
!               TupleDesc resultDesc);
  static void get_select_query_def(Query *query, deparse_context *context,
                       TupleDesc resultDesc);
  static void get_insert_query_def(Query *query, deparse_context *context);
--- 146,164 ----
   * as a parameter, and append their text output to its contents.
   * ----------
   */
! static char *get_simple_binary_op_name(OpExpr *expr);
! static void appendStringInfoSpace(StringInfo buf, int count);
! static void appendContextKeyword(deparse_context *context, char *str, int indentBefore, int indentAfter, int
indentPlus);
! static char *deparse_expression_pretty(Node *expr, List *dpcontext,
!               bool forceprefix, bool showimplicit, int prettyFlags, int startIndent);
! static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
! 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, 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, 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);
***************
*** 192,197 ****
--- 221,227 ----
      TupleDesc    rulettc;
      StringInfoData buf;
      int            len;
+     int             prettyFlags = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);

      /*
       * Connect to SPI manager
***************
*** 241,247 ****
       * Get the rules definition and put it into executors memory
       */
      initStringInfo(&buf);
!     make_ruledef(&buf, ruletup, rulettc);
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
      VARATT_SIZEP(ruledef) = len;
--- 271,277 ----
       * Get the rules definition and put it into executors memory
       */
      initStringInfo(&buf);
!     make_ruledef(&buf, ruletup, rulettc, prettyFlags);
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
      VARATT_SIZEP(ruledef) = len;
***************
*** 272,279 ****
      /* By OID */
      Oid            viewoid = PG_GETARG_OID(0);
      text       *ruledef;

!     ruledef = pg_do_getviewdef(viewoid);
      PG_RETURN_TEXT_P(ruledef);
  }

--- 302,310 ----
      /* By OID */
      Oid            viewoid = PG_GETARG_OID(0);
      text       *ruledef;
+     int             prettyFlags = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);

!     ruledef = pg_do_getviewdef(viewoid, prettyFlags);
      PG_RETURN_TEXT_P(ruledef);
  }

***************
*** 285,296 ****
      RangeVar   *viewrel;
      Oid            viewoid;
      text       *ruledef;

      viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname,
                                                           "get_viewdef"));
      viewoid = RangeVarGetRelid(viewrel, false);

!     ruledef = pg_do_getviewdef(viewoid);
      PG_RETURN_TEXT_P(ruledef);
  }

--- 316,328 ----
      RangeVar   *viewrel;
      Oid            viewoid;
      text       *ruledef;
+     int             prettyFlags = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);

      viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname,
                                                           "get_viewdef"));
      viewoid = RangeVarGetRelid(viewrel, false);

!     ruledef = pg_do_getviewdef(viewoid, prettyFlags);
      PG_RETURN_TEXT_P(ruledef);
  }

***************
*** 298,304 ****
   * Common code for by-OID and by-name variants of pg_get_viewdef
   */
  static text *
! pg_do_getviewdef(Oid viewoid)
  {
      text       *ruledef;
      Datum        args[2];
--- 330,336 ----
   * Common code for by-OID and by-name variants of pg_get_viewdef
   */
  static text *
! pg_do_getviewdef(Oid viewoid, int prettyFlags)
  {
      text       *ruledef;
      Datum        args[2];
***************
*** 353,359 ****
           */
          ruletup = SPI_tuptable->vals[0];
          rulettc = SPI_tuptable->tupdesc;
!         make_viewdef(&buf, ruletup, rulettc);
      }
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
--- 385,391 ----
           */
          ruletup = SPI_tuptable->vals[0];
          rulettc = SPI_tuptable->tupdesc;
!         make_viewdef(&buf, ruletup, rulettc, prettyFlags);
      }
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
***************
*** 544,549 ****
--- 576,583 ----
      StringInfoData buf;
      char       *str;
      char       *sep;
+     int        colno = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT16(1);
+     int        prettyFlags = PG_ARGISNULL(2) ? 0 : PG_GETARG_INT32(2);

      /*
       * Fetch the pg_index tuple by the Oid of the index
***************
*** 582,587 ****
--- 616,623 ----
       * Get the index expressions, if any.  (NOTE: we do not use the relcache
       * versions of the expressions and predicate, because we want to display
       * non-const-folded expressions.)
+          * if colno == 0, we want a complete index definition.
+          * if colno > 0, we only want the nth expression.
       */
      if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
      {
***************
*** 607,613 ****
       * never be schema-qualified, but the indexed rel's name may be.
       */
      initStringInfo(&buf);
!     appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
                       idxrec->indisunique ? "UNIQUE " : "",
                       quote_identifier(NameStr(idxrelrec->relname)),
                       generate_relation_name(indrelid),
--- 643,651 ----
       * never be schema-qualified, but the indexed rel's name may be.
       */
      initStringInfo(&buf);
!
!     if (!colno)
!         appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
                       idxrec->indisunique ? "UNIQUE " : "",
                       quote_identifier(NameStr(idxrelrec->relname)),
                       generate_relation_name(indrelid),
***************
*** 621,627 ****
      {
          AttrNumber    attnum = idxrec->indkey[keyno];

!         appendStringInfo(&buf, sep);
          sep = ", ";

          if (attnum != 0)
--- 659,666 ----
      {
          AttrNumber    attnum = idxrec->indkey[keyno];

!         if (!colno)
!             appendStringInfo(&buf, sep);
          sep = ", ";

          if (attnum != 0)
***************
*** 630,636 ****
              char       *attname;

              attname = get_relid_attribute_name(indrelid, attnum);
!             appendStringInfo(&buf, "%s", quote_identifier(attname));
              keycoltype = get_atttype(indrelid, attnum);
          }
          else
--- 669,676 ----
              char       *attname;

              attname = get_relid_attribute_name(indrelid, attnum);
!             if (!colno || colno == keyno+1)
!                 appendStringInfo(&buf, "%s", quote_identifier(attname));
              keycoltype = get_atttype(indrelid, attnum);
          }
          else
***************
*** 643,672 ****
              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);
              keycoltype = exprType(indexkey);
          }

          /*
           * Add the operator class name
           */
!         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))
      {
          Node       *node;
          Datum        predDatum;
          bool        isnull;
--- 683,718 ----
              indexkey = (Node *) lfirst(indexprs);
              indexprs = lnext(indexprs);
              /* Deparse */
!             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
           */
!         if (!colno)
!             get_opclass_name(idxrec->indclass[keyno], keycoltype,
                           &buf);
      }

!     if (!colno)
      {
+         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;
***************
*** 689,698 ****
          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);
      }
-
      /*
       * Create the result as a TEXT datum, and free working data
       */
--- 735,744 ----
          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);
+         }
      }
      /*
       * Create the result as a TEXT datum, and free working data
       */
***************
*** 729,734 ****
--- 775,781 ----
      ScanKeyData skey[1];
      HeapTuple    tup;
      Form_pg_constraint conForm;
+     int             prettyFlags = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);

      /*
       * Fetch the pg_constraint row.  There's no syscache for pg_constraint
***************
*** 934,940 ****
                      context = deparse_context_for(get_typname(conForm->contypid),
                                                    InvalidOid);

!                 consrc = deparse_expression(expr, context, false, false);

                  /* Append the constraint source */
                  appendStringInfoString(&buf, consrc);
--- 981,987 ----
                      context = deparse_context_for(get_typname(conForm->contypid),
                                                    InvalidOid);

!                 consrc = deparse_expression_pretty(expr, context, false, false, prettyFlags, 0);

                  /* Append the constraint source */
                  appendStringInfoString(&buf, consrc);
***************
*** 1018,1023 ****
--- 1065,1071 ----
      char       *exprstr;
      char       *relname;
      char       *str;
+     int             prettyFlags = PG_ARGISNULL(2) ? 0 : PG_GETARG_INT32(2);

      /* Get the name for the relation */
      relname = get_rel_name(relid);
***************
*** 1041,1047 ****

      /* Deparse */
      context = deparse_context_for(relname, relid);
!     str = deparse_expression(node, context, false, false);

      /* Pass the result back as TEXT */
      result = DatumGetTextP(DirectFunctionCall1(textin,
--- 1089,1095 ----

      /* Deparse */
      context = deparse_context_for(relname, relid);
!     str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0);

      /* Pass the result back as TEXT */
      result = DatumGetTextP(DirectFunctionCall1(textin,
***************
*** 1090,1095 ****
--- 1138,1154 ----

  /* ----------
   * 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).
***************
*** 1100,1112 ****
   * 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.
   *
   * The result is a palloc'd string.
   * ----------
   */
  char *
! deparse_expression(Node *expr, List *dpcontext,
!                    bool forceprefix, bool showimplicit)
  {
      StringInfoData buf;
      deparse_context context;
--- 1159,1173 ----
   * 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
   *
   * The result is a palloc'd string.
   * ----------
   */
  char *
! deparse_expression_pretty(Node *expr, List *dpcontext,
!                    bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
  {
      StringInfoData buf;
      deparse_context context;
***************
*** 1115,1120 ****
--- 1176,1183 ----
      context.buf = &buf;
      context.namespaces = dpcontext;
      context.varprefix = forceprefix;
+     context.prettyFlags = prettyFlags;
+     context.indentLevel = startIndent;

      get_rule_expr(expr, &context, showimplicit);

***************
*** 1267,1273 ****
   * ----------
   */
  static void
! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
  {
      char       *rulename;
      char        ev_type;
--- 1330,1336 ----
   * ----------
   */
  static void
! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
  {
      char       *rulename;
      char        ev_type;
***************
*** 1321,1329 ****
      /*
       * Build the rules definition text
       */
!     appendStringInfo(buf, "CREATE RULE %s AS ON ",
                       quote_identifier(rulename));

      /* The event the rule is fired for */
      switch (ev_type)
      {
--- 1384,1397 ----
      /*
       * Build the rules definition text
       */
!     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)
      {
***************
*** 1366,1371 ****
--- 1434,1441 ----
          deparse_context context;
          deparse_namespace dpns;

+         if (prettyFlags & PRETTYFLAG_INDENT)
+             appendStringInfoString(buf, "\n  ");
          appendStringInfo(buf, " WHERE ");

          qual = stringToNode(ev_qual);
***************
*** 1387,1392 ****
--- 1457,1464 ----
          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;
***************
*** 1410,1417 ****
          foreach(action, actions)
          {
              query = (Query *) lfirst(action);
!             get_query_def(query, buf, NIL, NULL);
!             appendStringInfo(buf, "; ");
          }
          appendStringInfo(buf, ");");
      }
--- 1482,1492 ----
          foreach(action, actions)
          {
              query = (Query *) lfirst(action);
!             get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
!             if (prettyFlags)
!                 appendStringInfo(buf, ";\n");
!             else
!                 appendStringInfo(buf, "; ");
          }
          appendStringInfo(buf, ");");
      }
***************
*** 1424,1430 ****
          Query       *query;

          query = (Query *) lfirst(actions);
!         get_query_def(query, buf, NIL, NULL);
          appendStringInfo(buf, ";");
      }
  }
--- 1499,1505 ----
          Query       *query;

          query = (Query *) lfirst(actions);
!         get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
          appendStringInfo(buf, ";");
      }
  }
***************
*** 1436,1442 ****
   * ----------
   */
  static void
! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
  {
      Query       *query;
      char        ev_type;
--- 1511,1517 ----
   * ----------
   */
  static void
! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
  {
      Query       *query;
      char        ev_type;
***************
*** 1490,1496 ****

      ev_relation = heap_open(ev_class, AccessShareLock);

!     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation));
      appendStringInfo(buf, ";");

      heap_close(ev_relation, AccessShareLock);
--- 1565,1571 ----

      ev_relation = heap_open(ev_class, AccessShareLock);

!     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), prettyFlags, 0);
      appendStringInfo(buf, ";");

      heap_close(ev_relation, AccessShareLock);
***************
*** 1506,1512 ****
   */
  static void
  get_query_def(Query *query, StringInfo buf, List *parentnamespace,
!               TupleDesc resultDesc)
  {
      deparse_context context;
      deparse_namespace dpns;
--- 1581,1587 ----
   */
  static void
  get_query_def(Query *query, StringInfo buf, List *parentnamespace,
!               TupleDesc resultDesc, int prettyFlags, int startIndent)
  {
      deparse_context context;
      deparse_namespace dpns;
***************
*** 1515,1520 ****
--- 1590,1598 ----
      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;
***************
*** 1586,1592 ****
      /* Add the ORDER BY clause if given */
      if (query->sortClause != NIL)
      {
!         appendStringInfo(buf, " ORDER BY ");
          sep = "";
          foreach(l, query->sortClause)
          {
--- 1664,1670 ----
      /* Add the ORDER BY clause if given */
      if (query->sortClause != NIL)
      {
!             appendContextKeyword(context, " ORDER BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          sep = "";
          foreach(l, query->sortClause)
          {
***************
*** 1615,1626 ****
      /* Add the LIMIT clause if given */
      if (query->limitOffset != NULL)
      {
!         appendStringInfo(buf, " OFFSET ");
          get_rule_expr(query->limitOffset, context, false);
      }
      if (query->limitCount != NULL)
      {
!         appendStringInfo(buf, " LIMIT ");
          if (IsA(query->limitCount, Const) &&
              ((Const *) query->limitCount)->constisnull)
              appendStringInfo(buf, "ALL");
--- 1693,1704 ----
      /* Add the LIMIT clause if given */
      if (query->limitOffset != NULL)
      {
!         appendContextKeyword(context, " OFFSET ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
          get_rule_expr(query->limitOffset, context, false);
      }
      if (query->limitCount != NULL)
      {
!         appendContextKeyword(context, " LIMIT ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
          if (IsA(query->limitCount, Const) &&
              ((Const *) query->limitCount)->constisnull)
              appendStringInfo(buf, "ALL");
***************
*** 1641,1646 ****
--- 1719,1729 ----
      /*
       * 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 */
***************
*** 1720,1733 ****
      /* Add the WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendStringInfo(buf, " WHERE ");
          get_rule_expr(query->jointree->quals, context, false);
      }

      /* Add the GROUP BY clause if given */
      if (query->groupClause != NULL)
      {
!         appendStringInfo(buf, " GROUP BY ");
          sep = "";
          foreach(l, query->groupClause)
          {
--- 1803,1816 ----
      /* Add the WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         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)
      {
!         appendContextKeyword(context, " GROUP BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          sep = "";
          foreach(l, query->groupClause)
          {
***************
*** 1743,1749 ****
      /* Add the HAVING clause if given */
      if (query->havingQual != NULL)
      {
!         appendStringInfo(buf, " HAVING ");
          get_rule_expr(query->havingQual, context, false);
      }
  }
--- 1826,1832 ----
      /* Add the HAVING clause if given */
      if (query->havingQual != NULL)
      {
!         appendContextKeyword(context, " HAVING ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
          get_rule_expr(query->havingQual, context, false);
      }
  }
***************
*** 1761,1795 ****
          Query       *subquery = rte->subquery;

          Assert(subquery != NULL);
!         get_query_def(subquery, buf, context->namespaces, resultDesc);
      }
      else if (IsA(setOp, SetOperationStmt))
      {
          SetOperationStmt *op = (SetOperationStmt *) setOp;

-         appendStringInfo(buf, "((");
          get_setop_query(op->larg, query, context, resultDesc);
          switch (op->op)
          {
              case SETOP_UNION:
!                 appendStringInfo(buf, ") UNION ");
                  break;
              case SETOP_INTERSECT:
!                 appendStringInfo(buf, ") INTERSECT ");
                  break;
              case SETOP_EXCEPT:
!                 appendStringInfo(buf, ") EXCEPT ");
                  break;
              default:
                  elog(ERROR, "get_setop_query: unexpected set op %d",
                       (int) op->op);
          }
          if (op->all)
!             appendStringInfo(buf, "ALL (");
          else
!             appendStringInfo(buf, "(");
          get_setop_query(op->rarg, query, context, resultDesc);
!         appendStringInfo(buf, "))");
      }
      else
      {
--- 1844,1907 ----
          Query       *subquery = rte->subquery;

          Assert(subquery != NULL);
!         get_query_def(subquery, buf, context->namespaces, resultDesc, context->prettyFlags, context->indentLevel);
      }
      else if (IsA(setOp, SetOperationStmt))
      {
          SetOperationStmt *op = (SetOperationStmt *) setOp;
+         bool need_paren=(PRETTY_PAREN(context) ? !IsA(op->rarg, RangeTblRef) : true);
+
+         if (!PRETTY_PAREN(context))
+             appendStringInfoString(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:
!                 appendContextKeyword(context, "UNION ", -PRETTYINDENT_STD, 0, 0);
                  break;
              case SETOP_INTERSECT:
!                 appendContextKeyword(context, "INTERSECT ", -PRETTYINDENT_STD, 0, 0);
                  break;
              case SETOP_EXCEPT:
!                 appendContextKeyword(context, "EXCEPT ", -PRETTYINDENT_STD, 0, 0);
                  break;
              default:
                  elog(ERROR, "get_setop_query: unexpected set op %d",
                       (int) op->op);
          }
          if (op->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
!             appendStringInfoChar(buf, '(');
!
          get_setop_query(op->rarg, query, context, resultDesc);
!
!         if (PRETTY_PAREN(context))
!         {
!             if (need_paren)
!             appendStringInfoChar(buf, ')');
!         }
!         else
!             appendStringInfoString(buf, "))");
      }
      else
      {
***************
*** 1862,1867 ****
--- 1974,1985 ----
       */
      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));

***************
*** 1883,1889 ****
      /* Add the VALUES or the SELECT */
      if (select_rte == NULL)
      {
!         appendStringInfo(buf, "VALUES (");
          sep = "";
          foreach(l, query->targetList)
          {
--- 2001,2007 ----
      /* Add the VALUES or the SELECT */
      if (select_rte == NULL)
      {
!         appendContextKeyword(context, "VALUES (", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
          sep = "";
          foreach(l, query->targetList)
          {
***************
*** 1899,1905 ****
          appendStringInfoChar(buf, ')');
      }
      else
!         get_query_def(select_rte->subquery, buf, NIL, NULL);
  }


--- 2017,2023 ----
          appendStringInfoChar(buf, ')');
      }
      else
!         get_query_def(select_rte->subquery, buf, NIL, NULL, context->prettyFlags, context->indentLevel);
  }


***************
*** 1920,1925 ****
--- 2038,2048 ----
       */
      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));
***************
*** 1953,1959 ****
      /* Finally add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendStringInfo(buf, " WHERE ");
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
--- 2076,2082 ----
      /* Finally add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
***************
*** 1974,1979 ****
--- 2097,2107 ----
       */
      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));
***************
*** 1981,1987 ****
      /* Add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendStringInfo(buf, " WHERE ");
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
--- 2109,2115 ----
      /* Add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
***************
*** 2000,2005 ****
--- 2128,2134 ----
      {
          NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;

+         appendContextKeyword(context, "", 0, PRETTYINDENT_STD, 1);
          appendStringInfo(buf, "NOTIFY %s",
                     quote_qualified_identifier(stmt->relation->schemaname,
                                                stmt->relation->relname));
***************
*** 2140,2145 ****
--- 2269,2510 ----
  }


+ /********************************************
+  * get_simple_binary_op_name
+  * helper function for isSimpleNode
+  * will return single char binary operator
+  *******************************************/
+
+ static 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);
+         char *op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
+
+         if (strlen(op) == 1)
+             return op;
+     }
+     return 0;
+ }
+
+
+ /***************************************
+  * check if given node is simple.
+  *  false  : not simple
+  *  true   : simple in the context of parent node's type
+  ***************************************/
+
+ static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
+ {
+     if (!node)
+     return true;
+
+     switch (nodeTag(node))
+     {
+     // single words: always simple
+     case T_Var:
+     case T_Const:
+     case T_Param:
+
+     // function-like: name(..) or name[..]
+     case T_ArrayRef:
+     case T_ArrayExpr:
+     case T_CoalesceExpr:
+     case T_NullIfExpr:
+     case T_Aggref:
+     case T_FuncExpr:
+
+         // CASE keywords act as parentheses
+     case T_CaseExpr:
+         return true;
+
+         // appears simple since . has top precedence, unless parent is T_FieldSelect itself!
+     case T_FieldSelect:
+         return (nodeTag(parentNode) == T_FieldSelect ? false : true);
+
+
+         // maybe simple, check args
+     case T_CoerceToDomain:
+         return isSimpleNode((Node*) ((CoerceToDomain*)node)->arg, node, prettyFlags);
+     case T_RelabelType:
+         return isSimpleNode((Node*) ((RelabelType*)node)->arg, node, prettyFlags);
+
+
+     // depends on parent node type; needs further checking
+     case T_OpExpr:
+     {
+         if (prettyFlags & PRETTYFLAG_OPPAREN && nodeTag(parentNode) == T_OpExpr)
+         {
+         char *op=get_simple_binary_op_name((OpExpr*)node);
+         char *parentOp=get_simple_binary_op_name((OpExpr*)parentNode);
+         if (!op || !parentOp)
+             return false;
+
+                 // we know only these basic operators
+         if (!strchr("+-*/%", *op) || !strchr("+-*/%", *parentOp))
+             return false;
+
+         // natural operator precedence, so we don't need parentheses
+         if (strchr("*/%", *op) || strchr("+-", *parentOp))
+             return true;
+
+         return false;
+         }
+             // else do the same stuff as for T_SubLink et al.
+     }
+     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_OPPAREN)
+             {
+             BoolExprType type=((BoolExpr*)node)->boolop;
+             BoolExprType 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;
+         }
+         // these are not completely implemented; so far, they're simple
+     case T_SubPlan:
+     case T_CoerceToDomainValue:
+         return true;
+
+     case T_ScalarArrayOpExpr:
+         // need to check
+     default:
+         break;
+     }
+     // those we don't know: in dubio complexo
+     return false;
+ }
+
+
+ /******************************************
+  * appendContextKeyword
+  * append spaces to buffer
+  ******************************************/
+ static void appendStringInfoSpace(StringInfo buf, int count)
+ {
+     while (count-- > 0)
+     appendStringInfoChar(buf, ' ');
+ }
+
+ /******************************************
+  * appendContextKeyword
+  * performing a line break, and indentation
+  * if prettyPrint is enabled.
+  * Otherwise, only the keyword is appended
+  *****************************************/
+
+ static void appendContextKeyword(deparse_context *context, 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');
+     appendStringInfoSpace(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  - parsing expr using get_rule_expr,
+  * embracing the string with parentheses if necessary for prettyPrint.
+  * never embracing 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 = 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
   *
***************
*** 2294,2305 ****
                  List       *args = expr->args;
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);
!
!                 appendStringInfoChar(buf, '(');
!                 get_rule_expr(arg1, context, true);
                  appendStringInfo(buf, " IS DISTINCT FROM ");
!                 get_rule_expr(arg2, context, true);
!                 appendStringInfoChar(buf, ')');
              }
              break;

--- 2659,2671 ----
                  List       *args = expr->args;
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, '(');
!                 get_rule_expr_paren(arg1, context, true, node);
                  appendStringInfo(buf, " IS DISTINCT FROM ");
!                 get_rule_expr_paren(arg2, context, true, node);
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, ')');
              }
              break;

***************
*** 2310,2324 ****
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);

!                 appendStringInfoChar(buf, '(');
!                 get_rule_expr(arg1, context, true);
                  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, "))");
              }
              break;

--- 2676,2694 ----
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);

!                 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_paren(arg2, context, true, node);
!                 appendStringInfoString(buf, ")");
!
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, ')');
              }
              break;

***************
*** 2330,2362 ****
                  switch (expr->boolop)
                  {
                      case AND_EXPR:
!                         appendStringInfoChar(buf, '(');
!                         get_rule_expr((Node *) lfirst(args), context, false);
                          while ((args = lnext(args)) != NIL)
                          {
                              appendStringInfo(buf, " AND ");
!                             get_rule_expr((Node *) lfirst(args), context,
!                                           false);
                          }
!                         appendStringInfoChar(buf, ')');
                          break;

                      case OR_EXPR:
!                         appendStringInfoChar(buf, '(');
!                         get_rule_expr((Node *) lfirst(args), context, false);
                          while ((args = lnext(args)) != NIL)
                          {
                              appendStringInfo(buf, " OR ");
!                             get_rule_expr((Node *) lfirst(args), context,
!                                           false);
                          }
!                         appendStringInfoChar(buf, ')');
                          break;

                      case NOT_EXPR:
!                         appendStringInfo(buf, "(NOT ");
!                         get_rule_expr((Node *) lfirst(args), context, false);
!                         appendStringInfoChar(buf, ')');
                          break;

                      default:
--- 2700,2739 ----
                  switch (expr->boolop)
                  {
                      case AND_EXPR:
!                             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_paren((Node *) lfirst(args), context,
!                                           false, node);
                          }
!                             if (!PRETTY_PAREN(context))
!                             appendStringInfoChar(buf, ')');
                          break;

                      case OR_EXPR:
!                             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_paren((Node *) lfirst(args), context,
!                                           false, node);
                          }
!                             if (!PRETTY_PAREN(context))
!                             appendStringInfoChar(buf, ')');
                          break;

                      case NOT_EXPR:
!                             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:
***************
*** 2404,2412 ****
                   * 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));
              }
              break;

--- 2781,2792 ----
                   * arg.fieldname, but most cases where FieldSelect is used
                   * are *not* simple.  So, always use parenthesized syntax.
                   */
!                     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;

***************
*** 2419,2425 ****
                      !showimplicit)
                  {
                      /* don't show the implicit cast */
!                     get_rule_expr(arg, context, showimplicit);
                  }
                  else
                  {
--- 2799,2805 ----
                      !showimplicit)
                  {
                      /* don't show the implicit cast */
!                     get_rule_expr_paren(arg, context, showimplicit, node);
                  }
                  else
                  {
***************
*** 2431,2439 ****
                       */
                      arg = strip_type_coercion(arg, relabel->resulttype);

!                     appendStringInfoChar(buf, '(');
!                     get_rule_expr(arg, context, showimplicit);
!                     appendStringInfo(buf, ")::%s",
                              format_type_with_typemod(relabel->resulttype,
                                                       relabel->resulttypmod));
                  }
--- 2811,2823 ----
                       */
                      arg = strip_type_coercion(arg, relabel->resulttype);

!                     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));
                  }
***************
*** 2445,2463 ****
                  CaseExpr   *caseexpr = (CaseExpr *) node;
                  List       *temp;

!                 appendStringInfo(buf, "CASE");
                  foreach(temp, caseexpr->args)
                  {
                      CaseWhen   *when = (CaseWhen *) lfirst(temp);

!                     appendStringInfo(buf, " WHEN ");
                      get_rule_expr((Node *) when->expr, context, false);
                      appendStringInfo(buf, " THEN ");
                      get_rule_expr((Node *) when->result, context, true);
                  }
!                 appendStringInfo(buf, " ELSE ");
                  get_rule_expr((Node *) caseexpr->defresult, context, true);
!                 appendStringInfo(buf, " END");
              }
              break;

--- 2829,2855 ----
                  CaseExpr   *caseexpr = (CaseExpr *) node;
                  List       *temp;

!                 appendContextKeyword(context, "CASE", 0, PRETTYINDENT_VAR, 0);
                  foreach(temp, caseexpr->args)
                  {
                      CaseWhen   *when = (CaseWhen *) lfirst(temp);

!                     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);
                  }
!                 if (!PRETTY_INDENT(context))
!                     appendStringInfoChar(buf, ' ');
!                 appendContextKeyword(context, "ELSE ", 0, 0, 0);
                  get_rule_expr((Node *) caseexpr->defresult, context, true);
!                 if (!PRETTY_INDENT(context))
!                     appendStringInfoChar(buf, ' ');
!                 appendContextKeyword(context, "END", -PRETTYINDENT_VAR, 0, 0);
              }
              break;

***************
*** 2525,2544 ****
              {
                  NullTest   *ntest = (NullTest *) node;

!                 appendStringInfo(buf, "(");
!                 get_rule_expr((Node *) ntest->arg, context, true);
                  switch (ntest->nulltesttype)
                  {
                      case IS_NULL:
!                         appendStringInfo(buf, " IS NULL)");
                          break;
                      case IS_NOT_NULL:
!                         appendStringInfo(buf, " IS NOT NULL)");
                          break;
                      default:
                          elog(ERROR, "get_rule_expr: unexpected nulltesttype %d",
                               (int) ntest->nulltesttype);
                  }
              }
              break;

--- 2917,2939 ----
              {
                  NullTest   *ntest = (NullTest *) node;

!                 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");
                          break;
                      case IS_NOT_NULL:
!                         appendStringInfo(buf, " IS NOT NULL");
                          break;
                      default:
                          elog(ERROR, "get_rule_expr: unexpected nulltesttype %d",
                               (int) ntest->nulltesttype);
                  }
+                 if (!PRETTY_PAREN(context))
+                     appendStringInfoChar(buf, ')');
              }
              break;

***************
*** 2546,2577 ****
              {
                  BooleanTest *btest = (BooleanTest *) node;

!                 appendStringInfo(buf, "(");
!                 get_rule_expr((Node *) btest->arg, context, false);
                  switch (btest->booltesttype)
                  {
                      case IS_TRUE:
!                         appendStringInfo(buf, " IS TRUE)");
                          break;
                      case IS_NOT_TRUE:
!                         appendStringInfo(buf, " IS NOT TRUE)");
                          break;
                      case IS_FALSE:
!                         appendStringInfo(buf, " IS FALSE)");
                          break;
                      case IS_NOT_FALSE:
!                         appendStringInfo(buf, " IS NOT FALSE)");
                          break;
                      case IS_UNKNOWN:
!                         appendStringInfo(buf, " IS UNKNOWN)");
                          break;
                      case IS_NOT_UNKNOWN:
!                         appendStringInfo(buf, " IS NOT UNKNOWN)");
                          break;
                      default:
                          elog(ERROR, "get_rule_expr: unexpected booltesttype %d",
                               (int) btest->booltesttype);
                  }
              }
              break;

--- 2941,2975 ----
              {
                  BooleanTest *btest = (BooleanTest *) node;

!                 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");
                          break;
                      case IS_NOT_TRUE:
!                         appendStringInfo(buf, " IS NOT TRUE");
                          break;
                      case IS_FALSE:
!                         appendStringInfo(buf, " IS FALSE");
                          break;
                      case IS_NOT_FALSE:
!                         appendStringInfo(buf, " IS NOT FALSE");
                          break;
                      case IS_UNKNOWN:
!                         appendStringInfo(buf, " IS UNKNOWN");
                          break;
                      case IS_NOT_UNKNOWN:
!                         appendStringInfo(buf, " IS NOT UNKNOWN");
                          break;
                      default:
                          elog(ERROR, "get_rule_expr: unexpected booltesttype %d",
                               (int) btest->booltesttype);
                  }
+                 if (!PRETTY_PAREN(context))
+                     appendStringInfoChar(buf, ')');
              }
              break;

***************
*** 2593,2601 ****
                  }
                  else
                  {
!                     appendStringInfoChar(buf, '(');
!                     get_rule_expr(arg, context, false);
!                     appendStringInfo(buf, ")::%s",
                              format_type_with_typemod(ctest->resulttype,
                                                       ctest->resulttypmod));
                  }
--- 2991,3004 ----
                  }
                  else
                  {
!                     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));
                  }
***************
*** 2627,2645 ****
      Oid            opno = expr->opno;
      List       *args = expr->args;

!     appendStringInfoChar(buf, '(');
      if (length(args) == 2)
      {
          /* binary operator */
          Node       *arg1 = (Node *) lfirst(args);
          Node       *arg2 = (Node *) lsecond(args);
!
!         get_rule_expr(arg1, context, true);
          appendStringInfo(buf, " %s ",
                           generate_operator_name(opno,
                                                  exprType(arg1),
                                                  exprType(arg2)));
!         get_rule_expr(arg2, context, true);
      }
      else
      {
--- 3030,3048 ----
      Oid            opno = expr->opno;
      List       *args = expr->args;

!     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_paren(arg1, context, true, (Node*)expr);
          appendStringInfo(buf, " %s ",
                           generate_operator_name(opno,
                                                  exprType(arg1),
                                                  exprType(arg2)));
!         get_rule_expr_paren(arg2, context, true, (Node*)expr);
      }
      else
      {
***************
*** 2661,2670 ****
                                   generate_operator_name(opno,
                                                          InvalidOid,
                                                          exprType(arg)));
!                 get_rule_expr(arg, context, true);
                  break;
              case 'r':
!                 get_rule_expr(arg, context, true);
                  appendStringInfo(buf, " %s",
                                   generate_operator_name(opno,
                                                          exprType(arg),
--- 3064,3073 ----
                                   generate_operator_name(opno,
                                                          InvalidOid,
                                                          exprType(arg)));
!                 get_rule_expr_paren(arg, context, true, (Node*)expr);
                  break;
              case 'r':
!                 get_rule_expr_paren(arg, context, true, (Node*)expr);
                  appendStringInfo(buf, " %s",
                                   generate_operator_name(opno,
                                                          exprType(arg),
***************
*** 2675,2681 ****
          }
          ReleaseSysCache(tp);
      }
!     appendStringInfoChar(buf, ')');
  }

  /*
--- 3078,3085 ----
          }
          ReleaseSysCache(tp);
      }
!     if (!PRETTY_PAREN(context))
!         appendStringInfoChar(buf, ')');
  }

  /*
***************
*** 2698,2704 ****
       */
      if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
      {
!         get_rule_expr((Node *) lfirst(expr->args), context, showimplicit);
          return;
      }

--- 3102,3108 ----
       */
      if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
      {
!         get_rule_expr_paren((Node *) lfirst(expr->args), context, showimplicit, (Node*)expr);
          return;
      }

***************
*** 2724,2732 ****
           */
          arg = strip_type_coercion(arg, rettype);

!         appendStringInfoChar(buf, '(');
!         get_rule_expr(arg, context, showimplicit);
!         appendStringInfo(buf, ")::%s",
                           format_type_with_typemod(rettype, coercedTypmod));

          return;
--- 3128,3141 ----
           */
          arg = strip_type_coercion(arg, rettype);

!         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;
***************
*** 3047,3053 ****
      if (need_paren)
          appendStringInfoChar(buf, '(');

!     get_query_def(query, buf, context->namespaces, NULL);

      if (need_paren)
          appendStringInfo(buf, "))");
--- 3456,3462 ----
      if (need_paren)
          appendStringInfoChar(buf, '(');

!     get_query_def(query, buf, context->namespaces, NULL, context->prettyFlags, context->indentLevel);

      if (need_paren)
          appendStringInfo(buf, "))");
***************
*** 3064,3070 ****
  get_from_clause(Query *query, deparse_context *context)
  {
      StringInfo    buf = context->buf;
!     char       *sep;
      List       *l;

      /*
--- 3473,3479 ----
  get_from_clause(Query *query, deparse_context *context)
  {
      StringInfo    buf = context->buf;
!     char       *sep=0;
      List       *l;

      /*
***************
*** 3074,3080 ****
       * sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW
       * and OLD.
       */
-     sep = " FROM ";

      foreach(l, query->jointree->fromlist)
      {
--- 3483,3488 ----
***************
*** 3093,3099 ****
                  continue;
          }

!         appendStringInfo(buf, sep);
          get_from_clause_item(jtnode, query, context);
          sep = ", ";
      }
--- 3501,3511 ----
                  continue;
          }

!         if (!sep)
!             appendContextKeyword(context, " FROM ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
!         else
!             appendStringInfo(buf, sep);
!
          get_from_clause_item(jtnode, query, context);
          sep = ", ";
      }
***************
*** 3122,3128 ****
              case RTE_SUBQUERY:
                  /* Subquery RTE */
                  appendStringInfoChar(buf, '(');
!                 get_query_def(rte->subquery, buf, context->namespaces, NULL);
                  appendStringInfoChar(buf, ')');
                  break;
              case RTE_FUNCTION:
--- 3534,3541 ----
              case RTE_SUBQUERY:
                  /* Subquery RTE */
                  appendStringInfoChar(buf, '(');
!                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
!                           context->prettyFlags, context->indentLevel);
                  appendStringInfoChar(buf, ')');
                  break;
              case RTE_FUNCTION:
***************
*** 3144,3150 ****
              {
                  List       *col;

!                 appendStringInfo(buf, "(");
                  foreach(col, rte->alias->colnames)
                  {
                      if (col != rte->alias->colnames)
--- 3557,3563 ----
              {
                  List       *col;

!                 appendStringInfoChar(buf, '(');
                  foreach(col, rte->alias->colnames)
                  {
                      if (col != rte->alias->colnames)
***************
*** 3178,3213 ****
      else if (IsA(jtnode, JoinExpr))
      {
          JoinExpr   *j = (JoinExpr *) jtnode;

-         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, "get_from_clause_item: unknown join type %d",
                       (int) j->jointype);
          }
          get_from_clause_item(j->rarg, query, context);
          if (!j->isNatural)
          {
              if (j->using)
--- 3591,3668 ----
      else if (IsA(jtnode, JoinExpr))
      {
          JoinExpr   *j = (JoinExpr *) jtnode;
+         bool need_paren_on_right = PRETTY_PAREN(context) && !IsA(j->rarg, RangeTblRef);
+
+         if (!PRETTY_PAREN(context) || j->alias != NULL)
+             appendStringInfoChar(buf, '(');

          get_from_clause_item(j->larg, query, context);
+
          if (j->isNatural)
          {
+             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, "get_from_clause_item: unknown 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, "get_from_clause_item: unknown 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)
***************
*** 3226,3237 ****
              }
              else if (j->quals)
              {
!                 appendStringInfo(buf, " ON (");
                  get_rule_expr(j->quals, context, false);
!                 appendStringInfoChar(buf, ')');
              }
          }
!         appendStringInfoChar(buf, ')');
          /* Yes, it's correct to put alias after the right paren ... */
          if (j->alias != NULL)
          {
--- 3681,3697 ----
              }
              else if (j->quals)
              {
!                 appendStringInfo(buf, " ON ");
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, '(');
                  get_rule_expr(j->quals, context, false);
!                 if (!PRETTY_PAREN(context))
!                     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)
          {
***************
*** 3241,3247 ****
              {
                  List       *col;

!                 appendStringInfo(buf, "(");
                  foreach(col, j->alias->colnames)
                  {
                      if (col != j->alias->colnames)
--- 3701,3707 ----
              {
                  List       *col;

!                 appendStringInfoChar(buf, '(');
                  foreach(col, j->alias->colnames)
                  {
                      if (col != j->alias->colnames)

Re: ruleutils with pretty-print option

From
Andreas Pflug
Date:
Hi Bruce,
so here's the complete patch against the current cvs.

Description:
The attached patches will add
   pg_get_ruledef(oid, bool)
   pg_get_viewdef(text, bool)
   pg_get_viewdef(oid, bool)
   pg_get_indexdef(oid, int4, bool)
   pg_get_constraintdef(oid, bool)
   pg_get_expr(text, oid, bool)

If the last parameter "pretty-print" is false, these function will
return the same result as their original counterparts without that
parameter. The source is based on ruleutils.c 1.145 and pg_proc 1.309,
and should return exactly the same result as before if no pretty-print
is selected. My tests didn't show any differences for pg_dump output
with old or new version.

If the last parameter "pretty-print" is true, parentheses are checked;
only necessary parentheses will be emitted. Additionally, line and
indentation formatting is performed.

pg_get_indexdef has one additional parameter. The second parameter
(int4) selects the nth expression of an index (1..indnatts). If zero, a
complete CREATE INDEX statement is generated to obtain the previous
behaviour.
The third is the pretty-print option as described.

example:
pg_get_indexdef(12345, 0, true)  -> CREATE INDEX foo ON bar (numcol,
length(txtcol), intcol2, (8+length(txtcol2)))
pg_get_indexdef(12345, 1, true)  -> numcol
pg_get_indexdef(12345, 2, true)  -> length(txtcol)
pg_get_indexdef(12345, 3, true)  -> intcol2
pg_get_indexdef(12345, 4, true)  -> (8+length(txtcol2))

Regards,
Andreas

Index: pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
retrieving revision 1.309
diff -r1.309 pg_proc.h
3407a3408,3421
> /* 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 - _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 - _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 - _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 - _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 - _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 - _null_ ));
> DESCR("deparse an encoded expression with pretty-print option");
>
Index: ruleutils.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.145
diff -r1.145 ruleutils.c
73a74,92
> /******************************
>  * 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)
>
>
83a103,104
>         int             prettyFlags;            /* enabling/disabling of pretty-print functions */
>         int             indentLevel;            /* for prettyPrint, current space indents are counted */
126c147,153
< static text *pg_do_getviewdef(Oid viewoid);
---
> static char *get_simple_binary_op_name(OpExpr *expr);
> static void appendStringInfoSpace(StringInfo buf, int count);
> static void appendContextKeyword(deparse_context *context, char *str, int indentBefore, int indentAfter, int
indentPlus);
> static char *deparse_expression_pretty(Node *expr, List *dpcontext,
>               bool forceprefix, bool showimplicit, int prettyFlags, int startIndent);
> static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
> static text *pg_do_getviewdef(Oid viewoid, int prettyFlags);
129,130c156,157
< static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
< static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
---
> static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags);
> static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags);
132c159
<               TupleDesc resultDesc);
---
>               TupleDesc resultDesc, int prettyFlags, int startIndent);
194a222
>     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
244c272
<     make_ruledef(&buf, ruletup, rulettc);
---
>     make_ruledef(&buf, ruletup, rulettc, prettyFlags);
274a303
>     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
276c305
<     ruledef = pg_do_getviewdef(viewoid);
---
>     ruledef = pg_do_getviewdef(viewoid, prettyFlags);
287a317
>     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
293c323
<     ruledef = pg_do_getviewdef(viewoid);
---
>     ruledef = pg_do_getviewdef(viewoid, prettyFlags);
301c331
< pg_do_getviewdef(Oid viewoid)
---
> pg_do_getviewdef(Oid viewoid, int prettyFlags)
356c386
<         make_viewdef(&buf, ruletup, rulettc);
---
>         make_viewdef(&buf, ruletup, rulettc, prettyFlags);
546a577,578
>     int        colno = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);
>     int        prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
584a617,618
>          * if colno == 0, we want a complete index definition.
>          * if colno > 0, we only want the nth expression.
610c644,646
<     appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
---
>
>     if (!colno)
>         appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
624c660,661
<         appendStringInfo(&buf, sep);
---
>         if (!colno)
>             appendStringInfo(&buf, sep);
633c670,671
<             appendStringInfo(&buf, "%s", quote_identifier(attname));
---
>             if (!colno || colno == keyno+1)
>                 appendStringInfo(&buf, "%s", quote_identifier(attname));
646,648c684,688
<             str = deparse_expression(indexkey, context, false, false);
<             /* Need parens if it's not a bare function call */
<             if (indexkey && IsA(indexkey, FuncExpr) &&
---
>             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) &&
651c691
<             else
---
>                 else
652a693
>             }
659c700,701
<         get_opclass_name(idxrec->indclass[keyno], keycoltype,
---
>         if (!colno)
>             get_opclass_name(idxrec->indclass[keyno], keycoltype,
663,668c705
<     appendStringInfoChar(&buf, ')');
<
<     /*
<      * If it's a partial index, decompile and append the predicate
<      */
<     if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
---
>     if (!colno)
669a707,713
>         appendStringInfoChar(&buf, ')');
>
>         /*
>          * If it's a partial index, decompile and append the predicate
>          */
>         if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
>         {
692c736
<         str = deparse_expression(node, context, false, false);
---
>         str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0);
693a738
>         }
695d739
<
731a776
>     int      prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
937c982
<                 consrc = deparse_expression(expr, context, false, false);
---
>                 consrc = deparse_expression_pretty(expr, context, false, false, prettyFlags, 0);
1020a1066
>     int      prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
1044c1090
<     str = deparse_expression(node, context, false, false);
---
>     str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0);
1092a1139,1149
>  * 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
1102a1160,1161
>  *
>  * tries to pretty up the output according to prettyFlags
1108,1109c1167,1168
< 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)
1117a1177,1178
>     context.prettyFlags = prettyFlags;
>     context.indentLevel = startIndent;
1270c1331
< make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
---
> make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
1324c1385
<     appendStringInfo(buf, "CREATE RULE %s AS ON ",
---
>     appendStringInfo(buf, "CREATE RULE %s AS",
1326a1388,1392
>     if (prettyFlags & PRETTYFLAG_INDENT)
>         appendStringInfoString(buf, "\n    ON ");
>     else
>         appendStringInfoString(buf, "ON ");
>
1368a1435,1436
>         if (prettyFlags & PRETTYFLAG_INDENT)
>             appendStringInfoString(buf, "\n  ");
1389a1458,1459
>         context.prettyFlags = prettyFlags;
>         context.indentLevel = PRETTYINDENT_STD;
1413,1414c1483,1487
<             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, "; ");
1427c1500
<         get_query_def(query, buf, NIL, NULL);
---
>         get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
1439c1512
< make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
---
> make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
1493c1566
<     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation));
---
>     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), prettyFlags, 0);
1509c1582
<               TupleDesc resultDesc)
---
>               TupleDesc resultDesc, int prettyFlags, int startIndent)
1517a1591,1593
>     context.prettyFlags = prettyFlags;
>     context.indentLevel = startIndent;
>
1589c1665
<         appendStringInfo(buf, " ORDER BY ");
---
>             appendContextKeyword(context, " ORDER BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
1618c1694
<         appendStringInfo(buf, " OFFSET ");
---
>         appendContextKeyword(context, " OFFSET ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
1623c1699
<         appendStringInfo(buf, " LIMIT ");
---
>         appendContextKeyword(context, " LIMIT ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
1643a1720,1724
>     if (PRETTY_INDENT(context))
>     {
>         context->indentLevel += PRETTYINDENT_STD;
>         appendStringInfoChar(buf, ' ');
>     }
1723c1804
<         appendStringInfo(buf, " WHERE ");
---
>         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
1730c1811
<         appendStringInfo(buf, " GROUP BY ");
---
>         appendContextKeyword(context, " GROUP BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
1746c1827
<         appendStringInfo(buf, " HAVING ");
---
>         appendContextKeyword(context, " HAVING ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
1764c1845
<         get_query_def(subquery, buf, context->namespaces, resultDesc);
---
>         get_query_def(subquery, buf, context->namespaces, resultDesc, context->prettyFlags, context->indentLevel);
1768a1850,1853
>         bool need_paren=(PRETTY_PAREN(context) ? !IsA(op->rarg, RangeTblRef) : true);
>
>         if (!PRETTY_PAREN(context))
>             appendStringInfoString(buf, "((");
1770d1854
<         appendStringInfo(buf, "((");
1771a1856,1860
>
>         if (!PRETTY_PAREN(context))
>             appendStringInfoChar(buf, ')');
>         if (!PRETTY_INDENT(context))
>             appendStringInfoChar(buf, ' ');
1775c1864
<                 appendStringInfo(buf, ") UNION ");
---
>                 appendContextKeyword(context, "UNION ", -PRETTYINDENT_STD, 0, 0);
1778c1867
<                 appendStringInfo(buf, ") INTERSECT ");
---
>                 appendContextKeyword(context, "INTERSECT ", -PRETTYINDENT_STD, 0, 0);
1781c1870
<                 appendStringInfo(buf, ") EXCEPT ");
---
>                 appendContextKeyword(context, "EXCEPT ", -PRETTYINDENT_STD, 0, 0);
1788c1877,1890
<             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');
>             }
>         }
1790c1892,1893
<             appendStringInfo(buf, "(");
---
>             appendStringInfoChar(buf, '(');
>
1792c1895,1902
<         appendStringInfo(buf, "))");
---
>
>         if (PRETTY_PAREN(context))
>         {
>             if (need_paren)
>             appendStringInfoChar(buf, ')');
>         }
>         else
>             appendStringInfoString(buf, "))");
1864a1975,1980
>
>     if (PRETTY_INDENT(context))
>     {
>         context->indentLevel += PRETTYINDENT_STD;
>         appendStringInfoChar(buf, ' ');
>     }
1886c2002
<         appendStringInfo(buf, "VALUES (");
---
>         appendContextKeyword(context, "VALUES (", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
1902c2018
<         get_query_def(select_rte->subquery, buf, NIL, NULL);
---
>         get_query_def(select_rte->subquery, buf, NIL, NULL, context->prettyFlags, context->indentLevel);
1922a2039,2043
>     if (PRETTY_INDENT(context))
>     {
>         appendStringInfoChar(buf, ' ');
>         context->indentLevel += PRETTYINDENT_STD;
>     }
1956c2077
<         appendStringInfo(buf, " WHERE ");
---
>         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
1976a2098,2102
>     if (PRETTY_INDENT(context))
>     {
>         context->indentLevel += PRETTYINDENT_STD;
>         appendStringInfoChar(buf, ' ');
>     }
1984c2110
<         appendStringInfo(buf, " WHERE ");
---
>         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2002a2129
>         appendContextKeyword(context, "", 0, PRETTYINDENT_STD, 1);
2142a2270,2505
> /********************************************
>  * get_simple_binary_op_name
>  * helper function for isSimpleNode
>  * will return single char binary operator
>  *******************************************/
>
> static 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);
>         char *op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
>
>         if (strlen(op) == 1)
>             return op;
>     }
>     return 0;
> }
>
>
> /***************************************
>  * check if given node is simple.
>  *  false  : not simple
>  *  true   : simple in the context of parent node's type
>  ***************************************/
>
> static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
> {
>     if (!node)
>     return true;
>
>     switch (nodeTag(node))
>     {
>     // single words: always simple
>     case T_Var:
>     case T_Const:
>     case T_Param:
>
>     // function-like: name(..) or name[..]
>     case T_ArrayRef:
>     case T_ArrayExpr:
>     case T_CoalesceExpr:
>     case T_NullIfExpr:
>     case T_Aggref:
>     case T_FuncExpr:
>
>         // CASE keywords act as parentheses
>     case T_CaseExpr:
>         return true;
>
>         // appears simple since . has top precedence, unless parent is T_FieldSelect itself!
>     case T_FieldSelect:
>         return (nodeTag(parentNode) == T_FieldSelect ? false : true);
>
>
>         // maybe simple, check args
>     case T_CoerceToDomain:
>         return isSimpleNode((Node*) ((CoerceToDomain*)node)->arg, node, prettyFlags);
>     case T_RelabelType:
>         return isSimpleNode((Node*) ((RelabelType*)node)->arg, node, prettyFlags);
>
>
>     // depends on parent node type; needs further checking
>     case T_OpExpr:
>     {
>         if (prettyFlags & PRETTYFLAG_PAREN && nodeTag(parentNode) == T_OpExpr)
>         {
>         char *op=get_simple_binary_op_name((OpExpr*)node);
>         char *parentOp=get_simple_binary_op_name((OpExpr*)parentNode);
>         if (!op || !parentOp)
>             return false;
>
>                 // we know only these basic operators
>         if (!strchr("+-*/%", *op) || !strchr("+-*/%", *parentOp))
>             return false;
>
>         // natural operator precedence, so we don't need parentheses
>         if (strchr("*/%", *op) || strchr("+-", *parentOp))
>             return true;
>
>         return false;
>         }
>             // else do the same stuff as for T_SubLink et al.
>     }
>     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=((BoolExpr*)node)->boolop;
>             BoolExprType 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;
>         }
>         // these are not completely implemented; so far, they're simple
>     case T_SubPlan:
>     case T_CoerceToDomainValue:
>         return true;
>
>     case T_ScalarArrayOpExpr:
>         // need to check
>     default:
>         break;
>     }
>     // those we don't know: in dubio complexo
>     return false;
> }
>
>
> /******************************************
>  * appendContextKeyword
>  * append spaces to buffer
>  ******************************************/
> static void appendStringInfoSpace(StringInfo buf, int count)
> {
>     while (count-- > 0)
>     appendStringInfoChar(buf, ' ');
> }
>
> /******************************************
>  * appendContextKeyword
>  * performing a line break, and indentation
>  * if prettyPrint is enabled.
>  * Otherwise, only the keyword is appended
>  *****************************************/
>
> static void appendContextKeyword(deparse_context *context, 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');
>     appendStringInfoSpace(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  - parsing expr using get_rule_expr,
>  * embracing the string with parentheses if necessary for prettyPrint.
>  * never embracing 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 = 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, ')');
> }
>
>
2297,2299c2660,2662
<
<                 appendStringInfoChar(buf, '(');
<                 get_rule_expr(arg1, context, true);
---
>                 if (!PRETTY_PAREN(context))
>                     appendStringInfoChar(buf, '(');
>                 get_rule_expr_paren(arg1, context, true, node);
2301,2302c2664,2666
<                 get_rule_expr(arg2, context, true);
<                 appendStringInfoChar(buf, ')');
---
>                 get_rule_expr_paren(arg2, context, true, node);
>                 if (!PRETTY_PAREN(context))
>                     appendStringInfoChar(buf, ')');
2313,2314c2677,2679
<                 appendStringInfoChar(buf, '(');
<                 get_rule_expr(arg1, context, true);
---
>                 if (!PRETTY_PAREN(context))
>                     appendStringInfoChar(buf, '(');
>                 get_rule_expr_paren(arg1, context, true, node);
2320,2321c2685,2689
<                 get_rule_expr(arg2, context, true);
<                 appendStringInfo(buf, "))");
---
>                 get_rule_expr_paren(arg2, context, true, node);
>                 appendStringInfoString(buf, ")");
>
>                 if (!PRETTY_PAREN(context))
>                     appendStringInfoChar(buf, ')');
2333,2334c2701,2703
<                         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);
2338,2339c2707,2708
<                             get_rule_expr((Node *) lfirst(args), context,
<                                           false);
---
>                             get_rule_expr_paren((Node *) lfirst(args), context,
>                                           false, node);
2341c2710,2711
<                         appendStringInfoChar(buf, ')');
---
>                             if (!PRETTY_PAREN(context))
>                             appendStringInfoChar(buf, ')');
2345,2346c2715,2717
<                         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);
2350,2351c2721,2722
<                             get_rule_expr((Node *) lfirst(args), context,
<                                           false);
---
>                             get_rule_expr_paren((Node *) lfirst(args), context,
>                                           false, node);
2353c2724,2725
<                         appendStringInfoChar(buf, ')');
---
>                             if (!PRETTY_PAREN(context))
>                             appendStringInfoChar(buf, ')');
2357,2359c2729,2734
<                         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, ')');
2407,2409c2782,2787
<                 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));
2422c2800
<                     get_rule_expr(arg, context, showimplicit);
---
>                     get_rule_expr_paren(arg, context, showimplicit, node);
2434,2436c2812,2818
<                     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",
2448c2830
<                 appendStringInfo(buf, "CASE");
---
>                 appendContextKeyword(context, "CASE", 0, PRETTYINDENT_VAR, 0);
2453c2835,2838
<                     appendStringInfo(buf, " WHEN ");
---
>                     if (!PRETTY_INDENT(context))
>                         appendStringInfoChar(buf, ' ');
>
>                     appendContextKeyword(context, "WHEN ", 0, 0, 0);
2454a2840
>
2458c2844,2846
<                 appendStringInfo(buf, " ELSE ");
---
>                 if (!PRETTY_INDENT(context))
>                     appendStringInfoChar(buf, ' ');
>                 appendContextKeyword(context, "ELSE ", 0, 0, 0);
2460c2848,2850
<                 appendStringInfo(buf, " END");
---
>                 if (!PRETTY_INDENT(context))
>                     appendStringInfoChar(buf, ' ');
>                 appendContextKeyword(context, "END", -PRETTYINDENT_VAR, 0, 0);
2528,2529c2918,2920
<                 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);
2533c2924
<                         appendStringInfo(buf, " IS NULL)");
---
>                         appendStringInfo(buf, " IS NULL");
2536c2927
<                         appendStringInfo(buf, " IS NOT NULL)");
---
>                         appendStringInfo(buf, " IS NOT NULL");
2541a2933,2934
>                 if (!PRETTY_PAREN(context))
>                     appendStringInfoChar(buf, ')');
2549,2550c2942,2944
<                 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);
2554c2948
<                         appendStringInfo(buf, " IS TRUE)");
---
>                         appendStringInfo(buf, " IS TRUE");
2557c2951
<                         appendStringInfo(buf, " IS NOT TRUE)");
---
>                         appendStringInfo(buf, " IS NOT TRUE");
2560c2954
<                         appendStringInfo(buf, " IS FALSE)");
---
>                         appendStringInfo(buf, " IS FALSE");
2563c2957
<                         appendStringInfo(buf, " IS NOT FALSE)");
---
>                         appendStringInfo(buf, " IS NOT FALSE");
2566c2960
<                         appendStringInfo(buf, " IS UNKNOWN)");
---
>                         appendStringInfo(buf, " IS UNKNOWN");
2569c2963
<                         appendStringInfo(buf, " IS NOT UNKNOWN)");
---
>                         appendStringInfo(buf, " IS NOT UNKNOWN");
2574a2969,2970
>                 if (!PRETTY_PAREN(context))
>                     appendStringInfoChar(buf, ')');
2596,2598c2992,2999
<                     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",
2630c3031,3032
<     appendStringInfoChar(buf, '(');
---
>     if (!PRETTY_PAREN(context))
>         appendStringInfoChar(buf, '(');
2636,2637c3038
<
<         get_rule_expr(arg1, context, true);
---
>         get_rule_expr_paren(arg1, context, true, (Node*)expr);
2642c3043
<         get_rule_expr(arg2, context, true);
---
>         get_rule_expr_paren(arg2, context, true, (Node*)expr);
2664c3065
<                 get_rule_expr(arg, context, true);
---
>                 get_rule_expr_paren(arg, context, true, (Node*)expr);
2667c3068
<                 get_rule_expr(arg, context, true);
---
>                 get_rule_expr_paren(arg, context, true, (Node*)expr);
2678c3079,3080
<     appendStringInfoChar(buf, ')');
---
>     if (!PRETTY_PAREN(context))
>         appendStringInfoChar(buf, ')');
2701c3103
<         get_rule_expr((Node *) lfirst(expr->args), context, showimplicit);
---
>         get_rule_expr_paren((Node *) lfirst(expr->args), context, showimplicit, (Node*)expr);
2727,2729c3129,3136
<         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",
3050c3457
<     get_query_def(query, buf, context->namespaces, NULL);
---
>     get_query_def(query, buf, context->namespaces, NULL, context->prettyFlags, context->indentLevel);
3067c3474
<     char       *sep;
---
>     char       *sep=0;
3077d3483
<     sep = " FROM ";
3096c3502,3506
<         appendStringInfo(buf, sep);
---
>         if (!sep)
>             appendContextKeyword(context, " FROM ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
>         else
>             appendStringInfo(buf, sep);
>
3125c3535,3536
<                 get_query_def(rte->subquery, buf, context->namespaces, NULL);
---
>                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
>                           context->prettyFlags, context->indentLevel);
3147c3558
<                 appendStringInfo(buf, "(");
---
>                 appendStringInfoChar(buf, '(');
3180a3592,3595
>         bool need_paren_on_right = PRETTY_PAREN(context) && !IsA(j->rarg, RangeTblRef);
>
>         if (!PRETTY_PAREN(context) || j->alias != NULL)
>             appendStringInfoChar(buf, '(');
3182d3596
<         appendStringInfoChar(buf, '(');
3183a3598
>
3185,3186d3599
<             appendStringInfo(buf, " NATURAL");
<         switch (j->jointype)
3187a3601,3631
>             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, "get_from_clause_item: unknown join type %d",
>                      (int) j->jointype);
>             }
>         }
>         else
>         {
>             switch (j->jointype)
>             {
3190c3634
<                     appendStringInfo(buf, " JOIN ");
---
>                     appendContextKeyword(context, " JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
3192c3636
<                     appendStringInfo(buf, " CROSS JOIN ");
---
>                     appendContextKeyword(context, " CROSS JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 1);
3195c3639
<                 appendStringInfo(buf, " LEFT JOIN ");
---
>                 appendContextKeyword(context, " LEFT JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
3198c3642
<                 appendStringInfo(buf, " FULL JOIN ");
---
>                 appendContextKeyword(context, " FULL JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
3201c3645
<                 appendStringInfo(buf, " RIGHT JOIN ");
---
>                 appendContextKeyword(context, " RIGHT JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
3204c3648
<                 appendStringInfo(buf, " UNION JOIN ");
---
>                 appendContextKeyword(context, " UNION JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
3208a3653
>             }
3209a3655,3657
>
>         if (need_paren_on_right)
>             appendStringInfoChar(buf, '(');
3210a3659,3663
>         if (need_paren_on_right)
>             appendStringInfoChar(buf, ')');
>
>             context->indentLevel -= PRETTYINDENT_JOIN_ON;
>
3229c3682,3684
<                 appendStringInfo(buf, " ON (");
---
>                 appendStringInfo(buf, " ON ");
>                 if (!PRETTY_PAREN(context))
>                     appendStringInfoChar(buf, '(');
3231c3686,3687
<                 appendStringInfoChar(buf, ')');
---
>                 if (!PRETTY_PAREN(context))
>                     appendStringInfoChar(buf, ')');
3234c3690,3692
<         appendStringInfoChar(buf, ')');
---
>         if (!PRETTY_PAREN(context) || j->alias != NULL)
>             appendStringInfoChar(buf, ')');
>
3244c3702
<                 appendStringInfo(buf, "(");
---
>                 appendStringInfoChar(buf, '(');

Re: ruleutils with pretty-print option

From
Bruce Momjian
Date:
Andreas, looks good, but I need a diff -c, context diff.

---------------------------------------------------------------------------

Andreas Pflug wrote:
> Hi Bruce,
> so here's the complete patch against the current cvs.
>
> Description:
> The attached patches will add
>    pg_get_ruledef(oid, bool)
>    pg_get_viewdef(text, bool)
>    pg_get_viewdef(oid, bool)
>    pg_get_indexdef(oid, int4, bool)
>    pg_get_constraintdef(oid, bool)
>    pg_get_expr(text, oid, bool)
>
> If the last parameter "pretty-print" is false, these function will
> return the same result as their original counterparts without that
> parameter. The source is based on ruleutils.c 1.145 and pg_proc 1.309,
> and should return exactly the same result as before if no pretty-print
> is selected. My tests didn't show any differences for pg_dump output
> with old or new version.
>
> If the last parameter "pretty-print" is true, parentheses are checked;
> only necessary parentheses will be emitted. Additionally, line and
> indentation formatting is performed.
>
> pg_get_indexdef has one additional parameter. The second parameter
> (int4) selects the nth expression of an index (1..indnatts). If zero, a
> complete CREATE INDEX statement is generated to obtain the previous
> behaviour.
> The third is the pretty-print option as described.
>
> example:
> pg_get_indexdef(12345, 0, true)  -> CREATE INDEX foo ON bar (numcol,
> length(txtcol), intcol2, (8+length(txtcol2)))
> pg_get_indexdef(12345, 1, true)  -> numcol
> pg_get_indexdef(12345, 2, true)  -> length(txtcol)
> pg_get_indexdef(12345, 3, true)  -> intcol2
> pg_get_indexdef(12345, 4, true)  -> (8+length(txtcol2))
>
> Regards,
> Andreas
>

> Index: pg_proc.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
> retrieving revision 1.309
> diff -r1.309 pg_proc.h
> 3407a3408,3421
> > /* 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 - _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 - _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 - _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 - _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 - _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 - _null_
));
> > DESCR("deparse an encoded expression with pretty-print option");
> >

> Index: ruleutils.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
> retrieving revision 1.145
> diff -r1.145 ruleutils.c
> 73a74,92
> > /******************************
> >  * 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)
> >
> >
> 83a103,104
> >         int             prettyFlags;            /* enabling/disabling of pretty-print functions */
> >         int             indentLevel;            /* for prettyPrint, current space indents are counted */
> 126c147,153
> < static text *pg_do_getviewdef(Oid viewoid);
> ---
> > static char *get_simple_binary_op_name(OpExpr *expr);
> > static void appendStringInfoSpace(StringInfo buf, int count);
> > static void appendContextKeyword(deparse_context *context, char *str, int indentBefore, int indentAfter, int
indentPlus);
> > static char *deparse_expression_pretty(Node *expr, List *dpcontext,
> >               bool forceprefix, bool showimplicit, int prettyFlags, int startIndent);
> > static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
> > static text *pg_do_getviewdef(Oid viewoid, int prettyFlags);
> 129,130c156,157
> < static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
> < static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
> ---
> > static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags);
> > static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags);
> 132c159
> <               TupleDesc resultDesc);
> ---
> >               TupleDesc resultDesc, int prettyFlags, int startIndent);
> 194a222
> >     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
> 244c272
> <     make_ruledef(&buf, ruletup, rulettc);
> ---
> >     make_ruledef(&buf, ruletup, rulettc, prettyFlags);
> 274a303
> >     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
> 276c305
> <     ruledef = pg_do_getviewdef(viewoid);
> ---
> >     ruledef = pg_do_getviewdef(viewoid, prettyFlags);
> 287a317
> >     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
> 293c323
> <     ruledef = pg_do_getviewdef(viewoid);
> ---
> >     ruledef = pg_do_getviewdef(viewoid, prettyFlags);
> 301c331
> < pg_do_getviewdef(Oid viewoid)
> ---
> > pg_do_getviewdef(Oid viewoid, int prettyFlags)
> 356c386
> <         make_viewdef(&buf, ruletup, rulettc);
> ---
> >         make_viewdef(&buf, ruletup, rulettc, prettyFlags);
> 546a577,578
> >     int        colno = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);
> >     int        prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
> 584a617,618
> >          * if colno == 0, we want a complete index definition.
> >          * if colno > 0, we only want the nth expression.
> 610c644,646
> <     appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
> ---
> >
> >     if (!colno)
> >         appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
> 624c660,661
> <         appendStringInfo(&buf, sep);
> ---
> >         if (!colno)
> >             appendStringInfo(&buf, sep);
> 633c670,671
> <             appendStringInfo(&buf, "%s", quote_identifier(attname));
> ---
> >             if (!colno || colno == keyno+1)
> >                 appendStringInfo(&buf, "%s", quote_identifier(attname));
> 646,648c684,688
> <             str = deparse_expression(indexkey, context, false, false);
> <             /* Need parens if it's not a bare function call */
> <             if (indexkey && IsA(indexkey, FuncExpr) &&
> ---
> >             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) &&
> 651c691
> <             else
> ---
> >                 else
> 652a693
> >             }
> 659c700,701
> <         get_opclass_name(idxrec->indclass[keyno], keycoltype,
> ---
> >         if (!colno)
> >             get_opclass_name(idxrec->indclass[keyno], keycoltype,
> 663,668c705
> <     appendStringInfoChar(&buf, ')');
> <
> <     /*
> <      * If it's a partial index, decompile and append the predicate
> <      */
> <     if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
> ---
> >     if (!colno)
> 669a707,713
> >         appendStringInfoChar(&buf, ')');
> >
> >         /*
> >          * If it's a partial index, decompile and append the predicate
> >          */
> >         if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
> >         {
> 692c736
> <         str = deparse_expression(node, context, false, false);
> ---
> >         str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0);
> 693a738
> >         }
> 695d739
> <
> 731a776
> >     int      prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
> 937c982
> <                 consrc = deparse_expression(expr, context, false, false);
> ---
> >                 consrc = deparse_expression_pretty(expr, context, false, false, prettyFlags, 0);
> 1020a1066
> >     int      prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
> 1044c1090
> <     str = deparse_expression(node, context, false, false);
> ---
> >     str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0);
> 1092a1139,1149
> >  * 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
> 1102a1160,1161
> >  *
> >  * tries to pretty up the output according to prettyFlags
> 1108,1109c1167,1168
> < 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)
> 1117a1177,1178
> >     context.prettyFlags = prettyFlags;
> >     context.indentLevel = startIndent;
> 1270c1331
> < make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
> ---
> > make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
> 1324c1385
> <     appendStringInfo(buf, "CREATE RULE %s AS ON ",
> ---
> >     appendStringInfo(buf, "CREATE RULE %s AS",
> 1326a1388,1392
> >     if (prettyFlags & PRETTYFLAG_INDENT)
> >         appendStringInfoString(buf, "\n    ON ");
> >     else
> >         appendStringInfoString(buf, "ON ");
> >
> 1368a1435,1436
> >         if (prettyFlags & PRETTYFLAG_INDENT)
> >             appendStringInfoString(buf, "\n  ");
> 1389a1458,1459
> >         context.prettyFlags = prettyFlags;
> >         context.indentLevel = PRETTYINDENT_STD;
> 1413,1414c1483,1487
> <             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, "; ");
> 1427c1500
> <         get_query_def(query, buf, NIL, NULL);
> ---
> >         get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
> 1439c1512
> < make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
> ---
> > make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
> 1493c1566
> <     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation));
> ---
> >     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), prettyFlags, 0);
> 1509c1582
> <               TupleDesc resultDesc)
> ---
> >               TupleDesc resultDesc, int prettyFlags, int startIndent)
> 1517a1591,1593
> >     context.prettyFlags = prettyFlags;
> >     context.indentLevel = startIndent;
> >
> 1589c1665
> <         appendStringInfo(buf, " ORDER BY ");
> ---
> >             appendContextKeyword(context, " ORDER BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
> 1618c1694
> <         appendStringInfo(buf, " OFFSET ");
> ---
> >         appendContextKeyword(context, " OFFSET ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
> 1623c1699
> <         appendStringInfo(buf, " LIMIT ");
> ---
> >         appendContextKeyword(context, " LIMIT ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
> 1643a1720,1724
> >     if (PRETTY_INDENT(context))
> >     {
> >         context->indentLevel += PRETTYINDENT_STD;
> >         appendStringInfoChar(buf, ' ');
> >     }
> 1723c1804
> <         appendStringInfo(buf, " WHERE ");
> ---
> >         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
> 1730c1811
> <         appendStringInfo(buf, " GROUP BY ");
> ---
> >         appendContextKeyword(context, " GROUP BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
> 1746c1827
> <         appendStringInfo(buf, " HAVING ");
> ---
> >         appendContextKeyword(context, " HAVING ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
> 1764c1845
> <         get_query_def(subquery, buf, context->namespaces, resultDesc);
> ---
> >         get_query_def(subquery, buf, context->namespaces, resultDesc, context->prettyFlags, context->indentLevel);
> 1768a1850,1853
> >         bool need_paren=(PRETTY_PAREN(context) ? !IsA(op->rarg, RangeTblRef) : true);
> >
> >         if (!PRETTY_PAREN(context))
> >             appendStringInfoString(buf, "((");
> 1770d1854
> <         appendStringInfo(buf, "((");
> 1771a1856,1860
> >
> >         if (!PRETTY_PAREN(context))
> >             appendStringInfoChar(buf, ')');
> >         if (!PRETTY_INDENT(context))
> >             appendStringInfoChar(buf, ' ');
> 1775c1864
> <                 appendStringInfo(buf, ") UNION ");
> ---
> >                 appendContextKeyword(context, "UNION ", -PRETTYINDENT_STD, 0, 0);
> 1778c1867
> <                 appendStringInfo(buf, ") INTERSECT ");
> ---
> >                 appendContextKeyword(context, "INTERSECT ", -PRETTYINDENT_STD, 0, 0);
> 1781c1870
> <                 appendStringInfo(buf, ") EXCEPT ");
> ---
> >                 appendContextKeyword(context, "EXCEPT ", -PRETTYINDENT_STD, 0, 0);
> 1788c1877,1890
> <             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');
> >             }
> >         }
> 1790c1892,1893
> <             appendStringInfo(buf, "(");
> ---
> >             appendStringInfoChar(buf, '(');
> >
> 1792c1895,1902
> <         appendStringInfo(buf, "))");
> ---
> >
> >         if (PRETTY_PAREN(context))
> >         {
> >             if (need_paren)
> >             appendStringInfoChar(buf, ')');
> >         }
> >         else
> >             appendStringInfoString(buf, "))");
> 1864a1975,1980
> >
> >     if (PRETTY_INDENT(context))
> >     {
> >         context->indentLevel += PRETTYINDENT_STD;
> >         appendStringInfoChar(buf, ' ');
> >     }
> 1886c2002
> <         appendStringInfo(buf, "VALUES (");
> ---
> >         appendContextKeyword(context, "VALUES (", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
> 1902c2018
> <         get_query_def(select_rte->subquery, buf, NIL, NULL);
> ---
> >         get_query_def(select_rte->subquery, buf, NIL, NULL, context->prettyFlags, context->indentLevel);
> 1922a2039,2043
> >     if (PRETTY_INDENT(context))
> >     {
> >         appendStringInfoChar(buf, ' ');
> >         context->indentLevel += PRETTYINDENT_STD;
> >     }
> 1956c2077
> <         appendStringInfo(buf, " WHERE ");
> ---
> >         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
> 1976a2098,2102
> >     if (PRETTY_INDENT(context))
> >     {
> >         context->indentLevel += PRETTYINDENT_STD;
> >         appendStringInfoChar(buf, ' ');
> >     }
> 1984c2110
> <         appendStringInfo(buf, " WHERE ");
> ---
> >         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
> 2002a2129
> >         appendContextKeyword(context, "", 0, PRETTYINDENT_STD, 1);
> 2142a2270,2505
> > /********************************************
> >  * get_simple_binary_op_name
> >  * helper function for isSimpleNode
> >  * will return single char binary operator
> >  *******************************************/
> >
> > static 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);
> >         char *op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
> >
> >         if (strlen(op) == 1)
> >             return op;
> >     }
> >     return 0;
> > }
> >
> >
> > /***************************************
> >  * check if given node is simple.
> >  *  false  : not simple
> >  *  true   : simple in the context of parent node's type
> >  ***************************************/
> >
> > static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
> > {
> >     if (!node)
> >     return true;
> >
> >     switch (nodeTag(node))
> >     {
> >     // single words: always simple
> >     case T_Var:
> >     case T_Const:
> >     case T_Param:
> >
> >     // function-like: name(..) or name[..]
> >     case T_ArrayRef:
> >     case T_ArrayExpr:
> >     case T_CoalesceExpr:
> >     case T_NullIfExpr:
> >     case T_Aggref:
> >     case T_FuncExpr:
> >
> >         // CASE keywords act as parentheses
> >     case T_CaseExpr:
> >         return true;
> >
> >         // appears simple since . has top precedence, unless parent is T_FieldSelect itself!
> >     case T_FieldSelect:
> >         return (nodeTag(parentNode) == T_FieldSelect ? false : true);
> >
> >
> >         // maybe simple, check args
> >     case T_CoerceToDomain:
> >         return isSimpleNode((Node*) ((CoerceToDomain*)node)->arg, node, prettyFlags);
> >     case T_RelabelType:
> >         return isSimpleNode((Node*) ((RelabelType*)node)->arg, node, prettyFlags);
> >
> >
> >     // depends on parent node type; needs further checking
> >     case T_OpExpr:
> >     {
> >         if (prettyFlags & PRETTYFLAG_PAREN && nodeTag(parentNode) == T_OpExpr)
> >         {
> >         char *op=get_simple_binary_op_name((OpExpr*)node);
> >         char *parentOp=get_simple_binary_op_name((OpExpr*)parentNode);
> >         if (!op || !parentOp)
> >             return false;
> >
> >                 // we know only these basic operators
> >         if (!strchr("+-*/%", *op) || !strchr("+-*/%", *parentOp))
> >             return false;
> >
> >         // natural operator precedence, so we don't need parentheses
> >         if (strchr("*/%", *op) || strchr("+-", *parentOp))
> >             return true;
> >
> >         return false;
> >         }
> >             // else do the same stuff as for T_SubLink et al.
> >     }
> >     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=((BoolExpr*)node)->boolop;
> >             BoolExprType 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;
> >         }
> >         // these are not completely implemented; so far, they're simple
> >     case T_SubPlan:
> >     case T_CoerceToDomainValue:
> >         return true;
> >
> >     case T_ScalarArrayOpExpr:
> >         // need to check
> >     default:
> >         break;
> >     }
> >     // those we don't know: in dubio complexo
> >     return false;
> > }
> >
> >
> > /******************************************
> >  * appendContextKeyword
> >  * append spaces to buffer
> >  ******************************************/
> > static void appendStringInfoSpace(StringInfo buf, int count)
> > {
> >     while (count-- > 0)
> >     appendStringInfoChar(buf, ' ');
> > }
> >
> > /******************************************
> >  * appendContextKeyword
> >  * performing a line break, and indentation
> >  * if prettyPrint is enabled.
> >  * Otherwise, only the keyword is appended
> >  *****************************************/
> >
> > static void appendContextKeyword(deparse_context *context, 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');
> >     appendStringInfoSpace(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  - parsing expr using get_rule_expr,
> >  * embracing the string with parentheses if necessary for prettyPrint.
> >  * never embracing 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 = 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, ')');
> > }
> >
> >
> 2297,2299c2660,2662
> <
> <                 appendStringInfoChar(buf, '(');
> <                 get_rule_expr(arg1, context, true);
> ---
> >                 if (!PRETTY_PAREN(context))
> >                     appendStringInfoChar(buf, '(');
> >                 get_rule_expr_paren(arg1, context, true, node);
> 2301,2302c2664,2666
> <                 get_rule_expr(arg2, context, true);
> <                 appendStringInfoChar(buf, ')');
> ---
> >                 get_rule_expr_paren(arg2, context, true, node);
> >                 if (!PRETTY_PAREN(context))
> >                     appendStringInfoChar(buf, ')');
> 2313,2314c2677,2679
> <                 appendStringInfoChar(buf, '(');
> <                 get_rule_expr(arg1, context, true);
> ---
> >                 if (!PRETTY_PAREN(context))
> >                     appendStringInfoChar(buf, '(');
> >                 get_rule_expr_paren(arg1, context, true, node);
> 2320,2321c2685,2689
> <                 get_rule_expr(arg2, context, true);
> <                 appendStringInfo(buf, "))");
> ---
> >                 get_rule_expr_paren(arg2, context, true, node);
> >                 appendStringInfoString(buf, ")");
> >
> >                 if (!PRETTY_PAREN(context))
> >                     appendStringInfoChar(buf, ')');
> 2333,2334c2701,2703
> <                         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);
> 2338,2339c2707,2708
> <                             get_rule_expr((Node *) lfirst(args), context,
> <                                           false);
> ---
> >                             get_rule_expr_paren((Node *) lfirst(args), context,
> >                                           false, node);
> 2341c2710,2711
> <                         appendStringInfoChar(buf, ')');
> ---
> >                             if (!PRETTY_PAREN(context))
> >                             appendStringInfoChar(buf, ')');
> 2345,2346c2715,2717
> <                         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);
> 2350,2351c2721,2722
> <                             get_rule_expr((Node *) lfirst(args), context,
> <                                           false);
> ---
> >                             get_rule_expr_paren((Node *) lfirst(args), context,
> >                                           false, node);
> 2353c2724,2725
> <                         appendStringInfoChar(buf, ')');
> ---
> >                             if (!PRETTY_PAREN(context))
> >                             appendStringInfoChar(buf, ')');
> 2357,2359c2729,2734
> <                         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, ')');
> 2407,2409c2782,2787
> <                 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));
> 2422c2800
> <                     get_rule_expr(arg, context, showimplicit);
> ---
> >                     get_rule_expr_paren(arg, context, showimplicit, node);
> 2434,2436c2812,2818
> <                     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",
> 2448c2830
> <                 appendStringInfo(buf, "CASE");
> ---
> >                 appendContextKeyword(context, "CASE", 0, PRETTYINDENT_VAR, 0);
> 2453c2835,2838
> <                     appendStringInfo(buf, " WHEN ");
> ---
> >                     if (!PRETTY_INDENT(context))
> >                         appendStringInfoChar(buf, ' ');
> >
> >                     appendContextKeyword(context, "WHEN ", 0, 0, 0);
> 2454a2840
> >
> 2458c2844,2846
> <                 appendStringInfo(buf, " ELSE ");
> ---
> >                 if (!PRETTY_INDENT(context))
> >                     appendStringInfoChar(buf, ' ');
> >                 appendContextKeyword(context, "ELSE ", 0, 0, 0);
> 2460c2848,2850
> <                 appendStringInfo(buf, " END");
> ---
> >                 if (!PRETTY_INDENT(context))
> >                     appendStringInfoChar(buf, ' ');
> >                 appendContextKeyword(context, "END", -PRETTYINDENT_VAR, 0, 0);
> 2528,2529c2918,2920
> <                 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);
> 2533c2924
> <                         appendStringInfo(buf, " IS NULL)");
> ---
> >                         appendStringInfo(buf, " IS NULL");
> 2536c2927
> <                         appendStringInfo(buf, " IS NOT NULL)");
> ---
> >                         appendStringInfo(buf, " IS NOT NULL");
> 2541a2933,2934
> >                 if (!PRETTY_PAREN(context))
> >                     appendStringInfoChar(buf, ')');
> 2549,2550c2942,2944
> <                 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);
> 2554c2948
> <                         appendStringInfo(buf, " IS TRUE)");
> ---
> >                         appendStringInfo(buf, " IS TRUE");
> 2557c2951
> <                         appendStringInfo(buf, " IS NOT TRUE)");
> ---
> >                         appendStringInfo(buf, " IS NOT TRUE");
> 2560c2954
> <                         appendStringInfo(buf, " IS FALSE)");
> ---
> >                         appendStringInfo(buf, " IS FALSE");
> 2563c2957
> <                         appendStringInfo(buf, " IS NOT FALSE)");
> ---
> >                         appendStringInfo(buf, " IS NOT FALSE");
> 2566c2960
> <                         appendStringInfo(buf, " IS UNKNOWN)");
> ---
> >                         appendStringInfo(buf, " IS UNKNOWN");
> 2569c2963
> <                         appendStringInfo(buf, " IS NOT UNKNOWN)");
> ---
> >                         appendStringInfo(buf, " IS NOT UNKNOWN");
> 2574a2969,2970
> >                 if (!PRETTY_PAREN(context))
> >                     appendStringInfoChar(buf, ')');
> 2596,2598c2992,2999
> <                     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",
> 2630c3031,3032
> <     appendStringInfoChar(buf, '(');
> ---
> >     if (!PRETTY_PAREN(context))
> >         appendStringInfoChar(buf, '(');
> 2636,2637c3038
> <
> <         get_rule_expr(arg1, context, true);
> ---
> >         get_rule_expr_paren(arg1, context, true, (Node*)expr);
> 2642c3043
> <         get_rule_expr(arg2, context, true);
> ---
> >         get_rule_expr_paren(arg2, context, true, (Node*)expr);
> 2664c3065
> <                 get_rule_expr(arg, context, true);
> ---
> >                 get_rule_expr_paren(arg, context, true, (Node*)expr);
> 2667c3068
> <                 get_rule_expr(arg, context, true);
> ---
> >                 get_rule_expr_paren(arg, context, true, (Node*)expr);
> 2678c3079,3080
> <     appendStringInfoChar(buf, ')');
> ---
> >     if (!PRETTY_PAREN(context))
> >         appendStringInfoChar(buf, ')');
> 2701c3103
> <         get_rule_expr((Node *) lfirst(expr->args), context, showimplicit);
> ---
> >         get_rule_expr_paren((Node *) lfirst(expr->args), context, showimplicit, (Node*)expr);
> 2727,2729c3129,3136
> <         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",
> 3050c3457
> <     get_query_def(query, buf, context->namespaces, NULL);
> ---
> >     get_query_def(query, buf, context->namespaces, NULL, context->prettyFlags, context->indentLevel);
> 3067c3474
> <     char       *sep;
> ---
> >     char       *sep=0;
> 3077d3483
> <     sep = " FROM ";
> 3096c3502,3506
> <         appendStringInfo(buf, sep);
> ---
> >         if (!sep)
> >             appendContextKeyword(context, " FROM ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
> >         else
> >             appendStringInfo(buf, sep);
> >
> 3125c3535,3536
> <                 get_query_def(rte->subquery, buf, context->namespaces, NULL);
> ---
> >                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
> >                           context->prettyFlags, context->indentLevel);
> 3147c3558
> <                 appendStringInfo(buf, "(");
> ---
> >                 appendStringInfoChar(buf, '(');
> 3180a3592,3595
> >         bool need_paren_on_right = PRETTY_PAREN(context) && !IsA(j->rarg, RangeTblRef);
> >
> >         if (!PRETTY_PAREN(context) || j->alias != NULL)
> >             appendStringInfoChar(buf, '(');
> 3182d3596
> <         appendStringInfoChar(buf, '(');
> 3183a3598
> >
> 3185,3186d3599
> <             appendStringInfo(buf, " NATURAL");
> <         switch (j->jointype)
> 3187a3601,3631
> >             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, "get_from_clause_item: unknown join type %d",
> >                      (int) j->jointype);
> >             }
> >         }
> >         else
> >         {
> >             switch (j->jointype)
> >             {
> 3190c3634
> <                     appendStringInfo(buf, " JOIN ");
> ---
> >                     appendContextKeyword(context, " JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
> 3192c3636
> <                     appendStringInfo(buf, " CROSS JOIN ");
> ---
> >                     appendContextKeyword(context, " CROSS JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 1);
> 3195c3639
> <                 appendStringInfo(buf, " LEFT JOIN ");
> ---
> >                 appendContextKeyword(context, " LEFT JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
> 3198c3642
> <                 appendStringInfo(buf, " FULL JOIN ");
> ---
> >                 appendContextKeyword(context, " FULL JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
> 3201c3645
> <                 appendStringInfo(buf, " RIGHT JOIN ");
> ---
> >                 appendContextKeyword(context, " RIGHT JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
> 3204c3648
> <                 appendStringInfo(buf, " UNION JOIN ");
> ---
> >                 appendContextKeyword(context, " UNION JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
> 3208a3653
> >             }
> 3209a3655,3657
> >
> >         if (need_paren_on_right)
> >             appendStringInfoChar(buf, '(');
> 3210a3659,3663
> >         if (need_paren_on_right)
> >             appendStringInfoChar(buf, ')');
> >
> >             context->indentLevel -= PRETTYINDENT_JOIN_ON;
> >
> 3229c3682,3684
> <                 appendStringInfo(buf, " ON (");
> ---
> >                 appendStringInfo(buf, " ON ");
> >                 if (!PRETTY_PAREN(context))
> >                     appendStringInfoChar(buf, '(');
> 3231c3686,3687
> <                 appendStringInfoChar(buf, ')');
> ---
> >                 if (!PRETTY_PAREN(context))
> >                     appendStringInfoChar(buf, ')');
> 3234c3690,3692
> <         appendStringInfoChar(buf, ')');
> ---
> >         if (!PRETTY_PAREN(context) || j->alias != NULL)
> >             appendStringInfoChar(buf, ')');
> >
> 3244c3702
> <                 appendStringInfo(buf, "(");
> ---
> >                 appendStringInfoChar(buf, '(');

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: ruleutils with pretty-print option

From
Andreas Pflug
Date:
Bruce Momjian wrote:

>Andreas, looks good, but I need a diff -c, context diff.
>
>
>
Hi Bruce,
I intentionally only attached only non-context diffs because the patch
is about 50 % size of the original file. Now, here's the same as context
diff.

Regards,
Andreas
Index: pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
retrieving revision 1.309
diff -c -r1.309 pg_proc.h
*** pg_proc.h    1 Jul 2003 00:04:38 -0000    1.309
--- pg_proc.h    22 Jul 2003 12:52:07 -0000
***************
*** 3405,3410 ****
--- 3405,3424 ----
  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 - _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 - _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 - _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 - _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 - _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 - _null_ ));
+ DESCR("deparse an encoded expression with pretty-print option");
+

  /*
   * Symbolic values for provolatile column: these indicate whether the result
Index: ruleutils.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.145
diff -c -r1.145 ruleutils.c
*** ruleutils.c    4 Jul 2003 02:51:34 -0000    1.145
--- ruleutils.c    22 Jul 2003 12:54:10 -0000
***************
*** 71,76 ****
--- 71,95 ----
  #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,86 ****
--- 100,107 ----
  {
      StringInfo    buf;            /* output buffer to append to */
      List       *namespaces;        /* List of deparse_namespace nodes */
+         int             prettyFlags;            /* enabling/disabling of pretty-print functions */
+         int             indentLevel;            /* for prettyPrint, current space indents are counted */
      bool        varprefix;        /* TRUE to print prefixes on Vars */
  } deparse_context;

***************
*** 123,135 ****
   * as a parameter, and append their text output to its contents.
   * ----------
   */
! static text *pg_do_getviewdef(Oid viewoid);
  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 void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
!               TupleDesc resultDesc);
  static void get_select_query_def(Query *query, deparse_context *context,
                       TupleDesc resultDesc);
  static void get_insert_query_def(Query *query, deparse_context *context);
--- 144,162 ----
   * as a parameter, and append their text output to its contents.
   * ----------
   */
! static char *get_simple_binary_op_name(OpExpr *expr);
! static void appendStringInfoSpace(StringInfo buf, int count);
! static void appendContextKeyword(deparse_context *context, char *str, int indentBefore, int indentAfter, int
indentPlus);
! static char *deparse_expression_pretty(Node *expr, List *dpcontext,
!               bool forceprefix, bool showimplicit, int prettyFlags, int startIndent);
! static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
! 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, 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, 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);
***************
*** 192,197 ****
--- 219,225 ----
      TupleDesc    rulettc;
      StringInfoData buf;
      int            len;
+     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;

      /*
       * Connect to SPI manager
***************
*** 241,247 ****
       * Get the rules definition and put it into executors memory
       */
      initStringInfo(&buf);
!     make_ruledef(&buf, ruletup, rulettc);
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
      VARATT_SIZEP(ruledef) = len;
--- 269,275 ----
       * Get the rules definition and put it into executors memory
       */
      initStringInfo(&buf);
!     make_ruledef(&buf, ruletup, rulettc, prettyFlags);
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
      VARATT_SIZEP(ruledef) = len;
***************
*** 272,279 ****
      /* By OID */
      Oid            viewoid = PG_GETARG_OID(0);
      text       *ruledef;

!     ruledef = pg_do_getviewdef(viewoid);
      PG_RETURN_TEXT_P(ruledef);
  }

--- 300,308 ----
      /* By OID */
      Oid            viewoid = PG_GETARG_OID(0);
      text       *ruledef;
+     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;

!     ruledef = pg_do_getviewdef(viewoid, prettyFlags);
      PG_RETURN_TEXT_P(ruledef);
  }

***************
*** 285,296 ****
      RangeVar   *viewrel;
      Oid            viewoid;
      text       *ruledef;

      viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname,
                                                           "get_viewdef"));
      viewoid = RangeVarGetRelid(viewrel, false);

!     ruledef = pg_do_getviewdef(viewoid);
      PG_RETURN_TEXT_P(ruledef);
  }

--- 314,326 ----
      RangeVar   *viewrel;
      Oid            viewoid;
      text       *ruledef;
+     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? 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,304 ****
   * Common code for by-OID and by-name variants of pg_get_viewdef
   */
  static text *
! pg_do_getviewdef(Oid viewoid)
  {
      text       *ruledef;
      Datum        args[2];
--- 328,334 ----
   * Common code for by-OID and by-name variants of pg_get_viewdef
   */
  static text *
! pg_do_getviewdef(Oid viewoid, int prettyFlags)
  {
      text       *ruledef;
      Datum        args[2];
***************
*** 353,359 ****
           */
          ruletup = SPI_tuptable->vals[0];
          rulettc = SPI_tuptable->tupdesc;
!         make_viewdef(&buf, ruletup, rulettc);
      }
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
--- 383,389 ----
           */
          ruletup = SPI_tuptable->vals[0];
          rulettc = SPI_tuptable->tupdesc;
!         make_viewdef(&buf, ruletup, rulettc, prettyFlags);
      }
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
***************
*** 544,549 ****
--- 574,581 ----
      StringInfoData buf;
      char       *str;
      char       *sep;
+     int        colno = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);
+     int        prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;

      /*
       * Fetch the pg_index tuple by the Oid of the index
***************
*** 582,587 ****
--- 614,621 ----
       * Get the index expressions, if any.  (NOTE: we do not use the relcache
       * versions of the expressions and predicate, because we want to display
       * non-const-folded expressions.)
+          * if colno == 0, we want a complete index definition.
+          * if colno > 0, we only want the nth expression.
       */
      if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
      {
***************
*** 607,613 ****
       * never be schema-qualified, but the indexed rel's name may be.
       */
      initStringInfo(&buf);
!     appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
                       idxrec->indisunique ? "UNIQUE " : "",
                       quote_identifier(NameStr(idxrelrec->relname)),
                       generate_relation_name(indrelid),
--- 641,649 ----
       * never be schema-qualified, but the indexed rel's name may be.
       */
      initStringInfo(&buf);
!
!     if (!colno)
!         appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
                       idxrec->indisunique ? "UNIQUE " : "",
                       quote_identifier(NameStr(idxrelrec->relname)),
                       generate_relation_name(indrelid),
***************
*** 621,627 ****
      {
          AttrNumber    attnum = idxrec->indkey[keyno];

!         appendStringInfo(&buf, sep);
          sep = ", ";

          if (attnum != 0)
--- 657,664 ----
      {
          AttrNumber    attnum = idxrec->indkey[keyno];

!         if (!colno)
!             appendStringInfo(&buf, sep);
          sep = ", ";

          if (attnum != 0)
***************
*** 630,636 ****
              char       *attname;

              attname = get_relid_attribute_name(indrelid, attnum);
!             appendStringInfo(&buf, "%s", quote_identifier(attname));
              keycoltype = get_atttype(indrelid, attnum);
          }
          else
--- 667,674 ----
              char       *attname;

              attname = get_relid_attribute_name(indrelid, attnum);
!             if (!colno || colno == keyno+1)
!                 appendStringInfo(&buf, "%s", quote_identifier(attname));
              keycoltype = get_atttype(indrelid, attnum);
          }
          else
***************
*** 643,672 ****
              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);
              keycoltype = exprType(indexkey);
          }

          /*
           * Add the operator class name
           */
!         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))
      {
          Node       *node;
          Datum        predDatum;
          bool        isnull;
--- 681,716 ----
              indexkey = (Node *) lfirst(indexprs);
              indexprs = lnext(indexprs);
              /* Deparse */
!             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
           */
!         if (!colno)
!             get_opclass_name(idxrec->indclass[keyno], keycoltype,
                           &buf);
      }

!     if (!colno)
      {
+         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;
***************
*** 689,698 ****
          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);
      }
-
      /*
       * Create the result as a TEXT datum, and free working data
       */
--- 733,742 ----
          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);
+         }
      }
      /*
       * Create the result as a TEXT datum, and free working data
       */
***************
*** 729,734 ****
--- 773,779 ----
      ScanKeyData skey[1];
      HeapTuple    tup;
      Form_pg_constraint conForm;
+     int      prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;

      /*
       * Fetch the pg_constraint row.  There's no syscache for pg_constraint
***************
*** 934,940 ****
                      context = deparse_context_for(get_typname(conForm->contypid),
                                                    InvalidOid);

!                 consrc = deparse_expression(expr, context, false, false);

                  /* Append the constraint source */
                  appendStringInfoString(&buf, consrc);
--- 979,985 ----
                      context = deparse_context_for(get_typname(conForm->contypid),
                                                    InvalidOid);

!                 consrc = deparse_expression_pretty(expr, context, false, false, prettyFlags, 0);

                  /* Append the constraint source */
                  appendStringInfoString(&buf, consrc);
***************
*** 1018,1023 ****
--- 1063,1069 ----
      char       *exprstr;
      char       *relname;
      char       *str;
+     int      prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;

      /* Get the name for the relation */
      relname = get_rel_name(relid);
***************
*** 1041,1047 ****

      /* Deparse */
      context = deparse_context_for(relname, relid);
!     str = deparse_expression(node, context, false, false);

      /* Pass the result back as TEXT */
      result = DatumGetTextP(DirectFunctionCall1(textin,
--- 1087,1093 ----

      /* Deparse */
      context = deparse_context_for(relname, relid);
!     str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0);

      /* Pass the result back as TEXT */
      result = DatumGetTextP(DirectFunctionCall1(textin,
***************
*** 1090,1095 ****
--- 1136,1152 ----

  /* ----------
   * 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).
***************
*** 1100,1112 ****
   * 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.
   *
   * The result is a palloc'd string.
   * ----------
   */
  char *
! deparse_expression(Node *expr, List *dpcontext,
!                    bool forceprefix, bool showimplicit)
  {
      StringInfoData buf;
      deparse_context context;
--- 1157,1171 ----
   * 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
   *
   * The result is a palloc'd string.
   * ----------
   */
  char *
! deparse_expression_pretty(Node *expr, List *dpcontext,
!                    bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
  {
      StringInfoData buf;
      deparse_context context;
***************
*** 1115,1120 ****
--- 1174,1181 ----
      context.buf = &buf;
      context.namespaces = dpcontext;
      context.varprefix = forceprefix;
+     context.prettyFlags = prettyFlags;
+     context.indentLevel = startIndent;

      get_rule_expr(expr, &context, showimplicit);

***************
*** 1267,1273 ****
   * ----------
   */
  static void
! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
  {
      char       *rulename;
      char        ev_type;
--- 1328,1334 ----
   * ----------
   */
  static void
! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
  {
      char       *rulename;
      char        ev_type;
***************
*** 1321,1329 ****
      /*
       * Build the rules definition text
       */
!     appendStringInfo(buf, "CREATE RULE %s AS ON ",
                       quote_identifier(rulename));

      /* The event the rule is fired for */
      switch (ev_type)
      {
--- 1382,1395 ----
      /*
       * Build the rules definition text
       */
!     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)
      {
***************
*** 1366,1371 ****
--- 1432,1439 ----
          deparse_context context;
          deparse_namespace dpns;

+         if (prettyFlags & PRETTYFLAG_INDENT)
+             appendStringInfoString(buf, "\n  ");
          appendStringInfo(buf, " WHERE ");

          qual = stringToNode(ev_qual);
***************
*** 1387,1392 ****
--- 1455,1462 ----
          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;
***************
*** 1410,1417 ****
          foreach(action, actions)
          {
              query = (Query *) lfirst(action);
!             get_query_def(query, buf, NIL, NULL);
!             appendStringInfo(buf, "; ");
          }
          appendStringInfo(buf, ");");
      }
--- 1480,1490 ----
          foreach(action, actions)
          {
              query = (Query *) lfirst(action);
!             get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
!             if (prettyFlags)
!                 appendStringInfo(buf, ";\n");
!             else
!                 appendStringInfo(buf, "; ");
          }
          appendStringInfo(buf, ");");
      }
***************
*** 1424,1430 ****
          Query       *query;

          query = (Query *) lfirst(actions);
!         get_query_def(query, buf, NIL, NULL);
          appendStringInfo(buf, ";");
      }
  }
--- 1497,1503 ----
          Query       *query;

          query = (Query *) lfirst(actions);
!         get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
          appendStringInfo(buf, ";");
      }
  }
***************
*** 1436,1442 ****
   * ----------
   */
  static void
! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
  {
      Query       *query;
      char        ev_type;
--- 1509,1515 ----
   * ----------
   */
  static void
! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
  {
      Query       *query;
      char        ev_type;
***************
*** 1490,1496 ****

      ev_relation = heap_open(ev_class, AccessShareLock);

!     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation));
      appendStringInfo(buf, ";");

      heap_close(ev_relation, AccessShareLock);
--- 1563,1569 ----

      ev_relation = heap_open(ev_class, AccessShareLock);

!     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), prettyFlags, 0);
      appendStringInfo(buf, ";");

      heap_close(ev_relation, AccessShareLock);
***************
*** 1506,1512 ****
   */
  static void
  get_query_def(Query *query, StringInfo buf, List *parentnamespace,
!               TupleDesc resultDesc)
  {
      deparse_context context;
      deparse_namespace dpns;
--- 1579,1585 ----
   */
  static void
  get_query_def(Query *query, StringInfo buf, List *parentnamespace,
!               TupleDesc resultDesc, int prettyFlags, int startIndent)
  {
      deparse_context context;
      deparse_namespace dpns;
***************
*** 1515,1520 ****
--- 1588,1596 ----
      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;
***************
*** 1586,1592 ****
      /* Add the ORDER BY clause if given */
      if (query->sortClause != NIL)
      {
!         appendStringInfo(buf, " ORDER BY ");
          sep = "";
          foreach(l, query->sortClause)
          {
--- 1662,1668 ----
      /* Add the ORDER BY clause if given */
      if (query->sortClause != NIL)
      {
!             appendContextKeyword(context, " ORDER BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          sep = "";
          foreach(l, query->sortClause)
          {
***************
*** 1615,1626 ****
      /* Add the LIMIT clause if given */
      if (query->limitOffset != NULL)
      {
!         appendStringInfo(buf, " OFFSET ");
          get_rule_expr(query->limitOffset, context, false);
      }
      if (query->limitCount != NULL)
      {
!         appendStringInfo(buf, " LIMIT ");
          if (IsA(query->limitCount, Const) &&
              ((Const *) query->limitCount)->constisnull)
              appendStringInfo(buf, "ALL");
--- 1691,1702 ----
      /* Add the LIMIT clause if given */
      if (query->limitOffset != NULL)
      {
!         appendContextKeyword(context, " OFFSET ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
          get_rule_expr(query->limitOffset, context, false);
      }
      if (query->limitCount != NULL)
      {
!         appendContextKeyword(context, " LIMIT ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
          if (IsA(query->limitCount, Const) &&
              ((Const *) query->limitCount)->constisnull)
              appendStringInfo(buf, "ALL");
***************
*** 1641,1646 ****
--- 1717,1727 ----
      /*
       * 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 */
***************
*** 1720,1733 ****
      /* Add the WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendStringInfo(buf, " WHERE ");
          get_rule_expr(query->jointree->quals, context, false);
      }

      /* Add the GROUP BY clause if given */
      if (query->groupClause != NULL)
      {
!         appendStringInfo(buf, " GROUP BY ");
          sep = "";
          foreach(l, query->groupClause)
          {
--- 1801,1814 ----
      /* Add the WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         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)
      {
!         appendContextKeyword(context, " GROUP BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          sep = "";
          foreach(l, query->groupClause)
          {
***************
*** 1743,1749 ****
      /* Add the HAVING clause if given */
      if (query->havingQual != NULL)
      {
!         appendStringInfo(buf, " HAVING ");
          get_rule_expr(query->havingQual, context, false);
      }
  }
--- 1824,1830 ----
      /* Add the HAVING clause if given */
      if (query->havingQual != NULL)
      {
!         appendContextKeyword(context, " HAVING ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
          get_rule_expr(query->havingQual, context, false);
      }
  }
***************
*** 1761,1795 ****
          Query       *subquery = rte->subquery;

          Assert(subquery != NULL);
!         get_query_def(subquery, buf, context->namespaces, resultDesc);
      }
      else if (IsA(setOp, SetOperationStmt))
      {
          SetOperationStmt *op = (SetOperationStmt *) setOp;

-         appendStringInfo(buf, "((");
          get_setop_query(op->larg, query, context, resultDesc);
          switch (op->op)
          {
              case SETOP_UNION:
!                 appendStringInfo(buf, ") UNION ");
                  break;
              case SETOP_INTERSECT:
!                 appendStringInfo(buf, ") INTERSECT ");
                  break;
              case SETOP_EXCEPT:
!                 appendStringInfo(buf, ") EXCEPT ");
                  break;
              default:
                  elog(ERROR, "get_setop_query: unexpected set op %d",
                       (int) op->op);
          }
          if (op->all)
!             appendStringInfo(buf, "ALL (");
          else
!             appendStringInfo(buf, "(");
          get_setop_query(op->rarg, query, context, resultDesc);
!         appendStringInfo(buf, "))");
      }
      else
      {
--- 1842,1905 ----
          Query       *subquery = rte->subquery;

          Assert(subquery != NULL);
!         get_query_def(subquery, buf, context->namespaces, resultDesc, context->prettyFlags, context->indentLevel);
      }
      else if (IsA(setOp, SetOperationStmt))
      {
          SetOperationStmt *op = (SetOperationStmt *) setOp;
+         bool need_paren=(PRETTY_PAREN(context) ? !IsA(op->rarg, RangeTblRef) : true);
+
+         if (!PRETTY_PAREN(context))
+             appendStringInfoString(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:
!                 appendContextKeyword(context, "UNION ", -PRETTYINDENT_STD, 0, 0);
                  break;
              case SETOP_INTERSECT:
!                 appendContextKeyword(context, "INTERSECT ", -PRETTYINDENT_STD, 0, 0);
                  break;
              case SETOP_EXCEPT:
!                 appendContextKeyword(context, "EXCEPT ", -PRETTYINDENT_STD, 0, 0);
                  break;
              default:
                  elog(ERROR, "get_setop_query: unexpected set op %d",
                       (int) op->op);
          }
          if (op->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
!             appendStringInfoChar(buf, '(');
!
          get_setop_query(op->rarg, query, context, resultDesc);
!
!         if (PRETTY_PAREN(context))
!         {
!             if (need_paren)
!             appendStringInfoChar(buf, ')');
!         }
!         else
!             appendStringInfoString(buf, "))");
      }
      else
      {
***************
*** 1862,1867 ****
--- 1972,1983 ----
       */
      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));

***************
*** 1883,1889 ****
      /* Add the VALUES or the SELECT */
      if (select_rte == NULL)
      {
!         appendStringInfo(buf, "VALUES (");
          sep = "";
          foreach(l, query->targetList)
          {
--- 1999,2005 ----
      /* Add the VALUES or the SELECT */
      if (select_rte == NULL)
      {
!         appendContextKeyword(context, "VALUES (", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
          sep = "";
          foreach(l, query->targetList)
          {
***************
*** 1899,1905 ****
          appendStringInfoChar(buf, ')');
      }
      else
!         get_query_def(select_rte->subquery, buf, NIL, NULL);
  }


--- 2015,2021 ----
          appendStringInfoChar(buf, ')');
      }
      else
!         get_query_def(select_rte->subquery, buf, NIL, NULL, context->prettyFlags, context->indentLevel);
  }


***************
*** 1920,1925 ****
--- 2036,2046 ----
       */
      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));
***************
*** 1953,1959 ****
      /* Finally add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendStringInfo(buf, " WHERE ");
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
--- 2074,2080 ----
      /* Finally add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
***************
*** 1974,1979 ****
--- 2095,2105 ----
       */
      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));
***************
*** 1981,1987 ****
      /* Add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendStringInfo(buf, " WHERE ");
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
--- 2107,2113 ----
      /* Add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
***************
*** 2000,2005 ****
--- 2126,2132 ----
      {
          NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;

+         appendContextKeyword(context, "", 0, PRETTYINDENT_STD, 1);
          appendStringInfo(buf, "NOTIFY %s",
                     quote_qualified_identifier(stmt->relation->schemaname,
                                                stmt->relation->relname));
***************
*** 2140,2145 ****
--- 2267,2508 ----
  }


+ /********************************************
+  * get_simple_binary_op_name
+  * helper function for isSimpleNode
+  * will return single char binary operator
+  *******************************************/
+
+ static 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);
+         char *op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
+
+         if (strlen(op) == 1)
+             return op;
+     }
+     return 0;
+ }
+
+
+ /***************************************
+  * check if given node is simple.
+  *  false  : not simple
+  *  true   : simple in the context of parent node's type
+  ***************************************/
+
+ static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
+ {
+     if (!node)
+     return true;
+
+     switch (nodeTag(node))
+     {
+     // single words: always simple
+     case T_Var:
+     case T_Const:
+     case T_Param:
+
+     // function-like: name(..) or name[..]
+     case T_ArrayRef:
+     case T_ArrayExpr:
+     case T_CoalesceExpr:
+     case T_NullIfExpr:
+     case T_Aggref:
+     case T_FuncExpr:
+
+         // CASE keywords act as parentheses
+     case T_CaseExpr:
+         return true;
+
+         // appears simple since . has top precedence, unless parent is T_FieldSelect itself!
+     case T_FieldSelect:
+         return (nodeTag(parentNode) == T_FieldSelect ? false : true);
+
+
+         // maybe simple, check args
+     case T_CoerceToDomain:
+         return isSimpleNode((Node*) ((CoerceToDomain*)node)->arg, node, prettyFlags);
+     case T_RelabelType:
+         return isSimpleNode((Node*) ((RelabelType*)node)->arg, node, prettyFlags);
+
+
+     // depends on parent node type; needs further checking
+     case T_OpExpr:
+     {
+         if (prettyFlags & PRETTYFLAG_PAREN && nodeTag(parentNode) == T_OpExpr)
+         {
+         char *op=get_simple_binary_op_name((OpExpr*)node);
+         char *parentOp=get_simple_binary_op_name((OpExpr*)parentNode);
+         if (!op || !parentOp)
+             return false;
+
+                 // we know only these basic operators
+         if (!strchr("+-*/%", *op) || !strchr("+-*/%", *parentOp))
+             return false;
+
+         // natural operator precedence, so we don't need parentheses
+         if (strchr("*/%", *op) || strchr("+-", *parentOp))
+             return true;
+
+         return false;
+         }
+             // else do the same stuff as for T_SubLink et al.
+     }
+     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=((BoolExpr*)node)->boolop;
+             BoolExprType 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;
+         }
+         // these are not completely implemented; so far, they're simple
+     case T_SubPlan:
+     case T_CoerceToDomainValue:
+         return true;
+
+     case T_ScalarArrayOpExpr:
+         // need to check
+     default:
+         break;
+     }
+     // those we don't know: in dubio complexo
+     return false;
+ }
+
+
+ /******************************************
+  * appendContextKeyword
+  * append spaces to buffer
+  ******************************************/
+ static void appendStringInfoSpace(StringInfo buf, int count)
+ {
+     while (count-- > 0)
+     appendStringInfoChar(buf, ' ');
+ }
+
+ /******************************************
+  * appendContextKeyword
+  * performing a line break, and indentation
+  * if prettyPrint is enabled.
+  * Otherwise, only the keyword is appended
+  *****************************************/
+
+ static void appendContextKeyword(deparse_context *context, 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');
+     appendStringInfoSpace(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  - parsing expr using get_rule_expr,
+  * embracing the string with parentheses if necessary for prettyPrint.
+  * never embracing 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 = 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
   *
***************
*** 2294,2305 ****
                  List       *args = expr->args;
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);
!
!                 appendStringInfoChar(buf, '(');
!                 get_rule_expr(arg1, context, true);
                  appendStringInfo(buf, " IS DISTINCT FROM ");
!                 get_rule_expr(arg2, context, true);
!                 appendStringInfoChar(buf, ')');
              }
              break;

--- 2657,2669 ----
                  List       *args = expr->args;
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, '(');
!                 get_rule_expr_paren(arg1, context, true, node);
                  appendStringInfo(buf, " IS DISTINCT FROM ");
!                 get_rule_expr_paren(arg2, context, true, node);
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, ')');
              }
              break;

***************
*** 2310,2324 ****
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);

!                 appendStringInfoChar(buf, '(');
!                 get_rule_expr(arg1, context, true);
                  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, "))");
              }
              break;

--- 2674,2692 ----
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);

!                 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_paren(arg2, context, true, node);
!                 appendStringInfoString(buf, ")");
!
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, ')');
              }
              break;

***************
*** 2330,2362 ****
                  switch (expr->boolop)
                  {
                      case AND_EXPR:
!                         appendStringInfoChar(buf, '(');
!                         get_rule_expr((Node *) lfirst(args), context, false);
                          while ((args = lnext(args)) != NIL)
                          {
                              appendStringInfo(buf, " AND ");
!                             get_rule_expr((Node *) lfirst(args), context,
!                                           false);
                          }
!                         appendStringInfoChar(buf, ')');
                          break;

                      case OR_EXPR:
!                         appendStringInfoChar(buf, '(');
!                         get_rule_expr((Node *) lfirst(args), context, false);
                          while ((args = lnext(args)) != NIL)
                          {
                              appendStringInfo(buf, " OR ");
!                             get_rule_expr((Node *) lfirst(args), context,
!                                           false);
                          }
!                         appendStringInfoChar(buf, ')');
                          break;

                      case NOT_EXPR:
!                         appendStringInfo(buf, "(NOT ");
!                         get_rule_expr((Node *) lfirst(args), context, false);
!                         appendStringInfoChar(buf, ')');
                          break;

                      default:
--- 2698,2737 ----
                  switch (expr->boolop)
                  {
                      case AND_EXPR:
!                             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_paren((Node *) lfirst(args), context,
!                                           false, node);
                          }
!                             if (!PRETTY_PAREN(context))
!                             appendStringInfoChar(buf, ')');
                          break;

                      case OR_EXPR:
!                             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_paren((Node *) lfirst(args), context,
!                                           false, node);
                          }
!                             if (!PRETTY_PAREN(context))
!                             appendStringInfoChar(buf, ')');
                          break;

                      case NOT_EXPR:
!                             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:
***************
*** 2404,2412 ****
                   * 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));
              }
              break;

--- 2779,2790 ----
                   * arg.fieldname, but most cases where FieldSelect is used
                   * are *not* simple.  So, always use parenthesized syntax.
                   */
!                     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;

***************
*** 2419,2425 ****
                      !showimplicit)
                  {
                      /* don't show the implicit cast */
!                     get_rule_expr(arg, context, showimplicit);
                  }
                  else
                  {
--- 2797,2803 ----
                      !showimplicit)
                  {
                      /* don't show the implicit cast */
!                     get_rule_expr_paren(arg, context, showimplicit, node);
                  }
                  else
                  {
***************
*** 2431,2439 ****
                       */
                      arg = strip_type_coercion(arg, relabel->resulttype);

!                     appendStringInfoChar(buf, '(');
!                     get_rule_expr(arg, context, showimplicit);
!                     appendStringInfo(buf, ")::%s",
                              format_type_with_typemod(relabel->resulttype,
                                                       relabel->resulttypmod));
                  }
--- 2809,2821 ----
                       */
                      arg = strip_type_coercion(arg, relabel->resulttype);

!                     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));
                  }
***************
*** 2445,2463 ****
                  CaseExpr   *caseexpr = (CaseExpr *) node;
                  List       *temp;

!                 appendStringInfo(buf, "CASE");
                  foreach(temp, caseexpr->args)
                  {
                      CaseWhen   *when = (CaseWhen *) lfirst(temp);

!                     appendStringInfo(buf, " WHEN ");
                      get_rule_expr((Node *) when->expr, context, false);
                      appendStringInfo(buf, " THEN ");
                      get_rule_expr((Node *) when->result, context, true);
                  }
!                 appendStringInfo(buf, " ELSE ");
                  get_rule_expr((Node *) caseexpr->defresult, context, true);
!                 appendStringInfo(buf, " END");
              }
              break;

--- 2827,2853 ----
                  CaseExpr   *caseexpr = (CaseExpr *) node;
                  List       *temp;

!                 appendContextKeyword(context, "CASE", 0, PRETTYINDENT_VAR, 0);
                  foreach(temp, caseexpr->args)
                  {
                      CaseWhen   *when = (CaseWhen *) lfirst(temp);

!                     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);
                  }
!                 if (!PRETTY_INDENT(context))
!                     appendStringInfoChar(buf, ' ');
!                 appendContextKeyword(context, "ELSE ", 0, 0, 0);
                  get_rule_expr((Node *) caseexpr->defresult, context, true);
!                 if (!PRETTY_INDENT(context))
!                     appendStringInfoChar(buf, ' ');
!                 appendContextKeyword(context, "END", -PRETTYINDENT_VAR, 0, 0);
              }
              break;

***************
*** 2525,2544 ****
              {
                  NullTest   *ntest = (NullTest *) node;

!                 appendStringInfo(buf, "(");
!                 get_rule_expr((Node *) ntest->arg, context, true);
                  switch (ntest->nulltesttype)
                  {
                      case IS_NULL:
!                         appendStringInfo(buf, " IS NULL)");
                          break;
                      case IS_NOT_NULL:
!                         appendStringInfo(buf, " IS NOT NULL)");
                          break;
                      default:
                          elog(ERROR, "get_rule_expr: unexpected nulltesttype %d",
                               (int) ntest->nulltesttype);
                  }
              }
              break;

--- 2915,2937 ----
              {
                  NullTest   *ntest = (NullTest *) node;

!                 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");
                          break;
                      case IS_NOT_NULL:
!                         appendStringInfo(buf, " IS NOT NULL");
                          break;
                      default:
                          elog(ERROR, "get_rule_expr: unexpected nulltesttype %d",
                               (int) ntest->nulltesttype);
                  }
+                 if (!PRETTY_PAREN(context))
+                     appendStringInfoChar(buf, ')');
              }
              break;

***************
*** 2546,2577 ****
              {
                  BooleanTest *btest = (BooleanTest *) node;

!                 appendStringInfo(buf, "(");
!                 get_rule_expr((Node *) btest->arg, context, false);
                  switch (btest->booltesttype)
                  {
                      case IS_TRUE:
!                         appendStringInfo(buf, " IS TRUE)");
                          break;
                      case IS_NOT_TRUE:
!                         appendStringInfo(buf, " IS NOT TRUE)");
                          break;
                      case IS_FALSE:
!                         appendStringInfo(buf, " IS FALSE)");
                          break;
                      case IS_NOT_FALSE:
!                         appendStringInfo(buf, " IS NOT FALSE)");
                          break;
                      case IS_UNKNOWN:
!                         appendStringInfo(buf, " IS UNKNOWN)");
                          break;
                      case IS_NOT_UNKNOWN:
!                         appendStringInfo(buf, " IS NOT UNKNOWN)");
                          break;
                      default:
                          elog(ERROR, "get_rule_expr: unexpected booltesttype %d",
                               (int) btest->booltesttype);
                  }
              }
              break;

--- 2939,2973 ----
              {
                  BooleanTest *btest = (BooleanTest *) node;

!                 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");
                          break;
                      case IS_NOT_TRUE:
!                         appendStringInfo(buf, " IS NOT TRUE");
                          break;
                      case IS_FALSE:
!                         appendStringInfo(buf, " IS FALSE");
                          break;
                      case IS_NOT_FALSE:
!                         appendStringInfo(buf, " IS NOT FALSE");
                          break;
                      case IS_UNKNOWN:
!                         appendStringInfo(buf, " IS UNKNOWN");
                          break;
                      case IS_NOT_UNKNOWN:
!                         appendStringInfo(buf, " IS NOT UNKNOWN");
                          break;
                      default:
                          elog(ERROR, "get_rule_expr: unexpected booltesttype %d",
                               (int) btest->booltesttype);
                  }
+                 if (!PRETTY_PAREN(context))
+                     appendStringInfoChar(buf, ')');
              }
              break;

***************
*** 2593,2601 ****
                  }
                  else
                  {
!                     appendStringInfoChar(buf, '(');
!                     get_rule_expr(arg, context, false);
!                     appendStringInfo(buf, ")::%s",
                              format_type_with_typemod(ctest->resulttype,
                                                       ctest->resulttypmod));
                  }
--- 2989,3002 ----
                  }
                  else
                  {
!                     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));
                  }
***************
*** 2627,2645 ****
      Oid            opno = expr->opno;
      List       *args = expr->args;

!     appendStringInfoChar(buf, '(');
      if (length(args) == 2)
      {
          /* binary operator */
          Node       *arg1 = (Node *) lfirst(args);
          Node       *arg2 = (Node *) lsecond(args);
!
!         get_rule_expr(arg1, context, true);
          appendStringInfo(buf, " %s ",
                           generate_operator_name(opno,
                                                  exprType(arg1),
                                                  exprType(arg2)));
!         get_rule_expr(arg2, context, true);
      }
      else
      {
--- 3028,3046 ----
      Oid            opno = expr->opno;
      List       *args = expr->args;

!     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_paren(arg1, context, true, (Node*)expr);
          appendStringInfo(buf, " %s ",
                           generate_operator_name(opno,
                                                  exprType(arg1),
                                                  exprType(arg2)));
!         get_rule_expr_paren(arg2, context, true, (Node*)expr);
      }
      else
      {
***************
*** 2661,2670 ****
                                   generate_operator_name(opno,
                                                          InvalidOid,
                                                          exprType(arg)));
!                 get_rule_expr(arg, context, true);
                  break;
              case 'r':
!                 get_rule_expr(arg, context, true);
                  appendStringInfo(buf, " %s",
                                   generate_operator_name(opno,
                                                          exprType(arg),
--- 3062,3071 ----
                                   generate_operator_name(opno,
                                                          InvalidOid,
                                                          exprType(arg)));
!                 get_rule_expr_paren(arg, context, true, (Node*)expr);
                  break;
              case 'r':
!                 get_rule_expr_paren(arg, context, true, (Node*)expr);
                  appendStringInfo(buf, " %s",
                                   generate_operator_name(opno,
                                                          exprType(arg),
***************
*** 2675,2681 ****
          }
          ReleaseSysCache(tp);
      }
!     appendStringInfoChar(buf, ')');
  }

  /*
--- 3076,3083 ----
          }
          ReleaseSysCache(tp);
      }
!     if (!PRETTY_PAREN(context))
!         appendStringInfoChar(buf, ')');
  }

  /*
***************
*** 2698,2704 ****
       */
      if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
      {
!         get_rule_expr((Node *) lfirst(expr->args), context, showimplicit);
          return;
      }

--- 3100,3106 ----
       */
      if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
      {
!         get_rule_expr_paren((Node *) lfirst(expr->args), context, showimplicit, (Node*)expr);
          return;
      }

***************
*** 2724,2732 ****
           */
          arg = strip_type_coercion(arg, rettype);

!         appendStringInfoChar(buf, '(');
!         get_rule_expr(arg, context, showimplicit);
!         appendStringInfo(buf, ")::%s",
                           format_type_with_typemod(rettype, coercedTypmod));

          return;
--- 3126,3139 ----
           */
          arg = strip_type_coercion(arg, rettype);

!         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;
***************
*** 3047,3053 ****
      if (need_paren)
          appendStringInfoChar(buf, '(');

!     get_query_def(query, buf, context->namespaces, NULL);

      if (need_paren)
          appendStringInfo(buf, "))");
--- 3454,3460 ----
      if (need_paren)
          appendStringInfoChar(buf, '(');

!     get_query_def(query, buf, context->namespaces, NULL, context->prettyFlags, context->indentLevel);

      if (need_paren)
          appendStringInfo(buf, "))");
***************
*** 3064,3070 ****
  get_from_clause(Query *query, deparse_context *context)
  {
      StringInfo    buf = context->buf;
!     char       *sep;
      List       *l;

      /*
--- 3471,3477 ----
  get_from_clause(Query *query, deparse_context *context)
  {
      StringInfo    buf = context->buf;
!     char       *sep=0;
      List       *l;

      /*
***************
*** 3074,3080 ****
       * sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW
       * and OLD.
       */
-     sep = " FROM ";

      foreach(l, query->jointree->fromlist)
      {
--- 3481,3486 ----
***************
*** 3093,3099 ****
                  continue;
          }

!         appendStringInfo(buf, sep);
          get_from_clause_item(jtnode, query, context);
          sep = ", ";
      }
--- 3499,3509 ----
                  continue;
          }

!         if (!sep)
!             appendContextKeyword(context, " FROM ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
!         else
!             appendStringInfo(buf, sep);
!
          get_from_clause_item(jtnode, query, context);
          sep = ", ";
      }
***************
*** 3122,3128 ****
              case RTE_SUBQUERY:
                  /* Subquery RTE */
                  appendStringInfoChar(buf, '(');
!                 get_query_def(rte->subquery, buf, context->namespaces, NULL);
                  appendStringInfoChar(buf, ')');
                  break;
              case RTE_FUNCTION:
--- 3532,3539 ----
              case RTE_SUBQUERY:
                  /* Subquery RTE */
                  appendStringInfoChar(buf, '(');
!                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
!                           context->prettyFlags, context->indentLevel);
                  appendStringInfoChar(buf, ')');
                  break;
              case RTE_FUNCTION:
***************
*** 3144,3150 ****
              {
                  List       *col;

!                 appendStringInfo(buf, "(");
                  foreach(col, rte->alias->colnames)
                  {
                      if (col != rte->alias->colnames)
--- 3555,3561 ----
              {
                  List       *col;

!                 appendStringInfoChar(buf, '(');
                  foreach(col, rte->alias->colnames)
                  {
                      if (col != rte->alias->colnames)
***************
*** 3178,3213 ****
      else if (IsA(jtnode, JoinExpr))
      {
          JoinExpr   *j = (JoinExpr *) jtnode;

-         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, "get_from_clause_item: unknown join type %d",
                       (int) j->jointype);
          }
          get_from_clause_item(j->rarg, query, context);
          if (!j->isNatural)
          {
              if (j->using)
--- 3589,3666 ----
      else if (IsA(jtnode, JoinExpr))
      {
          JoinExpr   *j = (JoinExpr *) jtnode;
+         bool need_paren_on_right = PRETTY_PAREN(context) && !IsA(j->rarg, RangeTblRef);
+
+         if (!PRETTY_PAREN(context) || j->alias != NULL)
+             appendStringInfoChar(buf, '(');

          get_from_clause_item(j->larg, query, context);
+
          if (j->isNatural)
          {
+             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, "get_from_clause_item: unknown 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, "get_from_clause_item: unknown 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)
***************
*** 3226,3237 ****
              }
              else if (j->quals)
              {
!                 appendStringInfo(buf, " ON (");
                  get_rule_expr(j->quals, context, false);
!                 appendStringInfoChar(buf, ')');
              }
          }
!         appendStringInfoChar(buf, ')');
          /* Yes, it's correct to put alias after the right paren ... */
          if (j->alias != NULL)
          {
--- 3679,3695 ----
              }
              else if (j->quals)
              {
!                 appendStringInfo(buf, " ON ");
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, '(');
                  get_rule_expr(j->quals, context, false);
!                 if (!PRETTY_PAREN(context))
!                     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)
          {
***************
*** 3241,3247 ****
              {
                  List       *col;

!                 appendStringInfo(buf, "(");
                  foreach(col, j->alias->colnames)
                  {
                      if (col != j->alias->colnames)
--- 3699,3705 ----
              {
                  List       *col;

!                 appendStringInfoChar(buf, '(');
                  foreach(col, j->alias->colnames)
                  {
                      if (col != j->alias->colnames)

Re: ruleutils with pretty-print option

From
Bruce Momjian
Date:
Your patch has been added to the PostgreSQL unapplied patches list at:

    http://momjian.postgresql.org/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

---------------------------------------------------------------------------


Andreas Pflug wrote:
> Bruce Momjian wrote:
>
> >Andreas, looks good, but I need a diff -c, context diff.
> >
> >
> >
> Hi Bruce,
> I intentionally only attached only non-context diffs because the patch
> is about 50 % size of the original file. Now, here's the same as context
> diff.
>
> Regards,
> Andreas

> Index: pg_proc.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
> retrieving revision 1.309
> diff -c -r1.309 pg_proc.h
> *** pg_proc.h    1 Jul 2003 00:04:38 -0000    1.309
> --- pg_proc.h    22 Jul 2003 12:52:07 -0000
> ***************
> *** 3405,3410 ****
> --- 3405,3424 ----
>   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 - _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 - _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 - _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 - _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 - _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 - _null_
));
> + DESCR("deparse an encoded expression with pretty-print option");
> +
>
>   /*
>    * Symbolic values for provolatile column: these indicate whether the result

> Index: ruleutils.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
> retrieving revision 1.145
> diff -c -r1.145 ruleutils.c
> *** ruleutils.c    4 Jul 2003 02:51:34 -0000    1.145
> --- ruleutils.c    22 Jul 2003 12:54:10 -0000
> ***************
> *** 71,76 ****
> --- 71,95 ----
>   #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,86 ****
> --- 100,107 ----
>   {
>       StringInfo    buf;            /* output buffer to append to */
>       List       *namespaces;        /* List of deparse_namespace nodes */
> +         int             prettyFlags;            /* enabling/disabling of pretty-print functions */
> +         int             indentLevel;            /* for prettyPrint, current space indents are counted */
>       bool        varprefix;        /* TRUE to print prefixes on Vars */
>   } deparse_context;
>
> ***************
> *** 123,135 ****
>    * as a parameter, and append their text output to its contents.
>    * ----------
>    */
> ! static text *pg_do_getviewdef(Oid viewoid);
>   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 void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
> !               TupleDesc resultDesc);
>   static void get_select_query_def(Query *query, deparse_context *context,
>                        TupleDesc resultDesc);
>   static void get_insert_query_def(Query *query, deparse_context *context);
> --- 144,162 ----
>    * as a parameter, and append their text output to its contents.
>    * ----------
>    */
> ! static char *get_simple_binary_op_name(OpExpr *expr);
> ! static void appendStringInfoSpace(StringInfo buf, int count);
> ! static void appendContextKeyword(deparse_context *context, char *str, int indentBefore, int indentAfter, int
indentPlus);
> ! static char *deparse_expression_pretty(Node *expr, List *dpcontext,
> !               bool forceprefix, bool showimplicit, int prettyFlags, int startIndent);
> ! static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
> ! 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, 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, 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);
> ***************
> *** 192,197 ****
> --- 219,225 ----
>       TupleDesc    rulettc;
>       StringInfoData buf;
>       int            len;
> +     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
>
>       /*
>        * Connect to SPI manager
> ***************
> *** 241,247 ****
>        * Get the rules definition and put it into executors memory
>        */
>       initStringInfo(&buf);
> !     make_ruledef(&buf, ruletup, rulettc);
>       len = buf.len + VARHDRSZ;
>       ruledef = SPI_palloc(len);
>       VARATT_SIZEP(ruledef) = len;
> --- 269,275 ----
>        * Get the rules definition and put it into executors memory
>        */
>       initStringInfo(&buf);
> !     make_ruledef(&buf, ruletup, rulettc, prettyFlags);
>       len = buf.len + VARHDRSZ;
>       ruledef = SPI_palloc(len);
>       VARATT_SIZEP(ruledef) = len;
> ***************
> *** 272,279 ****
>       /* By OID */
>       Oid            viewoid = PG_GETARG_OID(0);
>       text       *ruledef;
>
> !     ruledef = pg_do_getviewdef(viewoid);
>       PG_RETURN_TEXT_P(ruledef);
>   }
>
> --- 300,308 ----
>       /* By OID */
>       Oid            viewoid = PG_GETARG_OID(0);
>       text       *ruledef;
> +     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
>
> !     ruledef = pg_do_getviewdef(viewoid, prettyFlags);
>       PG_RETURN_TEXT_P(ruledef);
>   }
>
> ***************
> *** 285,296 ****
>       RangeVar   *viewrel;
>       Oid            viewoid;
>       text       *ruledef;
>
>       viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname,
>                                                            "get_viewdef"));
>       viewoid = RangeVarGetRelid(viewrel, false);
>
> !     ruledef = pg_do_getviewdef(viewoid);
>       PG_RETURN_TEXT_P(ruledef);
>   }
>
> --- 314,326 ----
>       RangeVar   *viewrel;
>       Oid            viewoid;
>       text       *ruledef;
> +     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? 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,304 ****
>    * Common code for by-OID and by-name variants of pg_get_viewdef
>    */
>   static text *
> ! pg_do_getviewdef(Oid viewoid)
>   {
>       text       *ruledef;
>       Datum        args[2];
> --- 328,334 ----
>    * Common code for by-OID and by-name variants of pg_get_viewdef
>    */
>   static text *
> ! pg_do_getviewdef(Oid viewoid, int prettyFlags)
>   {
>       text       *ruledef;
>       Datum        args[2];
> ***************
> *** 353,359 ****
>            */
>           ruletup = SPI_tuptable->vals[0];
>           rulettc = SPI_tuptable->tupdesc;
> !         make_viewdef(&buf, ruletup, rulettc);
>       }
>       len = buf.len + VARHDRSZ;
>       ruledef = SPI_palloc(len);
> --- 383,389 ----
>            */
>           ruletup = SPI_tuptable->vals[0];
>           rulettc = SPI_tuptable->tupdesc;
> !         make_viewdef(&buf, ruletup, rulettc, prettyFlags);
>       }
>       len = buf.len + VARHDRSZ;
>       ruledef = SPI_palloc(len);
> ***************
> *** 544,549 ****
> --- 574,581 ----
>       StringInfoData buf;
>       char       *str;
>       char       *sep;
> +     int        colno = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);
> +     int        prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
>
>       /*
>        * Fetch the pg_index tuple by the Oid of the index
> ***************
> *** 582,587 ****
> --- 614,621 ----
>        * Get the index expressions, if any.  (NOTE: we do not use the relcache
>        * versions of the expressions and predicate, because we want to display
>        * non-const-folded expressions.)
> +          * if colno == 0, we want a complete index definition.
> +          * if colno > 0, we only want the nth expression.
>        */
>       if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
>       {
> ***************
> *** 607,613 ****
>        * never be schema-qualified, but the indexed rel's name may be.
>        */
>       initStringInfo(&buf);
> !     appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
>                        idxrec->indisunique ? "UNIQUE " : "",
>                        quote_identifier(NameStr(idxrelrec->relname)),
>                        generate_relation_name(indrelid),
> --- 641,649 ----
>        * never be schema-qualified, but the indexed rel's name may be.
>        */
>       initStringInfo(&buf);
> !
> !     if (!colno)
> !         appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
>                        idxrec->indisunique ? "UNIQUE " : "",
>                        quote_identifier(NameStr(idxrelrec->relname)),
>                        generate_relation_name(indrelid),
> ***************
> *** 621,627 ****
>       {
>           AttrNumber    attnum = idxrec->indkey[keyno];
>
> !         appendStringInfo(&buf, sep);
>           sep = ", ";
>
>           if (attnum != 0)
> --- 657,664 ----
>       {
>           AttrNumber    attnum = idxrec->indkey[keyno];
>
> !         if (!colno)
> !             appendStringInfo(&buf, sep);
>           sep = ", ";
>
>           if (attnum != 0)
> ***************
> *** 630,636 ****
>               char       *attname;
>
>               attname = get_relid_attribute_name(indrelid, attnum);
> !             appendStringInfo(&buf, "%s", quote_identifier(attname));
>               keycoltype = get_atttype(indrelid, attnum);
>           }
>           else
> --- 667,674 ----
>               char       *attname;
>
>               attname = get_relid_attribute_name(indrelid, attnum);
> !             if (!colno || colno == keyno+1)
> !                 appendStringInfo(&buf, "%s", quote_identifier(attname));
>               keycoltype = get_atttype(indrelid, attnum);
>           }
>           else
> ***************
> *** 643,672 ****
>               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);
>               keycoltype = exprType(indexkey);
>           }
>
>           /*
>            * Add the operator class name
>            */
> !         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))
>       {
>           Node       *node;
>           Datum        predDatum;
>           bool        isnull;
> --- 681,716 ----
>               indexkey = (Node *) lfirst(indexprs);
>               indexprs = lnext(indexprs);
>               /* Deparse */
> !             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
>            */
> !         if (!colno)
> !             get_opclass_name(idxrec->indclass[keyno], keycoltype,
>                            &buf);
>       }
>
> !     if (!colno)
>       {
> +         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;
> ***************
> *** 689,698 ****
>           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);
>       }
> -
>       /*
>        * Create the result as a TEXT datum, and free working data
>        */
> --- 733,742 ----
>           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);
> +         }
>       }
>       /*
>        * Create the result as a TEXT datum, and free working data
>        */
> ***************
> *** 729,734 ****
> --- 773,779 ----
>       ScanKeyData skey[1];
>       HeapTuple    tup;
>       Form_pg_constraint conForm;
> +     int      prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
>
>       /*
>        * Fetch the pg_constraint row.  There's no syscache for pg_constraint
> ***************
> *** 934,940 ****
>                       context = deparse_context_for(get_typname(conForm->contypid),
>                                                     InvalidOid);
>
> !                 consrc = deparse_expression(expr, context, false, false);
>
>                   /* Append the constraint source */
>                   appendStringInfoString(&buf, consrc);
> --- 979,985 ----
>                       context = deparse_context_for(get_typname(conForm->contypid),
>                                                     InvalidOid);
>
> !                 consrc = deparse_expression_pretty(expr, context, false, false, prettyFlags, 0);
>
>                   /* Append the constraint source */
>                   appendStringInfoString(&buf, consrc);
> ***************
> *** 1018,1023 ****
> --- 1063,1069 ----
>       char       *exprstr;
>       char       *relname;
>       char       *str;
> +     int      prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
>
>       /* Get the name for the relation */
>       relname = get_rel_name(relid);
> ***************
> *** 1041,1047 ****
>
>       /* Deparse */
>       context = deparse_context_for(relname, relid);
> !     str = deparse_expression(node, context, false, false);
>
>       /* Pass the result back as TEXT */
>       result = DatumGetTextP(DirectFunctionCall1(textin,
> --- 1087,1093 ----
>
>       /* Deparse */
>       context = deparse_context_for(relname, relid);
> !     str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0);
>
>       /* Pass the result back as TEXT */
>       result = DatumGetTextP(DirectFunctionCall1(textin,
> ***************
> *** 1090,1095 ****
> --- 1136,1152 ----
>
>   /* ----------
>    * 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).
> ***************
> *** 1100,1112 ****
>    * 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.
>    *
>    * The result is a palloc'd string.
>    * ----------
>    */
>   char *
> ! deparse_expression(Node *expr, List *dpcontext,
> !                    bool forceprefix, bool showimplicit)
>   {
>       StringInfoData buf;
>       deparse_context context;
> --- 1157,1171 ----
>    * 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
>    *
>    * The result is a palloc'd string.
>    * ----------
>    */
>   char *
> ! deparse_expression_pretty(Node *expr, List *dpcontext,
> !                    bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
>   {
>       StringInfoData buf;
>       deparse_context context;
> ***************
> *** 1115,1120 ****
> --- 1174,1181 ----
>       context.buf = &buf;
>       context.namespaces = dpcontext;
>       context.varprefix = forceprefix;
> +     context.prettyFlags = prettyFlags;
> +     context.indentLevel = startIndent;
>
>       get_rule_expr(expr, &context, showimplicit);
>
> ***************
> *** 1267,1273 ****
>    * ----------
>    */
>   static void
> ! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
>   {
>       char       *rulename;
>       char        ev_type;
> --- 1328,1334 ----
>    * ----------
>    */
>   static void
> ! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
>   {
>       char       *rulename;
>       char        ev_type;
> ***************
> *** 1321,1329 ****
>       /*
>        * Build the rules definition text
>        */
> !     appendStringInfo(buf, "CREATE RULE %s AS ON ",
>                        quote_identifier(rulename));
>
>       /* The event the rule is fired for */
>       switch (ev_type)
>       {
> --- 1382,1395 ----
>       /*
>        * Build the rules definition text
>        */
> !     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)
>       {
> ***************
> *** 1366,1371 ****
> --- 1432,1439 ----
>           deparse_context context;
>           deparse_namespace dpns;
>
> +         if (prettyFlags & PRETTYFLAG_INDENT)
> +             appendStringInfoString(buf, "\n  ");
>           appendStringInfo(buf, " WHERE ");
>
>           qual = stringToNode(ev_qual);
> ***************
> *** 1387,1392 ****
> --- 1455,1462 ----
>           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;
> ***************
> *** 1410,1417 ****
>           foreach(action, actions)
>           {
>               query = (Query *) lfirst(action);
> !             get_query_def(query, buf, NIL, NULL);
> !             appendStringInfo(buf, "; ");
>           }
>           appendStringInfo(buf, ");");
>       }
> --- 1480,1490 ----
>           foreach(action, actions)
>           {
>               query = (Query *) lfirst(action);
> !             get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
> !             if (prettyFlags)
> !                 appendStringInfo(buf, ";\n");
> !             else
> !                 appendStringInfo(buf, "; ");
>           }
>           appendStringInfo(buf, ");");
>       }
> ***************
> *** 1424,1430 ****
>           Query       *query;
>
>           query = (Query *) lfirst(actions);
> !         get_query_def(query, buf, NIL, NULL);
>           appendStringInfo(buf, ";");
>       }
>   }
> --- 1497,1503 ----
>           Query       *query;
>
>           query = (Query *) lfirst(actions);
> !         get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
>           appendStringInfo(buf, ";");
>       }
>   }
> ***************
> *** 1436,1442 ****
>    * ----------
>    */
>   static void
> ! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
>   {
>       Query       *query;
>       char        ev_type;
> --- 1509,1515 ----
>    * ----------
>    */
>   static void
> ! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
>   {
>       Query       *query;
>       char        ev_type;
> ***************
> *** 1490,1496 ****
>
>       ev_relation = heap_open(ev_class, AccessShareLock);
>
> !     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation));
>       appendStringInfo(buf, ";");
>
>       heap_close(ev_relation, AccessShareLock);
> --- 1563,1569 ----
>
>       ev_relation = heap_open(ev_class, AccessShareLock);
>
> !     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), prettyFlags, 0);
>       appendStringInfo(buf, ";");
>
>       heap_close(ev_relation, AccessShareLock);
> ***************
> *** 1506,1512 ****
>    */
>   static void
>   get_query_def(Query *query, StringInfo buf, List *parentnamespace,
> !               TupleDesc resultDesc)
>   {
>       deparse_context context;
>       deparse_namespace dpns;
> --- 1579,1585 ----
>    */
>   static void
>   get_query_def(Query *query, StringInfo buf, List *parentnamespace,
> !               TupleDesc resultDesc, int prettyFlags, int startIndent)
>   {
>       deparse_context context;
>       deparse_namespace dpns;
> ***************
> *** 1515,1520 ****
> --- 1588,1596 ----
>       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;
> ***************
> *** 1586,1592 ****
>       /* Add the ORDER BY clause if given */
>       if (query->sortClause != NIL)
>       {
> !         appendStringInfo(buf, " ORDER BY ");
>           sep = "";
>           foreach(l, query->sortClause)
>           {
> --- 1662,1668 ----
>       /* Add the ORDER BY clause if given */
>       if (query->sortClause != NIL)
>       {
> !             appendContextKeyword(context, " ORDER BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
>           sep = "";
>           foreach(l, query->sortClause)
>           {
> ***************
> *** 1615,1626 ****
>       /* Add the LIMIT clause if given */
>       if (query->limitOffset != NULL)
>       {
> !         appendStringInfo(buf, " OFFSET ");
>           get_rule_expr(query->limitOffset, context, false);
>       }
>       if (query->limitCount != NULL)
>       {
> !         appendStringInfo(buf, " LIMIT ");
>           if (IsA(query->limitCount, Const) &&
>               ((Const *) query->limitCount)->constisnull)
>               appendStringInfo(buf, "ALL");
> --- 1691,1702 ----
>       /* Add the LIMIT clause if given */
>       if (query->limitOffset != NULL)
>       {
> !         appendContextKeyword(context, " OFFSET ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
>           get_rule_expr(query->limitOffset, context, false);
>       }
>       if (query->limitCount != NULL)
>       {
> !         appendContextKeyword(context, " LIMIT ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
>           if (IsA(query->limitCount, Const) &&
>               ((Const *) query->limitCount)->constisnull)
>               appendStringInfo(buf, "ALL");
> ***************
> *** 1641,1646 ****
> --- 1717,1727 ----
>       /*
>        * 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 */
> ***************
> *** 1720,1733 ****
>       /* Add the WHERE clause if given */
>       if (query->jointree->quals != NULL)
>       {
> !         appendStringInfo(buf, " WHERE ");
>           get_rule_expr(query->jointree->quals, context, false);
>       }
>
>       /* Add the GROUP BY clause if given */
>       if (query->groupClause != NULL)
>       {
> !         appendStringInfo(buf, " GROUP BY ");
>           sep = "";
>           foreach(l, query->groupClause)
>           {
> --- 1801,1814 ----
>       /* Add the WHERE clause if given */
>       if (query->jointree->quals != NULL)
>       {
> !         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)
>       {
> !         appendContextKeyword(context, " GROUP BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
>           sep = "";
>           foreach(l, query->groupClause)
>           {
> ***************
> *** 1743,1749 ****
>       /* Add the HAVING clause if given */
>       if (query->havingQual != NULL)
>       {
> !         appendStringInfo(buf, " HAVING ");
>           get_rule_expr(query->havingQual, context, false);
>       }
>   }
> --- 1824,1830 ----
>       /* Add the HAVING clause if given */
>       if (query->havingQual != NULL)
>       {
> !         appendContextKeyword(context, " HAVING ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
>           get_rule_expr(query->havingQual, context, false);
>       }
>   }
> ***************
> *** 1761,1795 ****
>           Query       *subquery = rte->subquery;
>
>           Assert(subquery != NULL);
> !         get_query_def(subquery, buf, context->namespaces, resultDesc);
>       }
>       else if (IsA(setOp, SetOperationStmt))
>       {
>           SetOperationStmt *op = (SetOperationStmt *) setOp;
>
> -         appendStringInfo(buf, "((");
>           get_setop_query(op->larg, query, context, resultDesc);
>           switch (op->op)
>           {
>               case SETOP_UNION:
> !                 appendStringInfo(buf, ") UNION ");
>                   break;
>               case SETOP_INTERSECT:
> !                 appendStringInfo(buf, ") INTERSECT ");
>                   break;
>               case SETOP_EXCEPT:
> !                 appendStringInfo(buf, ") EXCEPT ");
>                   break;
>               default:
>                   elog(ERROR, "get_setop_query: unexpected set op %d",
>                        (int) op->op);
>           }
>           if (op->all)
> !             appendStringInfo(buf, "ALL (");
>           else
> !             appendStringInfo(buf, "(");
>           get_setop_query(op->rarg, query, context, resultDesc);
> !         appendStringInfo(buf, "))");
>       }
>       else
>       {
> --- 1842,1905 ----
>           Query       *subquery = rte->subquery;
>
>           Assert(subquery != NULL);
> !         get_query_def(subquery, buf, context->namespaces, resultDesc, context->prettyFlags, context->indentLevel);
>       }
>       else if (IsA(setOp, SetOperationStmt))
>       {
>           SetOperationStmt *op = (SetOperationStmt *) setOp;
> +         bool need_paren=(PRETTY_PAREN(context) ? !IsA(op->rarg, RangeTblRef) : true);
> +
> +         if (!PRETTY_PAREN(context))
> +             appendStringInfoString(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:
> !                 appendContextKeyword(context, "UNION ", -PRETTYINDENT_STD, 0, 0);
>                   break;
>               case SETOP_INTERSECT:
> !                 appendContextKeyword(context, "INTERSECT ", -PRETTYINDENT_STD, 0, 0);
>                   break;
>               case SETOP_EXCEPT:
> !                 appendContextKeyword(context, "EXCEPT ", -PRETTYINDENT_STD, 0, 0);
>                   break;
>               default:
>                   elog(ERROR, "get_setop_query: unexpected set op %d",
>                        (int) op->op);
>           }
>           if (op->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
> !             appendStringInfoChar(buf, '(');
> !
>           get_setop_query(op->rarg, query, context, resultDesc);
> !
> !         if (PRETTY_PAREN(context))
> !         {
> !             if (need_paren)
> !             appendStringInfoChar(buf, ')');
> !         }
> !         else
> !             appendStringInfoString(buf, "))");
>       }
>       else
>       {
> ***************
> *** 1862,1867 ****
> --- 1972,1983 ----
>        */
>       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));
>
> ***************
> *** 1883,1889 ****
>       /* Add the VALUES or the SELECT */
>       if (select_rte == NULL)
>       {
> !         appendStringInfo(buf, "VALUES (");
>           sep = "";
>           foreach(l, query->targetList)
>           {
> --- 1999,2005 ----
>       /* Add the VALUES or the SELECT */
>       if (select_rte == NULL)
>       {
> !         appendContextKeyword(context, "VALUES (", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
>           sep = "";
>           foreach(l, query->targetList)
>           {
> ***************
> *** 1899,1905 ****
>           appendStringInfoChar(buf, ')');
>       }
>       else
> !         get_query_def(select_rte->subquery, buf, NIL, NULL);
>   }
>
>
> --- 2015,2021 ----
>           appendStringInfoChar(buf, ')');
>       }
>       else
> !         get_query_def(select_rte->subquery, buf, NIL, NULL, context->prettyFlags, context->indentLevel);
>   }
>
>
> ***************
> *** 1920,1925 ****
> --- 2036,2046 ----
>        */
>       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));
> ***************
> *** 1953,1959 ****
>       /* Finally add a WHERE clause if given */
>       if (query->jointree->quals != NULL)
>       {
> !         appendStringInfo(buf, " WHERE ");
>           get_rule_expr(query->jointree->quals, context, false);
>       }
>   }
> --- 2074,2080 ----
>       /* Finally add a WHERE clause if given */
>       if (query->jointree->quals != NULL)
>       {
> !         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
>           get_rule_expr(query->jointree->quals, context, false);
>       }
>   }
> ***************
> *** 1974,1979 ****
> --- 2095,2105 ----
>        */
>       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));
> ***************
> *** 1981,1987 ****
>       /* Add a WHERE clause if given */
>       if (query->jointree->quals != NULL)
>       {
> !         appendStringInfo(buf, " WHERE ");
>           get_rule_expr(query->jointree->quals, context, false);
>       }
>   }
> --- 2107,2113 ----
>       /* Add a WHERE clause if given */
>       if (query->jointree->quals != NULL)
>       {
> !         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
>           get_rule_expr(query->jointree->quals, context, false);
>       }
>   }
> ***************
> *** 2000,2005 ****
> --- 2126,2132 ----
>       {
>           NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
>
> +         appendContextKeyword(context, "", 0, PRETTYINDENT_STD, 1);
>           appendStringInfo(buf, "NOTIFY %s",
>                      quote_qualified_identifier(stmt->relation->schemaname,
>                                                 stmt->relation->relname));
> ***************
> *** 2140,2145 ****
> --- 2267,2508 ----
>   }
>
>
> + /********************************************
> +  * get_simple_binary_op_name
> +  * helper function for isSimpleNode
> +  * will return single char binary operator
> +  *******************************************/
> +
> + static 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);
> +         char *op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
> +
> +         if (strlen(op) == 1)
> +             return op;
> +     }
> +     return 0;
> + }
> +
> +
> + /***************************************
> +  * check if given node is simple.
> +  *  false  : not simple
> +  *  true   : simple in the context of parent node's type
> +  ***************************************/
> +
> + static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
> + {
> +     if (!node)
> +     return true;
> +
> +     switch (nodeTag(node))
> +     {
> +     // single words: always simple
> +     case T_Var:
> +     case T_Const:
> +     case T_Param:
> +
> +     // function-like: name(..) or name[..]
> +     case T_ArrayRef:
> +     case T_ArrayExpr:
> +     case T_CoalesceExpr:
> +     case T_NullIfExpr:
> +     case T_Aggref:
> +     case T_FuncExpr:
> +
> +         // CASE keywords act as parentheses
> +     case T_CaseExpr:
> +         return true;
> +
> +         // appears simple since . has top precedence, unless parent is T_FieldSelect itself!
> +     case T_FieldSelect:
> +         return (nodeTag(parentNode) == T_FieldSelect ? false : true);
> +
> +
> +         // maybe simple, check args
> +     case T_CoerceToDomain:
> +         return isSimpleNode((Node*) ((CoerceToDomain*)node)->arg, node, prettyFlags);
> +     case T_RelabelType:
> +         return isSimpleNode((Node*) ((RelabelType*)node)->arg, node, prettyFlags);
> +
> +
> +     // depends on parent node type; needs further checking
> +     case T_OpExpr:
> +     {
> +         if (prettyFlags & PRETTYFLAG_PAREN && nodeTag(parentNode) == T_OpExpr)
> +         {
> +         char *op=get_simple_binary_op_name((OpExpr*)node);
> +         char *parentOp=get_simple_binary_op_name((OpExpr*)parentNode);
> +         if (!op || !parentOp)
> +             return false;
> +
> +                 // we know only these basic operators
> +         if (!strchr("+-*/%", *op) || !strchr("+-*/%", *parentOp))
> +             return false;
> +
> +         // natural operator precedence, so we don't need parentheses
> +         if (strchr("*/%", *op) || strchr("+-", *parentOp))
> +             return true;
> +
> +         return false;
> +         }
> +             // else do the same stuff as for T_SubLink et al.
> +     }
> +     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=((BoolExpr*)node)->boolop;
> +             BoolExprType 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;
> +         }
> +         // these are not completely implemented; so far, they're simple
> +     case T_SubPlan:
> +     case T_CoerceToDomainValue:
> +         return true;
> +
> +     case T_ScalarArrayOpExpr:
> +         // need to check
> +     default:
> +         break;
> +     }
> +     // those we don't know: in dubio complexo
> +     return false;
> + }
> +
> +
> + /******************************************
> +  * appendContextKeyword
> +  * append spaces to buffer
> +  ******************************************/
> + static void appendStringInfoSpace(StringInfo buf, int count)
> + {
> +     while (count-- > 0)
> +     appendStringInfoChar(buf, ' ');
> + }
> +
> + /******************************************
> +  * appendContextKeyword
> +  * performing a line break, and indentation
> +  * if prettyPrint is enabled.
> +  * Otherwise, only the keyword is appended
> +  *****************************************/
> +
> + static void appendContextKeyword(deparse_context *context, 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');
> +     appendStringInfoSpace(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  - parsing expr using get_rule_expr,
> +  * embracing the string with parentheses if necessary for prettyPrint.
> +  * never embracing 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 = 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
>    *
> ***************
> *** 2294,2305 ****
>                   List       *args = expr->args;
>                   Node       *arg1 = (Node *) lfirst(args);
>                   Node       *arg2 = (Node *) lsecond(args);
> !
> !                 appendStringInfoChar(buf, '(');
> !                 get_rule_expr(arg1, context, true);
>                   appendStringInfo(buf, " IS DISTINCT FROM ");
> !                 get_rule_expr(arg2, context, true);
> !                 appendStringInfoChar(buf, ')');
>               }
>               break;
>
> --- 2657,2669 ----
>                   List       *args = expr->args;
>                   Node       *arg1 = (Node *) lfirst(args);
>                   Node       *arg2 = (Node *) lsecond(args);
> !                 if (!PRETTY_PAREN(context))
> !                     appendStringInfoChar(buf, '(');
> !                 get_rule_expr_paren(arg1, context, true, node);
>                   appendStringInfo(buf, " IS DISTINCT FROM ");
> !                 get_rule_expr_paren(arg2, context, true, node);
> !                 if (!PRETTY_PAREN(context))
> !                     appendStringInfoChar(buf, ')');
>               }
>               break;
>
> ***************
> *** 2310,2324 ****
>                   Node       *arg1 = (Node *) lfirst(args);
>                   Node       *arg2 = (Node *) lsecond(args);
>
> !                 appendStringInfoChar(buf, '(');
> !                 get_rule_expr(arg1, context, true);
>                   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, "))");
>               }
>               break;
>
> --- 2674,2692 ----
>                   Node       *arg1 = (Node *) lfirst(args);
>                   Node       *arg2 = (Node *) lsecond(args);
>
> !                 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_paren(arg2, context, true, node);
> !                 appendStringInfoString(buf, ")");
> !
> !                 if (!PRETTY_PAREN(context))
> !                     appendStringInfoChar(buf, ')');
>               }
>               break;
>
> ***************
> *** 2330,2362 ****
>                   switch (expr->boolop)
>                   {
>                       case AND_EXPR:
> !                         appendStringInfoChar(buf, '(');
> !                         get_rule_expr((Node *) lfirst(args), context, false);
>                           while ((args = lnext(args)) != NIL)
>                           {
>                               appendStringInfo(buf, " AND ");
> !                             get_rule_expr((Node *) lfirst(args), context,
> !                                           false);
>                           }
> !                         appendStringInfoChar(buf, ')');
>                           break;
>
>                       case OR_EXPR:
> !                         appendStringInfoChar(buf, '(');
> !                         get_rule_expr((Node *) lfirst(args), context, false);
>                           while ((args = lnext(args)) != NIL)
>                           {
>                               appendStringInfo(buf, " OR ");
> !                             get_rule_expr((Node *) lfirst(args), context,
> !                                           false);
>                           }
> !                         appendStringInfoChar(buf, ')');
>                           break;
>
>                       case NOT_EXPR:
> !                         appendStringInfo(buf, "(NOT ");
> !                         get_rule_expr((Node *) lfirst(args), context, false);
> !                         appendStringInfoChar(buf, ')');
>                           break;
>
>                       default:
> --- 2698,2737 ----
>                   switch (expr->boolop)
>                   {
>                       case AND_EXPR:
> !                             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_paren((Node *) lfirst(args), context,
> !                                           false, node);
>                           }
> !                             if (!PRETTY_PAREN(context))
> !                             appendStringInfoChar(buf, ')');
>                           break;
>
>                       case OR_EXPR:
> !                             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_paren((Node *) lfirst(args), context,
> !                                           false, node);
>                           }
> !                             if (!PRETTY_PAREN(context))
> !                             appendStringInfoChar(buf, ')');
>                           break;
>
>                       case NOT_EXPR:
> !                             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:
> ***************
> *** 2404,2412 ****
>                    * 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));
>               }
>               break;
>
> --- 2779,2790 ----
>                    * arg.fieldname, but most cases where FieldSelect is used
>                    * are *not* simple.  So, always use parenthesized syntax.
>                    */
> !                     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;
>
> ***************
> *** 2419,2425 ****
>                       !showimplicit)
>                   {
>                       /* don't show the implicit cast */
> !                     get_rule_expr(arg, context, showimplicit);
>                   }
>                   else
>                   {
> --- 2797,2803 ----
>                       !showimplicit)
>                   {
>                       /* don't show the implicit cast */
> !                     get_rule_expr_paren(arg, context, showimplicit, node);
>                   }
>                   else
>                   {
> ***************
> *** 2431,2439 ****
>                        */
>                       arg = strip_type_coercion(arg, relabel->resulttype);
>
> !                     appendStringInfoChar(buf, '(');
> !                     get_rule_expr(arg, context, showimplicit);
> !                     appendStringInfo(buf, ")::%s",
>                               format_type_with_typemod(relabel->resulttype,
>                                                        relabel->resulttypmod));
>                   }
> --- 2809,2821 ----
>                        */
>                       arg = strip_type_coercion(arg, relabel->resulttype);
>
> !                     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));
>                   }
> ***************
> *** 2445,2463 ****
>                   CaseExpr   *caseexpr = (CaseExpr *) node;
>                   List       *temp;
>
> !                 appendStringInfo(buf, "CASE");
>                   foreach(temp, caseexpr->args)
>                   {
>                       CaseWhen   *when = (CaseWhen *) lfirst(temp);
>
> !                     appendStringInfo(buf, " WHEN ");
>                       get_rule_expr((Node *) when->expr, context, false);
>                       appendStringInfo(buf, " THEN ");
>                       get_rule_expr((Node *) when->result, context, true);
>                   }
> !                 appendStringInfo(buf, " ELSE ");
>                   get_rule_expr((Node *) caseexpr->defresult, context, true);
> !                 appendStringInfo(buf, " END");
>               }
>               break;
>
> --- 2827,2853 ----
>                   CaseExpr   *caseexpr = (CaseExpr *) node;
>                   List       *temp;
>
> !                 appendContextKeyword(context, "CASE", 0, PRETTYINDENT_VAR, 0);
>                   foreach(temp, caseexpr->args)
>                   {
>                       CaseWhen   *when = (CaseWhen *) lfirst(temp);
>
> !                     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);
>                   }
> !                 if (!PRETTY_INDENT(context))
> !                     appendStringInfoChar(buf, ' ');
> !                 appendContextKeyword(context, "ELSE ", 0, 0, 0);
>                   get_rule_expr((Node *) caseexpr->defresult, context, true);
> !                 if (!PRETTY_INDENT(context))
> !                     appendStringInfoChar(buf, ' ');
> !                 appendContextKeyword(context, "END", -PRETTYINDENT_VAR, 0, 0);
>               }
>               break;
>
> ***************
> *** 2525,2544 ****
>               {
>                   NullTest   *ntest = (NullTest *) node;
>
> !                 appendStringInfo(buf, "(");
> !                 get_rule_expr((Node *) ntest->arg, context, true);
>                   switch (ntest->nulltesttype)
>                   {
>                       case IS_NULL:
> !                         appendStringInfo(buf, " IS NULL)");
>                           break;
>                       case IS_NOT_NULL:
> !                         appendStringInfo(buf, " IS NOT NULL)");
>                           break;
>                       default:
>                           elog(ERROR, "get_rule_expr: unexpected nulltesttype %d",
>                                (int) ntest->nulltesttype);
>                   }
>               }
>               break;
>
> --- 2915,2937 ----
>               {
>                   NullTest   *ntest = (NullTest *) node;
>
> !                 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");
>                           break;
>                       case IS_NOT_NULL:
> !                         appendStringInfo(buf, " IS NOT NULL");
>                           break;
>                       default:
>                           elog(ERROR, "get_rule_expr: unexpected nulltesttype %d",
>                                (int) ntest->nulltesttype);
>                   }
> +                 if (!PRETTY_PAREN(context))
> +                     appendStringInfoChar(buf, ')');
>               }
>               break;
>
> ***************
> *** 2546,2577 ****
>               {
>                   BooleanTest *btest = (BooleanTest *) node;
>
> !                 appendStringInfo(buf, "(");
> !                 get_rule_expr((Node *) btest->arg, context, false);
>                   switch (btest->booltesttype)
>                   {
>                       case IS_TRUE:
> !                         appendStringInfo(buf, " IS TRUE)");
>                           break;
>                       case IS_NOT_TRUE:
> !                         appendStringInfo(buf, " IS NOT TRUE)");
>                           break;
>                       case IS_FALSE:
> !                         appendStringInfo(buf, " IS FALSE)");
>                           break;
>                       case IS_NOT_FALSE:
> !                         appendStringInfo(buf, " IS NOT FALSE)");
>                           break;
>                       case IS_UNKNOWN:
> !                         appendStringInfo(buf, " IS UNKNOWN)");
>                           break;
>                       case IS_NOT_UNKNOWN:
> !                         appendStringInfo(buf, " IS NOT UNKNOWN)");
>                           break;
>                       default:
>                           elog(ERROR, "get_rule_expr: unexpected booltesttype %d",
>                                (int) btest->booltesttype);
>                   }
>               }
>               break;
>
> --- 2939,2973 ----
>               {
>                   BooleanTest *btest = (BooleanTest *) node;
>
> !                 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");
>                           break;
>                       case IS_NOT_TRUE:
> !                         appendStringInfo(buf, " IS NOT TRUE");
>                           break;
>                       case IS_FALSE:
> !                         appendStringInfo(buf, " IS FALSE");
>                           break;
>                       case IS_NOT_FALSE:
> !                         appendStringInfo(buf, " IS NOT FALSE");
>                           break;
>                       case IS_UNKNOWN:
> !                         appendStringInfo(buf, " IS UNKNOWN");
>                           break;
>                       case IS_NOT_UNKNOWN:
> !                         appendStringInfo(buf, " IS NOT UNKNOWN");
>                           break;
>                       default:
>                           elog(ERROR, "get_rule_expr: unexpected booltesttype %d",
>                                (int) btest->booltesttype);
>                   }
> +                 if (!PRETTY_PAREN(context))
> +                     appendStringInfoChar(buf, ')');
>               }
>               break;
>
> ***************
> *** 2593,2601 ****
>                   }
>                   else
>                   {
> !                     appendStringInfoChar(buf, '(');
> !                     get_rule_expr(arg, context, false);
> !                     appendStringInfo(buf, ")::%s",
>                               format_type_with_typemod(ctest->resulttype,
>                                                        ctest->resulttypmod));
>                   }
> --- 2989,3002 ----
>                   }
>                   else
>                   {
> !                     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));
>                   }
> ***************
> *** 2627,2645 ****
>       Oid            opno = expr->opno;
>       List       *args = expr->args;
>
> !     appendStringInfoChar(buf, '(');
>       if (length(args) == 2)
>       {
>           /* binary operator */
>           Node       *arg1 = (Node *) lfirst(args);
>           Node       *arg2 = (Node *) lsecond(args);
> !
> !         get_rule_expr(arg1, context, true);
>           appendStringInfo(buf, " %s ",
>                            generate_operator_name(opno,
>                                                   exprType(arg1),
>                                                   exprType(arg2)));
> !         get_rule_expr(arg2, context, true);
>       }
>       else
>       {
> --- 3028,3046 ----
>       Oid            opno = expr->opno;
>       List       *args = expr->args;
>
> !     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_paren(arg1, context, true, (Node*)expr);
>           appendStringInfo(buf, " %s ",
>                            generate_operator_name(opno,
>                                                   exprType(arg1),
>                                                   exprType(arg2)));
> !         get_rule_expr_paren(arg2, context, true, (Node*)expr);
>       }
>       else
>       {
> ***************
> *** 2661,2670 ****
>                                    generate_operator_name(opno,
>                                                           InvalidOid,
>                                                           exprType(arg)));
> !                 get_rule_expr(arg, context, true);
>                   break;
>               case 'r':
> !                 get_rule_expr(arg, context, true);
>                   appendStringInfo(buf, " %s",
>                                    generate_operator_name(opno,
>                                                           exprType(arg),
> --- 3062,3071 ----
>                                    generate_operator_name(opno,
>                                                           InvalidOid,
>                                                           exprType(arg)));
> !                 get_rule_expr_paren(arg, context, true, (Node*)expr);
>                   break;
>               case 'r':
> !                 get_rule_expr_paren(arg, context, true, (Node*)expr);
>                   appendStringInfo(buf, " %s",
>                                    generate_operator_name(opno,
>                                                           exprType(arg),
> ***************
> *** 2675,2681 ****
>           }
>           ReleaseSysCache(tp);
>       }
> !     appendStringInfoChar(buf, ')');
>   }
>
>   /*
> --- 3076,3083 ----
>           }
>           ReleaseSysCache(tp);
>       }
> !     if (!PRETTY_PAREN(context))
> !         appendStringInfoChar(buf, ')');
>   }
>
>   /*
> ***************
> *** 2698,2704 ****
>        */
>       if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
>       {
> !         get_rule_expr((Node *) lfirst(expr->args), context, showimplicit);
>           return;
>       }
>
> --- 3100,3106 ----
>        */
>       if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
>       {
> !         get_rule_expr_paren((Node *) lfirst(expr->args), context, showimplicit, (Node*)expr);
>           return;
>       }
>
> ***************
> *** 2724,2732 ****
>            */
>           arg = strip_type_coercion(arg, rettype);
>
> !         appendStringInfoChar(buf, '(');
> !         get_rule_expr(arg, context, showimplicit);
> !         appendStringInfo(buf, ")::%s",
>                            format_type_with_typemod(rettype, coercedTypmod));
>
>           return;
> --- 3126,3139 ----
>            */
>           arg = strip_type_coercion(arg, rettype);
>
> !         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;
> ***************
> *** 3047,3053 ****
>       if (need_paren)
>           appendStringInfoChar(buf, '(');
>
> !     get_query_def(query, buf, context->namespaces, NULL);
>
>       if (need_paren)
>           appendStringInfo(buf, "))");
> --- 3454,3460 ----
>       if (need_paren)
>           appendStringInfoChar(buf, '(');
>
> !     get_query_def(query, buf, context->namespaces, NULL, context->prettyFlags, context->indentLevel);
>
>       if (need_paren)
>           appendStringInfo(buf, "))");
> ***************
> *** 3064,3070 ****
>   get_from_clause(Query *query, deparse_context *context)
>   {
>       StringInfo    buf = context->buf;
> !     char       *sep;
>       List       *l;
>
>       /*
> --- 3471,3477 ----
>   get_from_clause(Query *query, deparse_context *context)
>   {
>       StringInfo    buf = context->buf;
> !     char       *sep=0;
>       List       *l;
>
>       /*
> ***************
> *** 3074,3080 ****
>        * sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW
>        * and OLD.
>        */
> -     sep = " FROM ";
>
>       foreach(l, query->jointree->fromlist)
>       {
> --- 3481,3486 ----
> ***************
> *** 3093,3099 ****
>                   continue;
>           }
>
> !         appendStringInfo(buf, sep);
>           get_from_clause_item(jtnode, query, context);
>           sep = ", ";
>       }
> --- 3499,3509 ----
>                   continue;
>           }
>
> !         if (!sep)
> !             appendContextKeyword(context, " FROM ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
> !         else
> !             appendStringInfo(buf, sep);
> !
>           get_from_clause_item(jtnode, query, context);
>           sep = ", ";
>       }
> ***************
> *** 3122,3128 ****
>               case RTE_SUBQUERY:
>                   /* Subquery RTE */
>                   appendStringInfoChar(buf, '(');
> !                 get_query_def(rte->subquery, buf, context->namespaces, NULL);
>                   appendStringInfoChar(buf, ')');
>                   break;
>               case RTE_FUNCTION:
> --- 3532,3539 ----
>               case RTE_SUBQUERY:
>                   /* Subquery RTE */
>                   appendStringInfoChar(buf, '(');
> !                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
> !                           context->prettyFlags, context->indentLevel);
>                   appendStringInfoChar(buf, ')');
>                   break;
>               case RTE_FUNCTION:
> ***************
> *** 3144,3150 ****
>               {
>                   List       *col;
>
> !                 appendStringInfo(buf, "(");
>                   foreach(col, rte->alias->colnames)
>                   {
>                       if (col != rte->alias->colnames)
> --- 3555,3561 ----
>               {
>                   List       *col;
>
> !                 appendStringInfoChar(buf, '(');
>                   foreach(col, rte->alias->colnames)
>                   {
>                       if (col != rte->alias->colnames)
> ***************
> *** 3178,3213 ****
>       else if (IsA(jtnode, JoinExpr))
>       {
>           JoinExpr   *j = (JoinExpr *) jtnode;
>
> -         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, "get_from_clause_item: unknown join type %d",
>                        (int) j->jointype);
>           }
>           get_from_clause_item(j->rarg, query, context);
>           if (!j->isNatural)
>           {
>               if (j->using)
> --- 3589,3666 ----
>       else if (IsA(jtnode, JoinExpr))
>       {
>           JoinExpr   *j = (JoinExpr *) jtnode;
> +         bool need_paren_on_right = PRETTY_PAREN(context) && !IsA(j->rarg, RangeTblRef);
> +
> +         if (!PRETTY_PAREN(context) || j->alias != NULL)
> +             appendStringInfoChar(buf, '(');
>
>           get_from_clause_item(j->larg, query, context);
> +
>           if (j->isNatural)
>           {
> +             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, "get_from_clause_item: unknown 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, "get_from_clause_item: unknown 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)
> ***************
> *** 3226,3237 ****
>               }
>               else if (j->quals)
>               {
> !                 appendStringInfo(buf, " ON (");
>                   get_rule_expr(j->quals, context, false);
> !                 appendStringInfoChar(buf, ')');
>               }
>           }
> !         appendStringInfoChar(buf, ')');
>           /* Yes, it's correct to put alias after the right paren ... */
>           if (j->alias != NULL)
>           {
> --- 3679,3695 ----
>               }
>               else if (j->quals)
>               {
> !                 appendStringInfo(buf, " ON ");
> !                 if (!PRETTY_PAREN(context))
> !                     appendStringInfoChar(buf, '(');
>                   get_rule_expr(j->quals, context, false);
> !                 if (!PRETTY_PAREN(context))
> !                     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)
>           {
> ***************
> *** 3241,3247 ****
>               {
>                   List       *col;
>
> !                 appendStringInfo(buf, "(");
>                   foreach(col, j->alias->colnames)
>                   {
>                       if (col != j->alias->colnames)
> --- 3699,3705 ----
>               {
>                   List       *col;
>
> !                 appendStringInfoChar(buf, '(');
>                   foreach(col, j->alias->colnames)
>                   {
>                       if (col != j->alias->colnames)

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: ruleutils with pretty-print option

From
Bruce Momjian
Date:
Andreas Pflug wrote:
> Bruce Momjian wrote:
>
> >Andreas, looks good, but I need a diff -c, context diff.
> >
> >
> >
> Hi Bruce,
> I intentionally only attached only non-context diffs because the patch
> is about 50 % size of the original file. Now, here's the same as context
> diff.

I understand.  I need the context diff so I am sure the lines are going
where they are supposed to go.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: ruleutils with pretty-print option

From
Bruce Momjian
Date:
I am seeing the following regression failures from the patch to allow
pretty printing pg_get_*def functions.

Are these illustrating a problem with the function definition, or is it
happening because it is the first time we are calling the same function
with one and more than one parameter?

In fact, it seems you left the one-parameter versions of these functions
in pg_proc.h.  I don't think that works.  I think you need a wrapper
function for the one-parameter version that calls the two-parameter
version with a valid second parameter value.  I can do the work if you
that is the proper way to handle it, or you can submit a new version.

Also, the patch doesn't apply cleanly to CVS anymore because Tom changed
the elogs in the adt directory.  I can work around that.

I am attaching the regression failures, and an updated version of your
patch.

---------------------------------------------------------------------------

Andreas Pflug wrote:
> Bruce Momjian wrote:
>
> >Andreas, looks good, but I need a diff -c, context diff.
> >
> >
> >
> Hi Bruce,
> I intentionally only attached only non-context diffs because the patch
> is about 50 % size of the original file. Now, here's the same as context
> diff.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
*** ./expected/opr_sanity.out    Sun Jun 22 18:07:13 2003
--- ./results/opr_sanity.out    Sun Jul 27 01:37:24 2003
***************
*** 85,92 ****
       p1.provolatile != p2.provolatile OR
       p1.pronargs != p2.pronargs);
   oid | proname | oid | proname
! -----+---------+-----+---------
! (0 rows)

  -- Look for uses of different type OIDs in the argument/result type fields
  -- for different aliases of the same built-in function.
--- 85,104 ----
       p1.provolatile != p2.provolatile OR
       p1.pronargs != p2.pronargs);
   oid  |       proname        | oid  |       proname
! ------+----------------------+------+----------------------
!  2504 | pg_get_ruledef       | 1573 | pg_get_ruledef
!  2505 | pg_get_viewdef       | 1640 | pg_get_viewdef
!  2506 | pg_get_viewdef       | 1641 | pg_get_viewdef
!  2507 | pg_get_indexdef      | 1643 | pg_get_indexdef
!  2508 | pg_get_constraintdef | 1387 | pg_get_constraintdef
!  2509 | pg_get_expr          | 1716 | pg_get_expr
!  1716 | pg_get_expr          | 2509 | pg_get_expr
!  1573 | pg_get_ruledef       | 2504 | pg_get_ruledef
!  1640 | pg_get_viewdef       | 2505 | pg_get_viewdef
!  1641 | pg_get_viewdef       | 2506 | pg_get_viewdef
!  1643 | pg_get_indexdef      | 2507 | pg_get_indexdef
!  1387 | pg_get_constraintdef | 2508 | pg_get_constraintdef
! (12 rows)

  -- Look for uses of different type OIDs in the argument/result type fields
  -- for different aliases of the same built-in function.
***************
*** 136,147 ****
      (p1.proargtypes[1] < p2.proargtypes[1]);
   proargtypes | proargtypes
  -------------+-------------
            23 |          28
            25 |        1042
          1114 |        1184
          1560 |        1562
          2277 |        2283
! (5 rows)

  SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2]
  FROM pg_proc AS p1, pg_proc AS p2
--- 148,161 ----
      (p1.proargtypes[1] < p2.proargtypes[1]);
   proargtypes | proargtypes
  -------------+-------------
+            0 |          16
+            0 |          23
            23 |          28
            25 |        1042
          1114 |        1184
          1560 |        1562
          2277 |        2283
! (7 rows)

  SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2]
  FROM pg_proc AS p1, pg_proc AS p2
***************
*** 152,159 ****
      (p1.proargtypes[2] < p2.proargtypes[2]);
   proargtypes | proargtypes
  -------------+-------------
          1114 |        1184
! (1 row)

  SELECT DISTINCT p1.proargtypes[3], p2.proargtypes[3]
  FROM pg_proc AS p1, pg_proc AS p2
--- 166,174 ----
      (p1.proargtypes[2] < p2.proargtypes[2]);
   proargtypes | proargtypes
  -------------+-------------
+            0 |          16
          1114 |        1184
! (2 rows)

  SELECT DISTINCT p1.proargtypes[3], p2.proargtypes[3]
  FROM pg_proc AS p1, pg_proc AS p2

======================================================================

*** ./expected/rules.out    Sun Jul 27 00:26:06 2003
--- ./results/rules.out    Sun Jul 27 01:37:42 2003
***************
*** 1314,1320 ****
  SELECT tablename, rulename, definition FROM pg_rules
      ORDER BY tablename, rulename;
     tablename   |    rulename     |
                                             definition
                                                                  
!
---------------+-----------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   pg_settings   | pg_settings_n   | CREATE RULE pg_settings_n AS ON UPDATE TO pg_settings DO INSTEAD NOTHING;
   pg_settings   | pg_settings_u   | CREATE RULE pg_settings_u AS ON UPDATE TO pg_settings WHERE (new.name = old.name)
DOSELECT set_config(old.name, new.setting, false) AS set_config; 
   rtest_emp     | rtest_emp_del   | CREATE RULE rtest_emp_del AS ON DELETE TO rtest_emp DO INSERT INTO rtest_emplog
(ename,who, "action", newsal, oldsal) VALUES (old.ename, "current_user"(), 'fired'::bpchar, '$0.00'::money,
old.salary);
--- 1314,1320 ----
  SELECT tablename, rulename, definition FROM pg_rules
      ORDER BY tablename, rulename;
     tablename   |    rulename     |
                                             definition
                                                                 
!
---------------+-----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   pg_settings   | pg_settings_n   | CREATE RULE pg_settings_n ASON UPDATE TO pg_settings DO INSTEAD NOTHING;
   pg_settings   | pg_settings_u   | CREATE RULE pg_settings_u ASON UPDATE TO pg_settings WHERE (new.name = old.name)
DOSELECT set_config(old.name, new.setting, false) AS set_config; 
   rtest_emp     | rtest_emp_del   | CREATE RULE rtest_emp_del ASON DELETE TO rtest_emp DO INSERT INTO rtest_emplog
(ename,who, "action", newsal, oldsal) VALUES (old.ename, "current_user"(), 'fired'::bpchar, '$0.00'::money,
old.salary);

======================================================================

Index: src/backend/utils/adt/ruleutils.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.146
diff -c -c -r1.146 ruleutils.c
*** src/backend/utils/adt/ruleutils.c    27 Jul 2003 04:53:09 -0000    1.146
--- src/backend/utils/adt/ruleutils.c    27 Jul 2003 05:38:38 -0000
***************
*** 71,76 ****
--- 71,95 ----
  #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,86 ****
--- 100,107 ----
  {
      StringInfo    buf;            /* output buffer to append to */
      List       *namespaces;        /* List of deparse_namespace nodes */
+         int             prettyFlags;            /* enabling/disabling of pretty-print functions */
+         int             indentLevel;            /* for prettyPrint, current space indents are counted */
      bool        varprefix;        /* TRUE to print prefixes on Vars */
  } deparse_context;

***************
*** 123,135 ****
   * as a parameter, and append their text output to its contents.
   * ----------
   */
! static text *pg_do_getviewdef(Oid viewoid);
  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 void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
!               TupleDesc resultDesc);
  static void get_select_query_def(Query *query, deparse_context *context,
                       TupleDesc resultDesc);
  static void get_insert_query_def(Query *query, deparse_context *context);
--- 144,162 ----
   * as a parameter, and append their text output to its contents.
   * ----------
   */
! static char *get_simple_binary_op_name(OpExpr *expr);
! static void appendStringInfoSpace(StringInfo buf, int count);
! static void appendContextKeyword(deparse_context *context, char *str, int indentBefore, int indentAfter, int
indentPlus);
! static char *deparse_expression_pretty(Node *expr, List *dpcontext,
!               bool forceprefix, bool showimplicit, int prettyFlags, int startIndent);
! static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
! 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, 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, 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);
***************
*** 192,197 ****
--- 219,225 ----
      TupleDesc    rulettc;
      StringInfoData buf;
      int            len;
+     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;

      /*
       * Connect to SPI manager
***************
*** 241,247 ****
       * Get the rules definition and put it into executors memory
       */
      initStringInfo(&buf);
!     make_ruledef(&buf, ruletup, rulettc);
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
      VARATT_SIZEP(ruledef) = len;
--- 269,275 ----
       * Get the rules definition and put it into executors memory
       */
      initStringInfo(&buf);
!     make_ruledef(&buf, ruletup, rulettc, prettyFlags);
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
      VARATT_SIZEP(ruledef) = len;
***************
*** 272,279 ****
      /* By OID */
      Oid            viewoid = PG_GETARG_OID(0);
      text       *ruledef;

!     ruledef = pg_do_getviewdef(viewoid);
      PG_RETURN_TEXT_P(ruledef);
  }

--- 300,308 ----
      /* By OID */
      Oid            viewoid = PG_GETARG_OID(0);
      text       *ruledef;
+     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;

!     ruledef = pg_do_getviewdef(viewoid, prettyFlags);
      PG_RETURN_TEXT_P(ruledef);
  }

***************
*** 285,296 ****
      RangeVar   *viewrel;
      Oid            viewoid;
      text       *ruledef;

      viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname,
                                                           "get_viewdef"));
      viewoid = RangeVarGetRelid(viewrel, false);

!     ruledef = pg_do_getviewdef(viewoid);
      PG_RETURN_TEXT_P(ruledef);
  }

--- 314,326 ----
      RangeVar   *viewrel;
      Oid            viewoid;
      text       *ruledef;
+     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? 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,304 ****
   * Common code for by-OID and by-name variants of pg_get_viewdef
   */
  static text *
! pg_do_getviewdef(Oid viewoid)
  {
      text       *ruledef;
      Datum        args[2];
--- 328,334 ----
   * Common code for by-OID and by-name variants of pg_get_viewdef
   */
  static text *
! pg_do_getviewdef(Oid viewoid, int prettyFlags)
  {
      text       *ruledef;
      Datum        args[2];
***************
*** 353,359 ****
           */
          ruletup = SPI_tuptable->vals[0];
          rulettc = SPI_tuptable->tupdesc;
!         make_viewdef(&buf, ruletup, rulettc);
      }
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
--- 383,389 ----
           */
          ruletup = SPI_tuptable->vals[0];
          rulettc = SPI_tuptable->tupdesc;
!         make_viewdef(&buf, ruletup, rulettc, prettyFlags);
      }
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
***************
*** 543,548 ****
--- 573,580 ----
      StringInfoData buf;
      char       *str;
      char       *sep;
+     int        colno = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);
+     int        prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;

      /*
       * Fetch the pg_index tuple by the Oid of the index
***************
*** 582,587 ****
--- 614,621 ----
       * Get the index expressions, if any.  (NOTE: we do not use the relcache
       * versions of the expressions and predicate, because we want to display
       * non-const-folded expressions.)
+          * if colno == 0, we want a complete index definition.
+          * if colno > 0, we only want the nth expression.
       */
      if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
      {
***************
*** 607,613 ****
       * never be schema-qualified, but the indexed rel's name may be.
       */
      initStringInfo(&buf);
!     appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
                       idxrec->indisunique ? "UNIQUE " : "",
                       quote_identifier(NameStr(idxrelrec->relname)),
                       generate_relation_name(indrelid),
--- 641,649 ----
       * never be schema-qualified, but the indexed rel's name may be.
       */
      initStringInfo(&buf);
!
!     if (!colno)
!         appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
                       idxrec->indisunique ? "UNIQUE " : "",
                       quote_identifier(NameStr(idxrelrec->relname)),
                       generate_relation_name(indrelid),
***************
*** 621,627 ****
      {
          AttrNumber    attnum = idxrec->indkey[keyno];

!         appendStringInfo(&buf, sep);
          sep = ", ";

          if (attnum != 0)
--- 657,664 ----
      {
          AttrNumber    attnum = idxrec->indkey[keyno];

!         if (!colno)
!             appendStringInfo(&buf, sep);
          sep = ", ";

          if (attnum != 0)
***************
*** 630,636 ****
              char       *attname;

              attname = get_relid_attribute_name(indrelid, attnum);
!             appendStringInfo(&buf, "%s", quote_identifier(attname));
              keycoltype = get_atttype(indrelid, attnum);
          }
          else
--- 667,674 ----
              char       *attname;

              attname = get_relid_attribute_name(indrelid, attnum);
!             if (!colno || colno == keyno+1)
!                 appendStringInfo(&buf, "%s", quote_identifier(attname));
              keycoltype = get_atttype(indrelid, attnum);
          }
          else
***************
*** 643,672 ****
              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);
              keycoltype = exprType(indexkey);
          }

          /*
           * Add the operator class name
           */
!         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))
      {
          Node       *node;
          Datum        predDatum;
          bool        isnull;
--- 681,716 ----
              indexkey = (Node *) lfirst(indexprs);
              indexprs = lnext(indexprs);
              /* Deparse */
!             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
           */
!         if (!colno)
!             get_opclass_name(idxrec->indclass[keyno], keycoltype,
                           &buf);
      }

!     if (!colno)
      {
+         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;
***************
*** 689,698 ****
          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);
      }
-
      /*
       * Create the result as a TEXT datum, and free working data
       */
--- 733,742 ----
          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);
+         }
      }
      /*
       * Create the result as a TEXT datum, and free working data
       */
***************
*** 729,734 ****
--- 773,779 ----
      ScanKeyData skey[1];
      HeapTuple    tup;
      Form_pg_constraint conForm;
+     int      prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;

      /*
       * Fetch the pg_constraint row.  There's no syscache for pg_constraint
***************
*** 934,940 ****
                      context = deparse_context_for(get_typname(conForm->contypid),
                                                    InvalidOid);

!                 consrc = deparse_expression(expr, context, false, false);

                  /* Append the constraint source */
                  appendStringInfoString(&buf, consrc);
--- 979,985 ----
                      context = deparse_context_for(get_typname(conForm->contypid),
                                                    InvalidOid);

!                 consrc = deparse_expression_pretty(expr, context, false, false, prettyFlags, 0);

                  /* Append the constraint source */
                  appendStringInfoString(&buf, consrc);
***************
*** 1020,1025 ****
--- 1065,1071 ----
      char       *exprstr;
      char       *relname;
      char       *str;
+     int      prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;

      /* Get the name for the relation */
      relname = get_rel_name(relid);
***************
*** 1043,1049 ****

      /* Deparse */
      context = deparse_context_for(relname, relid);
!     str = deparse_expression(node, context, false, false);

      /* Pass the result back as TEXT */
      result = DatumGetTextP(DirectFunctionCall1(textin,
--- 1089,1095 ----

      /* Deparse */
      context = deparse_context_for(relname, relid);
!     str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0);

      /* Pass the result back as TEXT */
      result = DatumGetTextP(DirectFunctionCall1(textin,
***************
*** 1092,1097 ****
--- 1138,1154 ----

  /* ----------
   * 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,1114 ****
   * 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.
   *
   * The result is a palloc'd string.
   * ----------
   */
  char *
! deparse_expression(Node *expr, List *dpcontext,
!                    bool forceprefix, bool showimplicit)
  {
      StringInfoData buf;
      deparse_context context;
--- 1159,1173 ----
   * 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
   *
   * The result is a palloc'd string.
   * ----------
   */
  char *
! deparse_expression_pretty(Node *expr, List *dpcontext,
!                    bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
  {
      StringInfoData buf;
      deparse_context context;
***************
*** 1117,1122 ****
--- 1176,1183 ----
      context.buf = &buf;
      context.namespaces = dpcontext;
      context.varprefix = forceprefix;
+     context.prettyFlags = prettyFlags;
+     context.indentLevel = startIndent;

      get_rule_expr(expr, &context, showimplicit);

***************
*** 1269,1275 ****
   * ----------
   */
  static void
! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
  {
      char       *rulename;
      char        ev_type;
--- 1330,1336 ----
   * ----------
   */
  static void
! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
  {
      char       *rulename;
      char        ev_type;
***************
*** 1323,1331 ****
      /*
       * Build the rules definition text
       */
!     appendStringInfo(buf, "CREATE RULE %s AS ON ",
                       quote_identifier(rulename));

      /* The event the rule is fired for */
      switch (ev_type)
      {
--- 1384,1397 ----
      /*
       * Build the rules definition text
       */
!     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,1375 ****
--- 1436,1443 ----
          deparse_context context;
          deparse_namespace dpns;

+         if (prettyFlags & PRETTYFLAG_INDENT)
+             appendStringInfoString(buf, "\n  ");
          appendStringInfo(buf, " WHERE ");

          qual = stringToNode(ev_qual);
***************
*** 1391,1396 ****
--- 1459,1466 ----
          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,1421 ****
          foreach(action, actions)
          {
              query = (Query *) lfirst(action);
!             get_query_def(query, buf, NIL, NULL);
!             appendStringInfo(buf, "; ");
          }
          appendStringInfo(buf, ");");
      }
--- 1484,1494 ----
          foreach(action, actions)
          {
              query = (Query *) lfirst(action);
!             get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
!             if (prettyFlags)
!                 appendStringInfo(buf, ";\n");
!             else
!                 appendStringInfo(buf, "; ");
          }
          appendStringInfo(buf, ");");
      }
***************
*** 1428,1434 ****
          Query       *query;

          query = (Query *) lfirst(actions);
!         get_query_def(query, buf, NIL, NULL);
          appendStringInfo(buf, ";");
      }
  }
--- 1501,1507 ----
          Query       *query;

          query = (Query *) lfirst(actions);
!         get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
          appendStringInfo(buf, ";");
      }
  }
***************
*** 1440,1446 ****
   * ----------
   */
  static void
! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
  {
      Query       *query;
      char        ev_type;
--- 1513,1519 ----
   * ----------
   */
  static void
! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
  {
      Query       *query;
      char        ev_type;
***************
*** 1494,1500 ****

      ev_relation = heap_open(ev_class, AccessShareLock);

!     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation));
      appendStringInfo(buf, ";");

      heap_close(ev_relation, AccessShareLock);
--- 1567,1573 ----

      ev_relation = heap_open(ev_class, AccessShareLock);

!     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), prettyFlags, 0);
      appendStringInfo(buf, ";");

      heap_close(ev_relation, AccessShareLock);
***************
*** 1510,1516 ****
   */
  static void
  get_query_def(Query *query, StringInfo buf, List *parentnamespace,
!               TupleDesc resultDesc)
  {
      deparse_context context;
      deparse_namespace dpns;
--- 1583,1589 ----
   */
  static void
  get_query_def(Query *query, StringInfo buf, List *parentnamespace,
!               TupleDesc resultDesc, int prettyFlags, int startIndent)
  {
      deparse_context context;
      deparse_namespace dpns;
***************
*** 1519,1524 ****
--- 1592,1600 ----
      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,1596 ****
      /* Add the ORDER BY clause if given */
      if (query->sortClause != NIL)
      {
!         appendStringInfo(buf, " ORDER BY ");
          sep = "";
          foreach(l, query->sortClause)
          {
--- 1666,1672 ----
      /* Add the ORDER BY clause if given */
      if (query->sortClause != NIL)
      {
!             appendContextKeyword(context, " ORDER BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          sep = "";
          foreach(l, query->sortClause)
          {
***************
*** 1619,1630 ****
      /* Add the LIMIT clause if given */
      if (query->limitOffset != NULL)
      {
!         appendStringInfo(buf, " OFFSET ");
          get_rule_expr(query->limitOffset, context, false);
      }
      if (query->limitCount != NULL)
      {
!         appendStringInfo(buf, " LIMIT ");
          if (IsA(query->limitCount, Const) &&
              ((Const *) query->limitCount)->constisnull)
              appendStringInfo(buf, "ALL");
--- 1695,1706 ----
      /* Add the LIMIT clause if given */
      if (query->limitOffset != NULL)
      {
!         appendContextKeyword(context, " OFFSET ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
          get_rule_expr(query->limitOffset, context, false);
      }
      if (query->limitCount != NULL)
      {
!         appendContextKeyword(context, " LIMIT ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
          if (IsA(query->limitCount, Const) &&
              ((Const *) query->limitCount)->constisnull)
              appendStringInfo(buf, "ALL");
***************
*** 1645,1650 ****
--- 1721,1731 ----
      /*
       * 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,1737 ****
      /* Add the WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendStringInfo(buf, " WHERE ");
          get_rule_expr(query->jointree->quals, context, false);
      }

      /* Add the GROUP BY clause if given */
      if (query->groupClause != NULL)
      {
!         appendStringInfo(buf, " GROUP BY ");
          sep = "";
          foreach(l, query->groupClause)
          {
--- 1805,1818 ----
      /* Add the WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         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)
      {
!         appendContextKeyword(context, " GROUP BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          sep = "";
          foreach(l, query->groupClause)
          {
***************
*** 1747,1753 ****
      /* Add the HAVING clause if given */
      if (query->havingQual != NULL)
      {
!         appendStringInfo(buf, " HAVING ");
          get_rule_expr(query->havingQual, context, false);
      }
  }
--- 1828,1834 ----
      /* Add the HAVING clause if given */
      if (query->havingQual != NULL)
      {
!         appendContextKeyword(context, " HAVING ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
          get_rule_expr(query->havingQual, context, false);
      }
  }
***************
*** 1765,1799 ****
          Query       *subquery = rte->subquery;

          Assert(subquery != NULL);
!         get_query_def(subquery, buf, context->namespaces, resultDesc);
      }
      else if (IsA(setOp, SetOperationStmt))
      {
          SetOperationStmt *op = (SetOperationStmt *) setOp;

-         appendStringInfo(buf, "((");
          get_setop_query(op->larg, query, context, resultDesc);
          switch (op->op)
          {
              case SETOP_UNION:
!                 appendStringInfo(buf, ") UNION ");
                  break;
              case SETOP_INTERSECT:
!                 appendStringInfo(buf, ") INTERSECT ");
                  break;
              case SETOP_EXCEPT:
!                 appendStringInfo(buf, ") EXCEPT ");
                  break;
              default:
                  elog(ERROR, "unrecognized set op: %d",
                       (int) op->op);
          }
          if (op->all)
!             appendStringInfo(buf, "ALL (");
          else
!             appendStringInfo(buf, "(");
          get_setop_query(op->rarg, query, context, resultDesc);
!         appendStringInfo(buf, "))");
      }
      else
      {
--- 1846,1909 ----
          Query       *subquery = rte->subquery;

          Assert(subquery != NULL);
!         get_query_def(subquery, buf, context->namespaces, resultDesc, context->prettyFlags, context->indentLevel);
      }
      else if (IsA(setOp, SetOperationStmt))
      {
          SetOperationStmt *op = (SetOperationStmt *) setOp;
+         bool need_paren=(PRETTY_PAREN(context) ? !IsA(op->rarg, RangeTblRef) : true);
+
+         if (!PRETTY_PAREN(context))
+             appendStringInfoString(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:
!                 appendContextKeyword(context, "UNION ", -PRETTYINDENT_STD, 0, 0);
                  break;
              case SETOP_INTERSECT:
!                 appendContextKeyword(context, "INTERSECT ", -PRETTYINDENT_STD, 0, 0);
                  break;
              case SETOP_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 ");
!
!         if (PRETTY_INDENT(context))
!             appendStringInfoChar(buf, '\n');
!
!         if (PRETTY_PAREN(context))
!         {
!             if (need_paren)
!             {
!             appendStringInfoChar(buf, '(');
!             if (PRETTY_INDENT(context))
!                 appendStringInfoChar(buf, '\n');
!             }
!         }
          else
!             appendStringInfoChar(buf, '(');
!
          get_setop_query(op->rarg, query, context, resultDesc);
!
!         if (PRETTY_PAREN(context))
!         {
!             if (need_paren)
!             appendStringInfoChar(buf, ')');
!         }
!         else
!             appendStringInfoString(buf, "))");
      }
      else
      {
***************
*** 1866,1871 ****
--- 1976,1987 ----
       */
      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,1893 ****
      /* Add the VALUES or the SELECT */
      if (select_rte == NULL)
      {
!         appendStringInfo(buf, "VALUES (");
          sep = "";
          foreach(l, query->targetList)
          {
--- 2003,2009 ----
      /* Add the VALUES or the SELECT */
      if (select_rte == NULL)
      {
!         appendContextKeyword(context, "VALUES (", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
          sep = "";
          foreach(l, query->targetList)
          {
***************
*** 1903,1909 ****
          appendStringInfoChar(buf, ')');
      }
      else
!         get_query_def(select_rte->subquery, buf, NIL, NULL);
  }


--- 2019,2025 ----
          appendStringInfoChar(buf, ')');
      }
      else
!         get_query_def(select_rte->subquery, buf, NIL, NULL, context->prettyFlags, context->indentLevel);
  }


***************
*** 1924,1929 ****
--- 2040,2050 ----
       */
      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,1963 ****
      /* Finally add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendStringInfo(buf, " WHERE ");
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
--- 2078,2084 ----
      /* Finally add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
***************
*** 1978,1983 ****
--- 2099,2109 ----
       */
      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,1991 ****
      /* Add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendStringInfo(buf, " WHERE ");
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
--- 2111,2117 ----
      /* Add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
***************
*** 2004,2009 ****
--- 2130,2136 ----
      {
          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,2150 ****
--- 2272,2513 ----
  }


+ /********************************************
+  * get_simple_binary_op_name
+  * helper function for isSimpleNode
+  * will return single char binary operator
+  *******************************************/
+
+ static 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);
+         char *op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
+
+         if (strlen(op) == 1)
+             return op;
+     }
+     return 0;
+ }
+
+
+ /***************************************
+  * check if given node is simple.
+  *  false  : not simple
+  *  true   : simple in the context of parent node's type
+  ***************************************/
+
+ static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
+ {
+     if (!node)
+     return true;
+
+     switch (nodeTag(node))
+     {
+     // single words: always simple
+     case T_Var:
+     case T_Const:
+     case T_Param:
+
+     // function-like: name(..) or name[..]
+     case T_ArrayRef:
+     case T_ArrayExpr:
+     case T_CoalesceExpr:
+     case T_NullIfExpr:
+     case T_Aggref:
+     case T_FuncExpr:
+
+         // CASE keywords act as parentheses
+     case T_CaseExpr:
+         return true;
+
+         // appears simple since . has top precedence, unless parent is T_FieldSelect itself!
+     case T_FieldSelect:
+         return (nodeTag(parentNode) == T_FieldSelect ? false : true);
+
+
+         // maybe simple, check args
+     case T_CoerceToDomain:
+         return isSimpleNode((Node*) ((CoerceToDomain*)node)->arg, node, prettyFlags);
+     case T_RelabelType:
+         return isSimpleNode((Node*) ((RelabelType*)node)->arg, node, prettyFlags);
+
+
+     // depends on parent node type; needs further checking
+     case T_OpExpr:
+     {
+         if (prettyFlags & PRETTYFLAG_PAREN && nodeTag(parentNode) == T_OpExpr)
+         {
+         char *op=get_simple_binary_op_name((OpExpr*)node);
+         char *parentOp=get_simple_binary_op_name((OpExpr*)parentNode);
+         if (!op || !parentOp)
+             return false;
+
+                 // we know only these basic operators
+         if (!strchr("+-*/%", *op) || !strchr("+-*/%", *parentOp))
+             return false;
+
+         // natural operator precedence, so we don't need parentheses
+         if (strchr("*/%", *op) || strchr("+-", *parentOp))
+             return true;
+
+         return false;
+         }
+             // else do the same stuff as for T_SubLink et al.
+     }
+     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=((BoolExpr*)node)->boolop;
+             BoolExprType 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;
+         }
+         // these are not completely implemented; so far, they're simple
+     case T_SubPlan:
+     case T_CoerceToDomainValue:
+         return true;
+
+     case T_ScalarArrayOpExpr:
+         // need to check
+     default:
+         break;
+     }
+     // those we don't know: in dubio complexo
+     return false;
+ }
+
+
+ /******************************************
+  * appendContextKeyword
+  * append spaces to buffer
+  ******************************************/
+ static void appendStringInfoSpace(StringInfo buf, int count)
+ {
+     while (count-- > 0)
+     appendStringInfoChar(buf, ' ');
+ }
+
+ /******************************************
+  * appendContextKeyword
+  * performing a line break, and indentation
+  * if prettyPrint is enabled.
+  * Otherwise, only the keyword is appended
+  *****************************************/
+
+ static void appendContextKeyword(deparse_context *context, 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');
+     appendStringInfoSpace(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  - parsing expr using get_rule_expr,
+  * embracing the string with parentheses if necessary for prettyPrint.
+  * never embracing 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 = 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
   *
***************
*** 2299,2310 ****
                  List       *args = expr->args;
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);
!
!                 appendStringInfoChar(buf, '(');
!                 get_rule_expr(arg1, context, true);
                  appendStringInfo(buf, " IS DISTINCT FROM ");
!                 get_rule_expr(arg2, context, true);
!                 appendStringInfoChar(buf, ')');
              }
              break;

--- 2662,2674 ----
                  List       *args = expr->args;
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, '(');
!                 get_rule_expr_paren(arg1, context, true, node);
                  appendStringInfo(buf, " IS DISTINCT FROM ");
!                 get_rule_expr_paren(arg2, context, true, node);
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, ')');
              }
              break;

***************
*** 2315,2329 ****
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);

!                 appendStringInfoChar(buf, '(');
!                 get_rule_expr(arg1, context, true);
                  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, "))");
              }
              break;

--- 2679,2697 ----
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);

!                 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_paren(arg2, context, true, node);
!                 appendStringInfoString(buf, ")");
!
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, ')');
              }
              break;

***************
*** 2335,2367 ****
                  switch (expr->boolop)
                  {
                      case AND_EXPR:
!                         appendStringInfoChar(buf, '(');
!                         get_rule_expr((Node *) lfirst(args), context, false);
                          while ((args = lnext(args)) != NIL)
                          {
                              appendStringInfo(buf, " AND ");
!                             get_rule_expr((Node *) lfirst(args), context,
!                                           false);
                          }
!                         appendStringInfoChar(buf, ')');
                          break;

                      case OR_EXPR:
!                         appendStringInfoChar(buf, '(');
!                         get_rule_expr((Node *) lfirst(args), context, false);
                          while ((args = lnext(args)) != NIL)
                          {
                              appendStringInfo(buf, " OR ");
!                             get_rule_expr((Node *) lfirst(args), context,
!                                           false);
                          }
!                         appendStringInfoChar(buf, ')');
                          break;

                      case NOT_EXPR:
!                         appendStringInfo(buf, "(NOT ");
!                         get_rule_expr((Node *) lfirst(args), context, false);
!                         appendStringInfoChar(buf, ')');
                          break;

                      default:
--- 2703,2742 ----
                  switch (expr->boolop)
                  {
                      case AND_EXPR:
!                             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_paren((Node *) lfirst(args), context,
!                                           false, node);
                          }
!                             if (!PRETTY_PAREN(context))
!                             appendStringInfoChar(buf, ')');
                          break;

                      case OR_EXPR:
!                             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_paren((Node *) lfirst(args), context,
!                                           false, node);
                          }
!                             if (!PRETTY_PAREN(context))
!                             appendStringInfoChar(buf, ')');
                          break;

                      case NOT_EXPR:
!                             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,2417 ****
                   * 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));
              }
              break;

--- 2784,2795 ----
                   * arg.fieldname, but most cases where FieldSelect is used
                   * are *not* simple.  So, always use parenthesized syntax.
                   */
!                     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,2430 ****
                      !showimplicit)
                  {
                      /* don't show the implicit cast */
!                     get_rule_expr(arg, context, showimplicit);
                  }
                  else
                  {
--- 2802,2808 ----
                      !showimplicit)
                  {
                      /* don't show the implicit cast */
!                     get_rule_expr_paren(arg, context, showimplicit, node);
                  }
                  else
                  {
***************
*** 2436,2444 ****
                       */
                      arg = strip_type_coercion(arg, relabel->resulttype);

!                     appendStringInfoChar(buf, '(');
!                     get_rule_expr(arg, context, showimplicit);
!                     appendStringInfo(buf, ")::%s",
                              format_type_with_typemod(relabel->resulttype,
                                                       relabel->resulttypmod));
                  }
--- 2814,2826 ----
                       */
                      arg = strip_type_coercion(arg, relabel->resulttype);

!                     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,2468 ****
                  CaseExpr   *caseexpr = (CaseExpr *) node;
                  List       *temp;

!                 appendStringInfo(buf, "CASE");
                  foreach(temp, caseexpr->args)
                  {
                      CaseWhen   *when = (CaseWhen *) lfirst(temp);

!                     appendStringInfo(buf, " WHEN ");
                      get_rule_expr((Node *) when->expr, context, false);
                      appendStringInfo(buf, " THEN ");
                      get_rule_expr((Node *) when->result, context, true);
                  }
!                 appendStringInfo(buf, " ELSE ");
                  get_rule_expr((Node *) caseexpr->defresult, context, true);
!                 appendStringInfo(buf, " END");
              }
              break;

--- 2832,2858 ----
                  CaseExpr   *caseexpr = (CaseExpr *) node;
                  List       *temp;

!                 appendContextKeyword(context, "CASE", 0, PRETTYINDENT_VAR, 0);
                  foreach(temp, caseexpr->args)
                  {
                      CaseWhen   *when = (CaseWhen *) lfirst(temp);

!                     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);
                  }
!                 if (!PRETTY_INDENT(context))
!                     appendStringInfoChar(buf, ' ');
!                 appendContextKeyword(context, "ELSE ", 0, 0, 0);
                  get_rule_expr((Node *) caseexpr->defresult, context, true);
!                 if (!PRETTY_INDENT(context))
!                     appendStringInfoChar(buf, ' ');
!                 appendContextKeyword(context, "END", -PRETTYINDENT_VAR, 0, 0);
              }
              break;

***************
*** 2530,2549 ****
              {
                  NullTest   *ntest = (NullTest *) node;

!                 appendStringInfo(buf, "(");
!                 get_rule_expr((Node *) ntest->arg, context, true);
                  switch (ntest->nulltesttype)
                  {
                      case IS_NULL:
!                         appendStringInfo(buf, " IS NULL)");
                          break;
                      case IS_NOT_NULL:
!                         appendStringInfo(buf, " IS NOT NULL)");
                          break;
                      default:
                          elog(ERROR, "unrecognized nulltesttype: %d",
                               (int) ntest->nulltesttype);
                  }
              }
              break;

--- 2920,2942 ----
              {
                  NullTest   *ntest = (NullTest *) node;

!                 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");
                          break;
                      case 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,2582 ****
              {
                  BooleanTest *btest = (BooleanTest *) node;

!                 appendStringInfo(buf, "(");
!                 get_rule_expr((Node *) btest->arg, context, false);
                  switch (btest->booltesttype)
                  {
                      case IS_TRUE:
!                         appendStringInfo(buf, " IS TRUE)");
                          break;
                      case IS_NOT_TRUE:
!                         appendStringInfo(buf, " IS NOT TRUE)");
                          break;
                      case IS_FALSE:
!                         appendStringInfo(buf, " IS FALSE)");
                          break;
                      case IS_NOT_FALSE:
!                         appendStringInfo(buf, " IS NOT FALSE)");
                          break;
                      case IS_UNKNOWN:
!                         appendStringInfo(buf, " IS UNKNOWN)");
                          break;
                      case IS_NOT_UNKNOWN:
!                         appendStringInfo(buf, " IS NOT UNKNOWN)");
                          break;
                      default:
                          elog(ERROR, "unrecognized booltesttype: %d",
                               (int) btest->booltesttype);
                  }
              }
              break;

--- 2944,2978 ----
              {
                  BooleanTest *btest = (BooleanTest *) node;

!                 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");
                          break;
                      case IS_NOT_TRUE:
!                         appendStringInfo(buf, " IS NOT TRUE");
                          break;
                      case IS_FALSE:
!                         appendStringInfo(buf, " IS FALSE");
                          break;
                      case IS_NOT_FALSE:
!                         appendStringInfo(buf, " IS NOT FALSE");
                          break;
                      case IS_UNKNOWN:
!                         appendStringInfo(buf, " IS UNKNOWN");
                          break;
                      case 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,2606 ****
                  }
                  else
                  {
!                     appendStringInfoChar(buf, '(');
!                     get_rule_expr(arg, context, false);
!                     appendStringInfo(buf, ")::%s",
                              format_type_with_typemod(ctest->resulttype,
                                                       ctest->resulttypmod));
                  }
--- 2994,3007 ----
                  }
                  else
                  {
!                     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,2650 ****
      Oid            opno = expr->opno;
      List       *args = expr->args;

!     appendStringInfoChar(buf, '(');
      if (length(args) == 2)
      {
          /* binary operator */
          Node       *arg1 = (Node *) lfirst(args);
          Node       *arg2 = (Node *) lsecond(args);
!
!         get_rule_expr(arg1, context, true);
          appendStringInfo(buf, " %s ",
                           generate_operator_name(opno,
                                                  exprType(arg1),
                                                  exprType(arg2)));
!         get_rule_expr(arg2, context, true);
      }
      else
      {
--- 3033,3051 ----
      Oid            opno = expr->opno;
      List       *args = expr->args;

!     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_paren(arg1, context, true, (Node*)expr);
          appendStringInfo(buf, " %s ",
                           generate_operator_name(opno,
                                                  exprType(arg1),
                                                  exprType(arg2)));
!         get_rule_expr_paren(arg2, context, true, (Node*)expr);
      }
      else
      {
***************
*** 2666,2675 ****
                                   generate_operator_name(opno,
                                                          InvalidOid,
                                                          exprType(arg)));
!                 get_rule_expr(arg, context, true);
                  break;
              case 'r':
!                 get_rule_expr(arg, context, true);
                  appendStringInfo(buf, " %s",
                                   generate_operator_name(opno,
                                                          exprType(arg),
--- 3067,3076 ----
                                   generate_operator_name(opno,
                                                          InvalidOid,
                                                          exprType(arg)));
!                 get_rule_expr_paren(arg, context, true, (Node*)expr);
                  break;
              case 'r':
!                 get_rule_expr_paren(arg, context, true, (Node*)expr);
                  appendStringInfo(buf, " %s",
                                   generate_operator_name(opno,
                                                          exprType(arg),
***************
*** 2680,2686 ****
          }
          ReleaseSysCache(tp);
      }
!     appendStringInfoChar(buf, ')');
  }

  /*
--- 3081,3088 ----
          }
          ReleaseSysCache(tp);
      }
!     if (!PRETTY_PAREN(context))
!         appendStringInfoChar(buf, ')');
  }

  /*
***************
*** 2703,2709 ****
       */
      if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
      {
!         get_rule_expr((Node *) lfirst(expr->args), context, showimplicit);
          return;
      }

--- 3105,3111 ----
       */
      if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
      {
!         get_rule_expr_paren((Node *) lfirst(expr->args), context, showimplicit, (Node*)expr);
          return;
      }

***************
*** 2729,2737 ****
           */
          arg = strip_type_coercion(arg, rettype);

!         appendStringInfoChar(buf, '(');
!         get_rule_expr(arg, context, showimplicit);
!         appendStringInfo(buf, ")::%s",
                           format_type_with_typemod(rettype, coercedTypmod));

          return;
--- 3131,3144 ----
           */
          arg = strip_type_coercion(arg, rettype);

!         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,3058 ****
      if (need_paren)
          appendStringInfoChar(buf, '(');

!     get_query_def(query, buf, context->namespaces, NULL);

      if (need_paren)
          appendStringInfo(buf, "))");
--- 3459,3465 ----
      if (need_paren)
          appendStringInfoChar(buf, '(');

!     get_query_def(query, buf, context->namespaces, NULL, context->prettyFlags, context->indentLevel);

      if (need_paren)
          appendStringInfo(buf, "))");
***************
*** 3069,3075 ****
  get_from_clause(Query *query, deparse_context *context)
  {
      StringInfo    buf = context->buf;
!     char       *sep;
      List       *l;

      /*
--- 3476,3482 ----
  get_from_clause(Query *query, deparse_context *context)
  {
      StringInfo    buf = context->buf;
!     char       *sep=0;
      List       *l;

      /*
***************
*** 3079,3085 ****
       * sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW
       * and OLD.
       */
-     sep = " FROM ";

      foreach(l, query->jointree->fromlist)
      {
--- 3486,3491 ----
***************
*** 3098,3104 ****
                  continue;
          }

!         appendStringInfo(buf, sep);
          get_from_clause_item(jtnode, query, context);
          sep = ", ";
      }
--- 3504,3514 ----
                  continue;
          }

!         if (!sep)
!             appendContextKeyword(context, " FROM ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
!         else
!             appendStringInfo(buf, sep);
!
          get_from_clause_item(jtnode, query, context);
          sep = ", ";
      }
***************
*** 3127,3133 ****
              case RTE_SUBQUERY:
                  /* Subquery RTE */
                  appendStringInfoChar(buf, '(');
!                 get_query_def(rte->subquery, buf, context->namespaces, NULL);
                  appendStringInfoChar(buf, ')');
                  break;
              case RTE_FUNCTION:
--- 3537,3544 ----
              case RTE_SUBQUERY:
                  /* Subquery RTE */
                  appendStringInfoChar(buf, '(');
!                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
!                           context->prettyFlags, context->indentLevel);
                  appendStringInfoChar(buf, ')');
                  break;
              case RTE_FUNCTION:
***************
*** 3149,3155 ****
              {
                  List       *col;

!                 appendStringInfo(buf, "(");
                  foreach(col, rte->alias->colnames)
                  {
                      if (col != rte->alias->colnames)
--- 3560,3566 ----
              {
                  List       *col;

!                 appendStringInfoChar(buf, '(');
                  foreach(col, rte->alias->colnames)
                  {
                      if (col != rte->alias->colnames)
***************
*** 3183,3218 ****
      else if (IsA(jtnode, JoinExpr))
      {
          JoinExpr   *j = (JoinExpr *) jtnode;

-         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);
          }
          get_from_clause_item(j->rarg, query, context);
          if (!j->isNatural)
          {
              if (j->using)
--- 3594,3671 ----
      else if (IsA(jtnode, JoinExpr))
      {
          JoinExpr   *j = (JoinExpr *) jtnode;
+         bool need_paren_on_right = PRETTY_PAREN(context) && !IsA(j->rarg, RangeTblRef);
+
+         if (!PRETTY_PAREN(context) || j->alias != NULL)
+             appendStringInfoChar(buf, '(');

          get_from_clause_item(j->larg, query, context);
+
          if (j->isNatural)
          {
+             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, "get_from_clause_item: unknown 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)
***************
*** 3231,3242 ****
              }
              else if (j->quals)
              {
!                 appendStringInfo(buf, " ON (");
                  get_rule_expr(j->quals, context, false);
!                 appendStringInfoChar(buf, ')');
              }
          }
!         appendStringInfoChar(buf, ')');
          /* Yes, it's correct to put alias after the right paren ... */
          if (j->alias != NULL)
          {
--- 3684,3700 ----
              }
              else if (j->quals)
              {
!                 appendStringInfo(buf, " ON ");
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, '(');
                  get_rule_expr(j->quals, context, false);
!                 if (!PRETTY_PAREN(context))
!                     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,3252 ****
              {
                  List       *col;

!                 appendStringInfo(buf, "(");
                  foreach(col, j->alias->colnames)
                  {
                      if (col != j->alias->colnames)
--- 3704,3710 ----
              {
                  List       *col;

!                 appendStringInfoChar(buf, '(');
                  foreach(col, j->alias->colnames)
                  {
                      if (col != j->alias->colnames)
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
retrieving revision 1.309
diff -c -c -r1.309 pg_proc.h
*** src/include/catalog/pg_proc.h    1 Jul 2003 00:04:38 -0000    1.309
--- src/include/catalog/pg_proc.h    27 Jul 2003 05:38:45 -0000
***************
*** 3405,3410 ****
--- 3405,3424 ----
  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 - _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 - _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 - _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 - _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 - _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 - _null_ ));
+ DESCR("deparse an encoded expression with pretty-print option");
+

  /*
   * Symbolic values for provolatile column: these indicate whether the result


Re: ruleutils with pretty-print option

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> Are these illustrating a problem with the function definition, or is it
> happening because it is the first time we are calling the same function
> with one and more than one parameter?

The function definition is broken.  While it could be fixed (by
explicitly testing fcinfo->nargs, rather than assuming positions
beyond nargs are valid) I am not willing to remove the opr_sanity
check that is complaining.  Accordingly, a better solution would be
to make two C-code wrapper functions, one for the single-parameter
and one for the two-parameter case of each function.

            regards, tom lane

Re: ruleutils with pretty-print option

From
Bruce Momjian
Date:
OK, I am working on that now. I suspected that was the solution.

I met the patch author at LinuxTag and he mentioned he wasn't familiar
with the backend code yet, so I am glad to do the work to get this done
correctly.

---------------------------------------------------------------------------

Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > Are these illustrating a problem with the function definition, or is it
> > happening because it is the first time we are calling the same function
> > with one and more than one parameter?
>
> The function definition is broken.  While it could be fixed (by
> explicitly testing fcinfo->nargs, rather than assuming positions
> beyond nargs are valid) I am not willing to remove the opr_sanity
> check that is complaining.  Accordingly, a better solution would be
> to make two C-code wrapper functions, one for the single-parameter
> and one for the two-parameter case of each function.
>
>             regards, tom lane
>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: the planner will ignore your desire to choose an index scan if your
>       joining column's datatypes do not match
>

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: ruleutils with pretty-print option

From
Bruce Momjian
Date:
Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > Are these illustrating a problem with the function definition, or is it
> > happening because it is the first time we are calling the same function
> > with one and more than one parameter?
>
> The function definition is broken.  While it could be fixed (by
> explicitly testing fcinfo->nargs, rather than assuming positions
> beyond nargs are valid) I am not willing to remove the opr_sanity
> check that is complaining.  Accordingly, a better solution would be
> to make two C-code wrapper functions, one for the single-parameter
> and one for the two-parameter case of each function.

Tom, how do I pass PG_FUNCTION_ARGS to another function, while adding a
new parameter?  Would it be better to declare SQL functions to call new
functions with a prettyprint parameter of false?

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: ruleutils with pretty-print option

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> Tom, how do I pass PG_FUNCTION_ARGS to another function, while adding a
> new parameter?

I wouldn't.  Do the PG_GETARGS in the wrapper, and have the called
function take a normal C parameter list.

            regards, tom lane

Re: ruleutils with pretty-print option

From
Bruce Momjian
Date:
Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > Tom, how do I pass PG_FUNCTION_ARGS to another function, while adding a
> > new parameter?
>
> I wouldn't.  Do the PG_GETARGS in the wrapper, and have the called
> function take a normal C parameter list.

So I need to wrappers for each function, one that pulls the pretty print
option, and another that doesn't, and they both call a normal C function?

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: ruleutils with pretty-print option

From
Andreas Pflug
Date:
Bruce Momjian wrote:

>Tom Lane wrote:
>
>
>>Bruce Momjian <pgman@candle.pha.pa.us> writes:
>>
>>
>>>Tom, how do I pass PG_FUNCTION_ARGS to another function, while adding a
>>>new parameter?
>>>
>>>
>>I wouldn't.  Do the PG_GETARGS in the wrapper, and have the called
>>function take a normal C parameter list.
>>
>>
>
>So I need to wrappers for each function, one that pulls the pretty print
>option, and another that doesn't, and they both call a normal C function?
>
>
Hi Bruce,

sorry for my late reply, I was out for a day.

I wasn't aware of that regression test checking the arg count of the
functions. I wanted to keep the impact on the source tree as small as
possible, so I implemented that kind of overloaded functions.

I clearly understand that Tom doesn't like to weaken the check, because
in most cases a regression failure really is a coding problem.

I recoded the stuff as Tom recommended, leaving the non-pretty version
function names as they used to be, inventing new pg_get_XXXX_ext
functions for the extended stuff, and pushing the code down into
pg_get_XXXX_worker functions when needed. We now need the additional
prototype include patch from builtins.h.

All-new stuff attached, diff'ed against the current cvs.

Regards,
Andreas



Index: include/catalog/pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
retrieving revision 1.309
diff -c -r1.309 pg_proc.h
*** include/catalog/pg_proc.h    1 Jul 2003 00:04:38 -0000    1.309
--- include/catalog/pg_proc.h    27 Jul 2003 23:40:49 -0000
***************
*** 3405,3410 ****
--- 3405,3424 ----
  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: include/utils/builtins.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/utils/builtins.h,v
retrieving revision 1.223
diff -c -r1.223 builtins.h
*** include/utils/builtins.h    27 Jun 2003 00:33:26 -0000    1.223
--- include/utils/builtins.h    27 Jul 2003 23:41:58 -0000
***************
*** 441,453 ****
--- 441,459 ----

  /* 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);
Index: backend/utils/adt/ruleutils.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.146
diff -c -r1.146 ruleutils.c
*** backend/utils/adt/ruleutils.c    27 Jul 2003 04:53:09 -0000    1.146
--- backend/utils/adt/ruleutils.c    27 Jul 2003 23:42:40 -0000
***************
*** 71,76 ****
--- 71,95 ----
  #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,86 ****
--- 100,107 ----
  {
      StringInfo    buf;            /* output buffer to append to */
      List       *namespaces;        /* List of deparse_namespace nodes */
+         int             prettyFlags;            /* enabling/disabling of pretty-print functions */
+         int             indentLevel;            /* for prettyPrint, current space indents are counted */
      bool        varprefix;        /* TRUE to print prefixes on Vars */
  } deparse_context;

***************
*** 123,135 ****
   * as a parameter, and append their text output to its contents.
   * ----------
   */
! static text *pg_do_getviewdef(Oid viewoid);
  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 void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
!               TupleDesc resultDesc);
  static void get_select_query_def(Query *query, deparse_context *context,
                       TupleDesc resultDesc);
  static void get_insert_query_def(Query *query, deparse_context *context);
--- 144,166 ----
   * as a parameter, and append their text output to its contents.
   * ----------
   */
! static char *get_simple_binary_op_name(OpExpr *expr);
! static void appendStringInfoSpace(StringInfo buf, int count);
! static void appendContextKeyword(deparse_context *context, char *str, int indentBefore, int indentAfter, int
indentPlus);
! static char *deparse_expression_pretty(Node *expr, List *dpcontext,
!               bool forceprefix, bool showimplicit, int prettyFlags, int startIndent);
! static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
! static text *pg_do_getviewdef(Oid viewoid, int prettyFlags);
  static void decompile_column_index_array(Datum column_index_array, Oid relId,
                               StringInfo buf);
! 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, 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);
***************
*** 184,189 ****
--- 215,236 ----
  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);
+     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? 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,247 ****
       * Get the rules definition and put it into executors memory
       */
      initStringInfo(&buf);
!     make_ruledef(&buf, ruletup, rulettc);
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
      VARATT_SIZEP(ruledef) = len;
--- 288,294 ----
       * Get the rules definition and put it into executors memory
       */
      initStringInfo(&buf);
!     make_ruledef(&buf, ruletup, rulettc, prettyFlags);
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
      VARATT_SIZEP(ruledef) = len;
***************
*** 273,279 ****
      Oid            viewoid = PG_GETARG_OID(0);
      text       *ruledef;

!     ruledef = pg_do_getviewdef(viewoid);
      PG_RETURN_TEXT_P(ruledef);
  }

--- 320,339 ----
      Oid            viewoid = PG_GETARG_OID(0);
      text       *ruledef;

!     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);
!     text       *ruledef;
!     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
!
!     ruledef = pg_do_getviewdef(viewoid, prettyFlags);
      PG_RETURN_TEXT_P(ruledef);
  }

***************
*** 290,296 ****
                                                           "get_viewdef"));
      viewoid = RangeVarGetRelid(viewrel, false);

!     ruledef = pg_do_getviewdef(viewoid);
      PG_RETURN_TEXT_P(ruledef);
  }

--- 350,375 ----
                                                           "get_viewdef"));
      viewoid = RangeVarGetRelid(viewrel, false);

!     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);
!     RangeVar   *viewrel;
!     Oid            viewoid;
!     text       *ruledef;
!     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? 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,304 ****
   * Common code for by-OID and by-name variants of pg_get_viewdef
   */
  static text *
! pg_do_getviewdef(Oid viewoid)
  {
      text       *ruledef;
      Datum        args[2];
--- 377,383 ----
   * Common code for by-OID and by-name variants of pg_get_viewdef
   */
  static text *
! pg_do_getviewdef(Oid viewoid, int prettyFlags)
  {
      text       *ruledef;
      Datum        args[2];
***************
*** 353,359 ****
           */
          ruletup = SPI_tuptable->vals[0];
          rulettc = SPI_tuptable->tupdesc;
!         make_viewdef(&buf, ruletup, rulettc);
      }
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
--- 432,438 ----
           */
          ruletup = SPI_tuptable->vals[0];
          rulettc = SPI_tuptable->tupdesc;
!         make_viewdef(&buf, ruletup, rulettc, prettyFlags);
      }
      len = buf.len + VARHDRSZ;
      ruledef = SPI_palloc(len);
***************
*** 527,532 ****
--- 606,626 ----
  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);
+     int        colno = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);
+     int        prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? 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;
***************
*** 582,587 ****
--- 676,683 ----
       * Get the index expressions, if any.  (NOTE: we do not use the relcache
       * versions of the expressions and predicate, because we want to display
       * non-const-folded expressions.)
+          * if colno == 0, we want a complete index definition.
+          * if colno > 0, we only want the nth expression.
       */
      if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
      {
***************
*** 607,613 ****
       * never be schema-qualified, but the indexed rel's name may be.
       */
      initStringInfo(&buf);
!     appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
                       idxrec->indisunique ? "UNIQUE " : "",
                       quote_identifier(NameStr(idxrelrec->relname)),
                       generate_relation_name(indrelid),
--- 703,711 ----
       * never be schema-qualified, but the indexed rel's name may be.
       */
      initStringInfo(&buf);
!
!     if (!colno)
!         appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
                       idxrec->indisunique ? "UNIQUE " : "",
                       quote_identifier(NameStr(idxrelrec->relname)),
                       generate_relation_name(indrelid),
***************
*** 621,627 ****
      {
          AttrNumber    attnum = idxrec->indkey[keyno];

!         appendStringInfo(&buf, sep);
          sep = ", ";

          if (attnum != 0)
--- 719,726 ----
      {
          AttrNumber    attnum = idxrec->indkey[keyno];

!         if (!colno)
!             appendStringInfo(&buf, sep);
          sep = ", ";

          if (attnum != 0)
***************
*** 630,636 ****
              char       *attname;

              attname = get_relid_attribute_name(indrelid, attnum);
!             appendStringInfo(&buf, "%s", quote_identifier(attname));
              keycoltype = get_atttype(indrelid, attnum);
          }
          else
--- 729,736 ----
              char       *attname;

              attname = get_relid_attribute_name(indrelid, attnum);
!             if (!colno || colno == keyno+1)
!                 appendStringInfo(&buf, "%s", quote_identifier(attname));
              keycoltype = get_atttype(indrelid, attnum);
          }
          else
***************
*** 643,672 ****
              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);
              keycoltype = exprType(indexkey);
          }

          /*
           * Add the operator class name
           */
!         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))
      {
          Node       *node;
          Datum        predDatum;
          bool        isnull;
--- 743,778 ----
              indexkey = (Node *) lfirst(indexprs);
              indexprs = lnext(indexprs);
              /* Deparse */
!             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
           */
!         if (!colno)
!             get_opclass_name(idxrec->indclass[keyno], keycoltype,
                           &buf);
      }

!     if (!colno)
      {
+         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;
***************
*** 689,698 ****
          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);
      }
-
      /*
       * Create the result as a TEXT datum, and free working data
       */
--- 795,804 ----
          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);
+         }
      }
      /*
       * Create the result as a TEXT datum, and free working data
       */
***************
*** 721,726 ****
--- 827,847 ----
  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);
+     int      prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? 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,940 ****
                      context = deparse_context_for(get_typname(conForm->contypid),
                                                    InvalidOid);

!                 consrc = deparse_expression(expr, context, false, false);

                  /* Append the constraint source */
                  appendStringInfoString(&buf, consrc);
--- 1055,1061 ----
                      context = deparse_context_for(get_typname(conForm->contypid),
                                                    InvalidOid);

!                 consrc = deparse_expression_pretty(expr, context, false, false, prettyFlags, 0);

                  /* Append the constraint source */
                  appendStringInfoString(&buf, consrc);
***************
*** 1012,1031 ****
  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;
      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? */

      /* Convert input TEXT object to C string */
      exprstr = DatumGetCString(DirectFunctionCall1(textout,
                                                    PointerGetDatum(expr)));
--- 1133,1176 ----
  Datum
  pg_get_expr(PG_FUNCTION_ARGS)
  {
      char       *relname;
!     text    *expr = PG_GETARG_TEXT_P(0);
!     Oid    relid = PG_GETARG_OID(1);
!
!     /* 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)
! {
!     char       *relname;
!     text    *expr = PG_GETARG_TEXT_P(0);
!     Oid    relid = PG_GETARG_OID(1);
!     int     prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? 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,1049 ****

      /* Deparse */
      context = deparse_context_for(relname, relid);
!     str = deparse_expression(node, context, false, false);

      /* Pass the result back as TEXT */
      result = DatumGetTextP(DirectFunctionCall1(textin,
--- 1188,1194 ----

      /* Deparse */
      context = deparse_context_for(relname, relid);
!     str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0);

      /* Pass the result back as TEXT */
      result = DatumGetTextP(DirectFunctionCall1(textin,
***************
*** 1092,1097 ****
--- 1237,1253 ----

  /* ----------
   * 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,1114 ****
   * 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.
   *
   * The result is a palloc'd string.
   * ----------
   */
  char *
! deparse_expression(Node *expr, List *dpcontext,
!                    bool forceprefix, bool showimplicit)
  {
      StringInfoData buf;
      deparse_context context;
--- 1258,1272 ----
   * 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
   *
   * The result is a palloc'd string.
   * ----------
   */
  char *
! deparse_expression_pretty(Node *expr, List *dpcontext,
!                    bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
  {
      StringInfoData buf;
      deparse_context context;
***************
*** 1117,1122 ****
--- 1275,1282 ----
      context.buf = &buf;
      context.namespaces = dpcontext;
      context.varprefix = forceprefix;
+     context.prettyFlags = prettyFlags;
+     context.indentLevel = startIndent;

      get_rule_expr(expr, &context, showimplicit);

***************
*** 1269,1275 ****
   * ----------
   */
  static void
! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
  {
      char       *rulename;
      char        ev_type;
--- 1429,1435 ----
   * ----------
   */
  static void
! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
  {
      char       *rulename;
      char        ev_type;
***************
*** 1323,1331 ****
      /*
       * Build the rules definition text
       */
!     appendStringInfo(buf, "CREATE RULE %s AS ON ",
                       quote_identifier(rulename));

      /* The event the rule is fired for */
      switch (ev_type)
      {
--- 1483,1496 ----
      /*
       * Build the rules definition text
       */
!     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,1375 ****
--- 1535,1542 ----
          deparse_context context;
          deparse_namespace dpns;

+         if (prettyFlags & PRETTYFLAG_INDENT)
+             appendStringInfoString(buf, "\n  ");
          appendStringInfo(buf, " WHERE ");

          qual = stringToNode(ev_qual);
***************
*** 1391,1396 ****
--- 1558,1565 ----
          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,1421 ****
          foreach(action, actions)
          {
              query = (Query *) lfirst(action);
!             get_query_def(query, buf, NIL, NULL);
!             appendStringInfo(buf, "; ");
          }
          appendStringInfo(buf, ");");
      }
--- 1583,1593 ----
          foreach(action, actions)
          {
              query = (Query *) lfirst(action);
!             get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
!             if (prettyFlags)
!                 appendStringInfo(buf, ";\n");
!             else
!                 appendStringInfo(buf, "; ");
          }
          appendStringInfo(buf, ");");
      }
***************
*** 1428,1434 ****
          Query       *query;

          query = (Query *) lfirst(actions);
!         get_query_def(query, buf, NIL, NULL);
          appendStringInfo(buf, ";");
      }
  }
--- 1600,1606 ----
          Query       *query;

          query = (Query *) lfirst(actions);
!         get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
          appendStringInfo(buf, ";");
      }
  }
***************
*** 1440,1446 ****
   * ----------
   */
  static void
! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
  {
      Query       *query;
      char        ev_type;
--- 1612,1618 ----
   * ----------
   */
  static void
! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
  {
      Query       *query;
      char        ev_type;
***************
*** 1494,1500 ****

      ev_relation = heap_open(ev_class, AccessShareLock);

!     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation));
      appendStringInfo(buf, ";");

      heap_close(ev_relation, AccessShareLock);
--- 1666,1672 ----

      ev_relation = heap_open(ev_class, AccessShareLock);

!     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), prettyFlags, 0);
      appendStringInfo(buf, ";");

      heap_close(ev_relation, AccessShareLock);
***************
*** 1510,1516 ****
   */
  static void
  get_query_def(Query *query, StringInfo buf, List *parentnamespace,
!               TupleDesc resultDesc)
  {
      deparse_context context;
      deparse_namespace dpns;
--- 1682,1688 ----
   */
  static void
  get_query_def(Query *query, StringInfo buf, List *parentnamespace,
!               TupleDesc resultDesc, int prettyFlags, int startIndent)
  {
      deparse_context context;
      deparse_namespace dpns;
***************
*** 1519,1524 ****
--- 1691,1699 ----
      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,1596 ****
      /* Add the ORDER BY clause if given */
      if (query->sortClause != NIL)
      {
!         appendStringInfo(buf, " ORDER BY ");
          sep = "";
          foreach(l, query->sortClause)
          {
--- 1765,1771 ----
      /* Add the ORDER BY clause if given */
      if (query->sortClause != NIL)
      {
!             appendContextKeyword(context, " ORDER BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          sep = "";
          foreach(l, query->sortClause)
          {
***************
*** 1619,1630 ****
      /* Add the LIMIT clause if given */
      if (query->limitOffset != NULL)
      {
!         appendStringInfo(buf, " OFFSET ");
          get_rule_expr(query->limitOffset, context, false);
      }
      if (query->limitCount != NULL)
      {
!         appendStringInfo(buf, " LIMIT ");
          if (IsA(query->limitCount, Const) &&
              ((Const *) query->limitCount)->constisnull)
              appendStringInfo(buf, "ALL");
--- 1794,1805 ----
      /* Add the LIMIT clause if given */
      if (query->limitOffset != NULL)
      {
!         appendContextKeyword(context, " OFFSET ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
          get_rule_expr(query->limitOffset, context, false);
      }
      if (query->limitCount != NULL)
      {
!         appendContextKeyword(context, " LIMIT ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
          if (IsA(query->limitCount, Const) &&
              ((Const *) query->limitCount)->constisnull)
              appendStringInfo(buf, "ALL");
***************
*** 1645,1650 ****
--- 1820,1830 ----
      /*
       * 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,1737 ****
      /* Add the WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendStringInfo(buf, " WHERE ");
          get_rule_expr(query->jointree->quals, context, false);
      }

      /* Add the GROUP BY clause if given */
      if (query->groupClause != NULL)
      {
!         appendStringInfo(buf, " GROUP BY ");
          sep = "";
          foreach(l, query->groupClause)
          {
--- 1904,1917 ----
      /* Add the WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         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)
      {
!         appendContextKeyword(context, " GROUP BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          sep = "";
          foreach(l, query->groupClause)
          {
***************
*** 1747,1753 ****
      /* Add the HAVING clause if given */
      if (query->havingQual != NULL)
      {
!         appendStringInfo(buf, " HAVING ");
          get_rule_expr(query->havingQual, context, false);
      }
  }
--- 1927,1933 ----
      /* Add the HAVING clause if given */
      if (query->havingQual != NULL)
      {
!         appendContextKeyword(context, " HAVING ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
          get_rule_expr(query->havingQual, context, false);
      }
  }
***************
*** 1765,1799 ****
          Query       *subquery = rte->subquery;

          Assert(subquery != NULL);
!         get_query_def(subquery, buf, context->namespaces, resultDesc);
      }
      else if (IsA(setOp, SetOperationStmt))
      {
          SetOperationStmt *op = (SetOperationStmt *) setOp;

-         appendStringInfo(buf, "((");
          get_setop_query(op->larg, query, context, resultDesc);
          switch (op->op)
          {
              case SETOP_UNION:
!                 appendStringInfo(buf, ") UNION ");
                  break;
              case SETOP_INTERSECT:
!                 appendStringInfo(buf, ") INTERSECT ");
                  break;
              case SETOP_EXCEPT:
!                 appendStringInfo(buf, ") EXCEPT ");
                  break;
              default:
                  elog(ERROR, "unrecognized set op: %d",
                       (int) op->op);
          }
          if (op->all)
!             appendStringInfo(buf, "ALL (");
          else
!             appendStringInfo(buf, "(");
          get_setop_query(op->rarg, query, context, resultDesc);
!         appendStringInfo(buf, "))");
      }
      else
      {
--- 1945,2008 ----
          Query       *subquery = rte->subquery;

          Assert(subquery != NULL);
!         get_query_def(subquery, buf, context->namespaces, resultDesc, context->prettyFlags, context->indentLevel);
      }
      else if (IsA(setOp, SetOperationStmt))
      {
          SetOperationStmt *op = (SetOperationStmt *) setOp;
+         bool need_paren=(PRETTY_PAREN(context) ? !IsA(op->rarg, RangeTblRef) : true);
+
+         if (!PRETTY_PAREN(context))
+             appendStringInfoString(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:
!                 appendContextKeyword(context, "UNION ", -PRETTYINDENT_STD, 0, 0);
                  break;
              case SETOP_INTERSECT:
!                 appendContextKeyword(context, "INTERSECT ", -PRETTYINDENT_STD, 0, 0);
                  break;
              case SETOP_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 ");
!
!         if (PRETTY_INDENT(context))
!             appendStringInfoChar(buf, '\n');
!
!         if (PRETTY_PAREN(context))
!         {
!             if (need_paren)
!             {
!             appendStringInfoChar(buf, '(');
!             if (PRETTY_INDENT(context))
!                 appendStringInfoChar(buf, '\n');
!             }
!         }
          else
!             appendStringInfoChar(buf, '(');
!
          get_setop_query(op->rarg, query, context, resultDesc);
!
!         if (PRETTY_PAREN(context))
!         {
!             if (need_paren)
!             appendStringInfoChar(buf, ')');
!         }
!         else
!             appendStringInfoString(buf, "))");
      }
      else
      {
***************
*** 1866,1871 ****
--- 2075,2086 ----
       */
      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,1893 ****
      /* Add the VALUES or the SELECT */
      if (select_rte == NULL)
      {
!         appendStringInfo(buf, "VALUES (");
          sep = "";
          foreach(l, query->targetList)
          {
--- 2102,2108 ----
      /* Add the VALUES or the SELECT */
      if (select_rte == NULL)
      {
!         appendContextKeyword(context, "VALUES (", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
          sep = "";
          foreach(l, query->targetList)
          {
***************
*** 1903,1909 ****
          appendStringInfoChar(buf, ')');
      }
      else
!         get_query_def(select_rte->subquery, buf, NIL, NULL);
  }


--- 2118,2124 ----
          appendStringInfoChar(buf, ')');
      }
      else
!         get_query_def(select_rte->subquery, buf, NIL, NULL, context->prettyFlags, context->indentLevel);
  }


***************
*** 1924,1929 ****
--- 2139,2149 ----
       */
      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,1963 ****
      /* Finally add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendStringInfo(buf, " WHERE ");
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
--- 2177,2183 ----
      /* Finally add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
***************
*** 1978,1983 ****
--- 2198,2208 ----
       */
      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,1991 ****
      /* Add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendStringInfo(buf, " WHERE ");
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
--- 2210,2216 ----
      /* Add a WHERE clause if given */
      if (query->jointree->quals != NULL)
      {
!         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
          get_rule_expr(query->jointree->quals, context, false);
      }
  }
***************
*** 2004,2009 ****
--- 2229,2235 ----
      {
          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,2150 ****
--- 2371,2612 ----
  }


+ /********************************************
+  * get_simple_binary_op_name
+  * helper function for isSimpleNode
+  * will return single char binary operator
+  *******************************************/
+
+ static 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);
+         char *op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
+
+         if (strlen(op) == 1)
+             return op;
+     }
+     return 0;
+ }
+
+
+ /***************************************
+  * check if given node is simple.
+  *  false  : not simple
+  *  true   : simple in the context of parent node's type
+  ***************************************/
+
+ static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
+ {
+     if (!node)
+     return true;
+
+     switch (nodeTag(node))
+     {
+     // single words: always simple
+     case T_Var:
+     case T_Const:
+     case T_Param:
+
+     // function-like: name(..) or name[..]
+     case T_ArrayRef:
+     case T_ArrayExpr:
+     case T_CoalesceExpr:
+     case T_NullIfExpr:
+     case T_Aggref:
+     case T_FuncExpr:
+
+         // CASE keywords act as parentheses
+     case T_CaseExpr:
+         return true;
+
+         // appears simple since . has top precedence, unless parent is T_FieldSelect itself!
+     case T_FieldSelect:
+         return (nodeTag(parentNode) == T_FieldSelect ? false : true);
+
+
+         // maybe simple, check args
+     case T_CoerceToDomain:
+         return isSimpleNode((Node*) ((CoerceToDomain*)node)->arg, node, prettyFlags);
+     case T_RelabelType:
+         return isSimpleNode((Node*) ((RelabelType*)node)->arg, node, prettyFlags);
+
+
+     // depends on parent node type; needs further checking
+     case T_OpExpr:
+     {
+         if (prettyFlags & PRETTYFLAG_PAREN && nodeTag(parentNode) == T_OpExpr)
+         {
+         char *op=get_simple_binary_op_name((OpExpr*)node);
+         char *parentOp=get_simple_binary_op_name((OpExpr*)parentNode);
+         if (!op || !parentOp)
+             return false;
+
+                 // we know only these basic operators
+         if (!strchr("+-*/%", *op) || !strchr("+-*/%", *parentOp))
+             return false;
+
+         // natural operator precedence, so we don't need parentheses
+         if (strchr("*/%", *op) || strchr("+-", *parentOp))
+             return true;
+
+         return false;
+         }
+             // else do the same stuff as for T_SubLink et al.
+     }
+     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=((BoolExpr*)node)->boolop;
+             BoolExprType 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;
+         }
+         // these are not completely implemented; so far, they're simple
+     case T_SubPlan:
+     case T_CoerceToDomainValue:
+         return true;
+
+     case T_ScalarArrayOpExpr:
+         // need to check
+     default:
+         break;
+     }
+     // those we don't know: in dubio complexo
+     return false;
+ }
+
+
+ /******************************************
+  * appendContextKeyword
+  * append spaces to buffer
+  ******************************************/
+ static void appendStringInfoSpace(StringInfo buf, int count)
+ {
+     while (count-- > 0)
+     appendStringInfoChar(buf, ' ');
+ }
+
+ /******************************************
+  * appendContextKeyword
+  * performing a line break, and indentation
+  * if prettyPrint is enabled.
+  * Otherwise, only the keyword is appended
+  *****************************************/
+
+ static void appendContextKeyword(deparse_context *context, 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');
+     appendStringInfoSpace(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  - parsing expr using get_rule_expr,
+  * embracing the string with parentheses if necessary for prettyPrint.
+  * never embracing 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 = 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
   *
***************
*** 2299,2310 ****
                  List       *args = expr->args;
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);
!
!                 appendStringInfoChar(buf, '(');
!                 get_rule_expr(arg1, context, true);
                  appendStringInfo(buf, " IS DISTINCT FROM ");
!                 get_rule_expr(arg2, context, true);
!                 appendStringInfoChar(buf, ')');
              }
              break;

--- 2761,2773 ----
                  List       *args = expr->args;
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, '(');
!                 get_rule_expr_paren(arg1, context, true, node);
                  appendStringInfo(buf, " IS DISTINCT FROM ");
!                 get_rule_expr_paren(arg2, context, true, node);
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, ')');
              }
              break;

***************
*** 2315,2329 ****
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);

!                 appendStringInfoChar(buf, '(');
!                 get_rule_expr(arg1, context, true);
                  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, "))");
              }
              break;

--- 2778,2796 ----
                  Node       *arg1 = (Node *) lfirst(args);
                  Node       *arg2 = (Node *) lsecond(args);

!                 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_paren(arg2, context, true, node);
!                 appendStringInfoString(buf, ")");
!
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, ')');
              }
              break;

***************
*** 2335,2367 ****
                  switch (expr->boolop)
                  {
                      case AND_EXPR:
!                         appendStringInfoChar(buf, '(');
!                         get_rule_expr((Node *) lfirst(args), context, false);
                          while ((args = lnext(args)) != NIL)
                          {
                              appendStringInfo(buf, " AND ");
!                             get_rule_expr((Node *) lfirst(args), context,
!                                           false);
                          }
!                         appendStringInfoChar(buf, ')');
                          break;

                      case OR_EXPR:
!                         appendStringInfoChar(buf, '(');
!                         get_rule_expr((Node *) lfirst(args), context, false);
                          while ((args = lnext(args)) != NIL)
                          {
                              appendStringInfo(buf, " OR ");
!                             get_rule_expr((Node *) lfirst(args), context,
!                                           false);
                          }
!                         appendStringInfoChar(buf, ')');
                          break;

                      case NOT_EXPR:
!                         appendStringInfo(buf, "(NOT ");
!                         get_rule_expr((Node *) lfirst(args), context, false);
!                         appendStringInfoChar(buf, ')');
                          break;

                      default:
--- 2802,2841 ----
                  switch (expr->boolop)
                  {
                      case AND_EXPR:
!                             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_paren((Node *) lfirst(args), context,
!                                           false, node);
                          }
!                             if (!PRETTY_PAREN(context))
!                             appendStringInfoChar(buf, ')');
                          break;

                      case OR_EXPR:
!                             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_paren((Node *) lfirst(args), context,
!                                           false, node);
                          }
!                             if (!PRETTY_PAREN(context))
!                             appendStringInfoChar(buf, ')');
                          break;

                      case NOT_EXPR:
!                             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,2417 ****
                   * 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));
              }
              break;

--- 2883,2894 ----
                   * arg.fieldname, but most cases where FieldSelect is used
                   * are *not* simple.  So, always use parenthesized syntax.
                   */
!                     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,2430 ****
                      !showimplicit)
                  {
                      /* don't show the implicit cast */
!                     get_rule_expr(arg, context, showimplicit);
                  }
                  else
                  {
--- 2901,2907 ----
                      !showimplicit)
                  {
                      /* don't show the implicit cast */
!                     get_rule_expr_paren(arg, context, showimplicit, node);
                  }
                  else
                  {
***************
*** 2436,2444 ****
                       */
                      arg = strip_type_coercion(arg, relabel->resulttype);

!                     appendStringInfoChar(buf, '(');
!                     get_rule_expr(arg, context, showimplicit);
!                     appendStringInfo(buf, ")::%s",
                              format_type_with_typemod(relabel->resulttype,
                                                       relabel->resulttypmod));
                  }
--- 2913,2925 ----
                       */
                      arg = strip_type_coercion(arg, relabel->resulttype);

!                     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,2468 ****
                  CaseExpr   *caseexpr = (CaseExpr *) node;
                  List       *temp;

!                 appendStringInfo(buf, "CASE");
                  foreach(temp, caseexpr->args)
                  {
                      CaseWhen   *when = (CaseWhen *) lfirst(temp);

!                     appendStringInfo(buf, " WHEN ");
                      get_rule_expr((Node *) when->expr, context, false);
                      appendStringInfo(buf, " THEN ");
                      get_rule_expr((Node *) when->result, context, true);
                  }
!                 appendStringInfo(buf, " ELSE ");
                  get_rule_expr((Node *) caseexpr->defresult, context, true);
!                 appendStringInfo(buf, " END");
              }
              break;

--- 2931,2957 ----
                  CaseExpr   *caseexpr = (CaseExpr *) node;
                  List       *temp;

!                 appendContextKeyword(context, "CASE", 0, PRETTYINDENT_VAR, 0);
                  foreach(temp, caseexpr->args)
                  {
                      CaseWhen   *when = (CaseWhen *) lfirst(temp);

!                     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);
                  }
!                 if (!PRETTY_INDENT(context))
!                     appendStringInfoChar(buf, ' ');
!                 appendContextKeyword(context, "ELSE ", 0, 0, 0);
                  get_rule_expr((Node *) caseexpr->defresult, context, true);
!                 if (!PRETTY_INDENT(context))
!                     appendStringInfoChar(buf, ' ');
!                 appendContextKeyword(context, "END", -PRETTYINDENT_VAR, 0, 0);
              }
              break;

***************
*** 2530,2549 ****
              {
                  NullTest   *ntest = (NullTest *) node;

!                 appendStringInfo(buf, "(");
!                 get_rule_expr((Node *) ntest->arg, context, true);
                  switch (ntest->nulltesttype)
                  {
                      case IS_NULL:
!                         appendStringInfo(buf, " IS NULL)");
                          break;
                      case IS_NOT_NULL:
!                         appendStringInfo(buf, " IS NOT NULL)");
                          break;
                      default:
                          elog(ERROR, "unrecognized nulltesttype: %d",
                               (int) ntest->nulltesttype);
                  }
              }
              break;

--- 3019,3041 ----
              {
                  NullTest   *ntest = (NullTest *) node;

!                 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");
                          break;
                      case 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,2582 ****
              {
                  BooleanTest *btest = (BooleanTest *) node;

!                 appendStringInfo(buf, "(");
!                 get_rule_expr((Node *) btest->arg, context, false);
                  switch (btest->booltesttype)
                  {
                      case IS_TRUE:
!                         appendStringInfo(buf, " IS TRUE)");
                          break;
                      case IS_NOT_TRUE:
!                         appendStringInfo(buf, " IS NOT TRUE)");
                          break;
                      case IS_FALSE:
!                         appendStringInfo(buf, " IS FALSE)");
                          break;
                      case IS_NOT_FALSE:
!                         appendStringInfo(buf, " IS NOT FALSE)");
                          break;
                      case IS_UNKNOWN:
!                         appendStringInfo(buf, " IS UNKNOWN)");
                          break;
                      case IS_NOT_UNKNOWN:
!                         appendStringInfo(buf, " IS NOT UNKNOWN)");
                          break;
                      default:
                          elog(ERROR, "unrecognized booltesttype: %d",
                               (int) btest->booltesttype);
                  }
              }
              break;

--- 3043,3077 ----
              {
                  BooleanTest *btest = (BooleanTest *) node;

!                 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");
                          break;
                      case IS_NOT_TRUE:
!                         appendStringInfo(buf, " IS NOT TRUE");
                          break;
                      case IS_FALSE:
!                         appendStringInfo(buf, " IS FALSE");
                          break;
                      case IS_NOT_FALSE:
!                         appendStringInfo(buf, " IS NOT FALSE");
                          break;
                      case IS_UNKNOWN:
!                         appendStringInfo(buf, " IS UNKNOWN");
                          break;
                      case 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,2606 ****
                  }
                  else
                  {
!                     appendStringInfoChar(buf, '(');
!                     get_rule_expr(arg, context, false);
!                     appendStringInfo(buf, ")::%s",
                              format_type_with_typemod(ctest->resulttype,
                                                       ctest->resulttypmod));
                  }
--- 3093,3106 ----
                  }
                  else
                  {
!                     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,2650 ****
      Oid            opno = expr->opno;
      List       *args = expr->args;

!     appendStringInfoChar(buf, '(');
      if (length(args) == 2)
      {
          /* binary operator */
          Node       *arg1 = (Node *) lfirst(args);
          Node       *arg2 = (Node *) lsecond(args);
!
!         get_rule_expr(arg1, context, true);
          appendStringInfo(buf, " %s ",
                           generate_operator_name(opno,
                                                  exprType(arg1),
                                                  exprType(arg2)));
!         get_rule_expr(arg2, context, true);
      }
      else
      {
--- 3132,3150 ----
      Oid            opno = expr->opno;
      List       *args = expr->args;

!     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_paren(arg1, context, true, (Node*)expr);
          appendStringInfo(buf, " %s ",
                           generate_operator_name(opno,
                                                  exprType(arg1),
                                                  exprType(arg2)));
!         get_rule_expr_paren(arg2, context, true, (Node*)expr);
      }
      else
      {
***************
*** 2666,2675 ****
                                   generate_operator_name(opno,
                                                          InvalidOid,
                                                          exprType(arg)));
!                 get_rule_expr(arg, context, true);
                  break;
              case 'r':
!                 get_rule_expr(arg, context, true);
                  appendStringInfo(buf, " %s",
                                   generate_operator_name(opno,
                                                          exprType(arg),
--- 3166,3175 ----
                                   generate_operator_name(opno,
                                                          InvalidOid,
                                                          exprType(arg)));
!                 get_rule_expr_paren(arg, context, true, (Node*)expr);
                  break;
              case 'r':
!                 get_rule_expr_paren(arg, context, true, (Node*)expr);
                  appendStringInfo(buf, " %s",
                                   generate_operator_name(opno,
                                                          exprType(arg),
***************
*** 2680,2686 ****
          }
          ReleaseSysCache(tp);
      }
!     appendStringInfoChar(buf, ')');
  }

  /*
--- 3180,3187 ----
          }
          ReleaseSysCache(tp);
      }
!     if (!PRETTY_PAREN(context))
!         appendStringInfoChar(buf, ')');
  }

  /*
***************
*** 2703,2709 ****
       */
      if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
      {
!         get_rule_expr((Node *) lfirst(expr->args), context, showimplicit);
          return;
      }

--- 3204,3210 ----
       */
      if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
      {
!         get_rule_expr_paren((Node *) lfirst(expr->args), context, showimplicit, (Node*)expr);
          return;
      }

***************
*** 2729,2737 ****
           */
          arg = strip_type_coercion(arg, rettype);

!         appendStringInfoChar(buf, '(');
!         get_rule_expr(arg, context, showimplicit);
!         appendStringInfo(buf, ")::%s",
                           format_type_with_typemod(rettype, coercedTypmod));

          return;
--- 3230,3243 ----
           */
          arg = strip_type_coercion(arg, rettype);

!         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,3058 ****
      if (need_paren)
          appendStringInfoChar(buf, '(');

!     get_query_def(query, buf, context->namespaces, NULL);

      if (need_paren)
          appendStringInfo(buf, "))");
--- 3558,3564 ----
      if (need_paren)
          appendStringInfoChar(buf, '(');

!     get_query_def(query, buf, context->namespaces, NULL, context->prettyFlags, context->indentLevel);

      if (need_paren)
          appendStringInfo(buf, "))");
***************
*** 3069,3075 ****
  get_from_clause(Query *query, deparse_context *context)
  {
      StringInfo    buf = context->buf;
!     char       *sep;
      List       *l;

      /*
--- 3575,3581 ----
  get_from_clause(Query *query, deparse_context *context)
  {
      StringInfo    buf = context->buf;
!     char       *sep=0;
      List       *l;

      /*
***************
*** 3079,3085 ****
       * sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW
       * and OLD.
       */
-     sep = " FROM ";

      foreach(l, query->jointree->fromlist)
      {
--- 3585,3590 ----
***************
*** 3098,3104 ****
                  continue;
          }

!         appendStringInfo(buf, sep);
          get_from_clause_item(jtnode, query, context);
          sep = ", ";
      }
--- 3603,3613 ----
                  continue;
          }

!         if (!sep)
!             appendContextKeyword(context, " FROM ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
!         else
!             appendStringInfo(buf, sep);
!
          get_from_clause_item(jtnode, query, context);
          sep = ", ";
      }
***************
*** 3127,3133 ****
              case RTE_SUBQUERY:
                  /* Subquery RTE */
                  appendStringInfoChar(buf, '(');
!                 get_query_def(rte->subquery, buf, context->namespaces, NULL);
                  appendStringInfoChar(buf, ')');
                  break;
              case RTE_FUNCTION:
--- 3636,3643 ----
              case RTE_SUBQUERY:
                  /* Subquery RTE */
                  appendStringInfoChar(buf, '(');
!                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
!                           context->prettyFlags, context->indentLevel);
                  appendStringInfoChar(buf, ')');
                  break;
              case RTE_FUNCTION:
***************
*** 3149,3155 ****
              {
                  List       *col;

!                 appendStringInfo(buf, "(");
                  foreach(col, rte->alias->colnames)
                  {
                      if (col != rte->alias->colnames)
--- 3659,3665 ----
              {
                  List       *col;

!                 appendStringInfoChar(buf, '(');
                  foreach(col, rte->alias->colnames)
                  {
                      if (col != rte->alias->colnames)
***************
*** 3183,3218 ****
      else if (IsA(jtnode, JoinExpr))
      {
          JoinExpr   *j = (JoinExpr *) jtnode;

-         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);
          }
          get_from_clause_item(j->rarg, query, context);
          if (!j->isNatural)
          {
              if (j->using)
--- 3693,3770 ----
      else if (IsA(jtnode, JoinExpr))
      {
          JoinExpr   *j = (JoinExpr *) jtnode;
+         bool need_paren_on_right = PRETTY_PAREN(context) && !IsA(j->rarg, RangeTblRef);
+
+         if (!PRETTY_PAREN(context) || j->alias != NULL)
+             appendStringInfoChar(buf, '(');

          get_from_clause_item(j->larg, query, context);
+
          if (j->isNatural)
          {
+             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, "get_from_clause_item: unknown 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)
***************
*** 3231,3242 ****
              }
              else if (j->quals)
              {
!                 appendStringInfo(buf, " ON (");
                  get_rule_expr(j->quals, context, false);
!                 appendStringInfoChar(buf, ')');
              }
          }
!         appendStringInfoChar(buf, ')');
          /* Yes, it's correct to put alias after the right paren ... */
          if (j->alias != NULL)
          {
--- 3783,3799 ----
              }
              else if (j->quals)
              {
!                 appendStringInfo(buf, " ON ");
!                 if (!PRETTY_PAREN(context))
!                     appendStringInfoChar(buf, '(');
                  get_rule_expr(j->quals, context, false);
!                 if (!PRETTY_PAREN(context))
!                     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,3252 ****
              {
                  List       *col;

!                 appendStringInfo(buf, "(");
                  foreach(col, j->alias->colnames)
                  {
                      if (col != j->alias->colnames)
--- 3803,3809 ----
              {
                  List       *col;

!                 appendStringInfoChar(buf, '(');
                  foreach(col, j->alias->colnames)
                  {
                      if (col != j->alias->colnames)

Re: ruleutils with pretty-print option

From
Tom Lane
Date:
Andreas Pflug <pgadmin@pse-consulting.de> writes:
> +     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;

Since the pg_proc entries are all marked strict, it's unnecessary for
you to write any ARGISNULL checks.

            regards, tom lane

Re: ruleutils with pretty-print option

From
Andreas Pflug
Date:
Tom Lane wrote:

>Andreas Pflug <pgadmin@pse-consulting.de> writes:
>
>
>>+     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
>>
>>
>
>Since the pg_proc entries are all marked strict, it's unnecessary for
>you to write any ARGISNULL checks.
>

Yeah you're right, it's a remainder of the previous solution. it was
late at night... But it won't do any harm either.

Regards,
Andreas


Re: ruleutils with pretty-print option

From
Tom Lane
Date:
Andreas Pflug <pgadmin@pse-consulting.de> writes:
> I recoded the stuff as Tom recommended, leaving the non-pretty version
> function names as they used to be, inventing new pg_get_XXXX_ext
> functions for the extended stuff, and pushing the code down into
> pg_get_XXXX_worker functions when needed. We now need the additional
> prototype include patch from builtins.h.

Applied with some editorializing.  In particular, I don't believe the
original did the right thing with (a - (b - c)).

            regards, tom lane

Re: ruleutils with pretty-print option

From
Bruce Momjian
Date:
I didn't like the functions ending in _ext.  I renamed them to _pp for
pretty print.  Patch attached and applied.

---------------------------------------------------------------------------

Tom Lane wrote:
> Andreas Pflug <pgadmin@pse-consulting.de> writes:
> > I recoded the stuff as Tom recommended, leaving the non-pretty version
> > function names as they used to be, inventing new pg_get_XXXX_ext
> > functions for the extended stuff, and pushing the code down into
> > pg_get_XXXX_worker functions when needed. We now need the additional
> > prototype include patch from builtins.h.
>
> Applied with some editorializing.  In particular, I don't believe the
> original did the right thing with (a - (b - c)).
>
>             regards, tom lane
>
> ---------------------------(end of broadcast)---------------------------
> TIP 4: Don't 'kill -9' the postmaster
>

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: src/backend/utils/adt/ruleutils.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.147
diff -c -c -r1.147 ruleutils.c
*** src/backend/utils/adt/ruleutils.c    30 Jul 2003 22:56:23 -0000    1.147
--- src/backend/utils/adt/ruleutils.c    31 Jul 2003 04:48:35 -0000
***************
*** 228,234 ****


  Datum
! pg_get_ruledef_ext(PG_FUNCTION_ARGS)
  {
      Oid            ruleoid = PG_GETARG_OID(0);
      bool        pretty = PG_GETARG_BOOL(1);
--- 228,234 ----


  Datum
! pg_get_ruledef_pp(PG_FUNCTION_ARGS)
  {
      Oid            ruleoid = PG_GETARG_OID(0);
      bool        pretty = PG_GETARG_BOOL(1);
***************
*** 337,343 ****


  Datum
! pg_get_viewdef_ext(PG_FUNCTION_ARGS)
  {
      /* By OID */
      Oid            viewoid = PG_GETARG_OID(0);
--- 337,343 ----


  Datum
! pg_get_viewdef_pp(PG_FUNCTION_ARGS)
  {
      /* By OID */
      Oid            viewoid = PG_GETARG_OID(0);
***************
*** 369,375 ****


  Datum
! pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
  {
      /* By qualified name */
      text       *viewname = PG_GETARG_TEXT_P(0);
--- 369,375 ----


  Datum
! pg_get_viewdef_name_pp(PG_FUNCTION_ARGS)
  {
      /* By qualified name */
      text       *viewname = PG_GETARG_TEXT_P(0);
***************
*** 630,636 ****
  }

  Datum
! pg_get_indexdef_ext(PG_FUNCTION_ARGS)
  {
      Oid            indexrelid = PG_GETARG_OID(0);
      int32       colno = PG_GETARG_INT32(1);
--- 630,636 ----
  }

  Datum
! pg_get_indexdef_pp(PG_FUNCTION_ARGS)
  {
      Oid            indexrelid = PG_GETARG_OID(0);
      int32       colno = PG_GETARG_INT32(1);
***************
*** 856,862 ****
  }

  Datum
! pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
  {
      Oid            constraintId = PG_GETARG_OID(0);
      bool        pretty = PG_GETARG_BOOL(1);
--- 856,862 ----
  }

  Datum
! pg_get_constraintdef_pp(PG_FUNCTION_ARGS)
  {
      Oid            constraintId = PG_GETARG_OID(0);
      bool        pretty = PG_GETARG_BOOL(1);
***************
*** 1175,1181 ****
  }

  Datum
! pg_get_expr_ext(PG_FUNCTION_ARGS)
  {
      text    *expr = PG_GETARG_TEXT_P(0);
      Oid    relid = PG_GETARG_OID(1);
--- 1175,1181 ----
  }

  Datum
! pg_get_expr_pp(PG_FUNCTION_ARGS)
  {
      text    *expr = PG_GETARG_TEXT_P(0);
      Oid    relid = PG_GETARG_OID(1);
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
retrieving revision 1.310
diff -c -c -r1.310 pg_proc.h
*** src/include/catalog/pg_proc.h    30 Jul 2003 22:56:24 -0000    1.310
--- src/include/catalog/pg_proc.h    31 Jul 2003 04:48:40 -0000
***************
*** 3406,3422 ****
  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");


--- 3406,3422 ----
  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_pp - _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_pp - _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_pp - _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_pp - _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_pp -
_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_pp - _null_
));
  DESCR("deparse an encoded expression with pretty-print option");


Index: src/include/utils/builtins.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/utils/builtins.h,v
retrieving revision 1.224
diff -c -c -r1.224 builtins.h
*** src/include/utils/builtins.h    30 Jul 2003 22:56:24 -0000    1.224
--- src/include/utils/builtins.h    31 Jul 2003 04:48:41 -0000
***************
*** 441,459 ****

  /* 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);
--- 441,459 ----

  /* ruleutils.c */
  extern Datum pg_get_ruledef(PG_FUNCTION_ARGS);
! extern Datum pg_get_ruledef_pp(PG_FUNCTION_ARGS);
  extern Datum pg_get_viewdef(PG_FUNCTION_ARGS);
! extern Datum pg_get_viewdef_pp(PG_FUNCTION_ARGS);
  extern Datum pg_get_viewdef_name(PG_FUNCTION_ARGS);
! extern Datum pg_get_viewdef_name_pp(PG_FUNCTION_ARGS);
  extern Datum pg_get_indexdef(PG_FUNCTION_ARGS);
! extern Datum pg_get_indexdef_pp(PG_FUNCTION_ARGS);
  extern Datum pg_get_triggerdef(PG_FUNCTION_ARGS);
  extern Datum pg_get_constraintdef(PG_FUNCTION_ARGS);
! extern Datum pg_get_constraintdef_pp(PG_FUNCTION_ARGS);
  extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
  extern Datum pg_get_expr(PG_FUNCTION_ARGS);
! extern Datum pg_get_expr_pp(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);

Re: ruleutils with pretty-print option

From
Bruce Momjian
Date:
Patch applied, modified by Tom and myself.

---------------------------------------------------------------------------

Andreas Pflug wrote:
> Bruce Momjian wrote:
>
> >Andreas, looks good, but I need a diff -c, context diff.
> >
> >
> >
> Hi Bruce,
> I intentionally only attached only non-context diffs because the patch
> is about 50 % size of the original file. Now, here's the same as context
> diff.
>
> Regards,
> Andreas

> Index: pg_proc.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
> retrieving revision 1.309
> diff -c -r1.309 pg_proc.h
> *** pg_proc.h    1 Jul 2003 00:04:38 -0000    1.309
> --- pg_proc.h    22 Jul 2003 12:52:07 -0000
> ***************
> *** 3405,3410 ****
> --- 3405,3424 ----
>   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 - _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 - _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 - _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 - _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 - _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 - _null_
));
> + DESCR("deparse an encoded expression with pretty-print option");
> +
>
>   /*
>    * Symbolic values for provolatile column: these indicate whether the result

> Index: ruleutils.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
> retrieving revision 1.145
> diff -c -r1.145 ruleutils.c
> *** ruleutils.c    4 Jul 2003 02:51:34 -0000    1.145
> --- ruleutils.c    22 Jul 2003 12:54:10 -0000
> ***************
> *** 71,76 ****
> --- 71,95 ----
>   #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,86 ****
> --- 100,107 ----
>   {
>       StringInfo    buf;            /* output buffer to append to */
>       List       *namespaces;        /* List of deparse_namespace nodes */
> +         int             prettyFlags;            /* enabling/disabling of pretty-print functions */
> +         int             indentLevel;            /* for prettyPrint, current space indents are counted */
>       bool        varprefix;        /* TRUE to print prefixes on Vars */
>   } deparse_context;
>
> ***************
> *** 123,135 ****
>    * as a parameter, and append their text output to its contents.
>    * ----------
>    */
> ! static text *pg_do_getviewdef(Oid viewoid);
>   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 void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
> !               TupleDesc resultDesc);
>   static void get_select_query_def(Query *query, deparse_context *context,
>                        TupleDesc resultDesc);
>   static void get_insert_query_def(Query *query, deparse_context *context);
> --- 144,162 ----
>    * as a parameter, and append their text output to its contents.
>    * ----------
>    */
> ! static char *get_simple_binary_op_name(OpExpr *expr);
> ! static void appendStringInfoSpace(StringInfo buf, int count);
> ! static void appendContextKeyword(deparse_context *context, char *str, int indentBefore, int indentAfter, int
indentPlus);
> ! static char *deparse_expression_pretty(Node *expr, List *dpcontext,
> !               bool forceprefix, bool showimplicit, int prettyFlags, int startIndent);
> ! static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
> ! 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, 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, 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);
> ***************
> *** 192,197 ****
> --- 219,225 ----
>       TupleDesc    rulettc;
>       StringInfoData buf;
>       int            len;
> +     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
>
>       /*
>        * Connect to SPI manager
> ***************
> *** 241,247 ****
>        * Get the rules definition and put it into executors memory
>        */
>       initStringInfo(&buf);
> !     make_ruledef(&buf, ruletup, rulettc);
>       len = buf.len + VARHDRSZ;
>       ruledef = SPI_palloc(len);
>       VARATT_SIZEP(ruledef) = len;
> --- 269,275 ----
>        * Get the rules definition and put it into executors memory
>        */
>       initStringInfo(&buf);
> !     make_ruledef(&buf, ruletup, rulettc, prettyFlags);
>       len = buf.len + VARHDRSZ;
>       ruledef = SPI_palloc(len);
>       VARATT_SIZEP(ruledef) = len;
> ***************
> *** 272,279 ****
>       /* By OID */
>       Oid            viewoid = PG_GETARG_OID(0);
>       text       *ruledef;
>
> !     ruledef = pg_do_getviewdef(viewoid);
>       PG_RETURN_TEXT_P(ruledef);
>   }
>
> --- 300,308 ----
>       /* By OID */
>       Oid            viewoid = PG_GETARG_OID(0);
>       text       *ruledef;
> +     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
>
> !     ruledef = pg_do_getviewdef(viewoid, prettyFlags);
>       PG_RETURN_TEXT_P(ruledef);
>   }
>
> ***************
> *** 285,296 ****
>       RangeVar   *viewrel;
>       Oid            viewoid;
>       text       *ruledef;
>
>       viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname,
>                                                            "get_viewdef"));
>       viewoid = RangeVarGetRelid(viewrel, false);
>
> !     ruledef = pg_do_getviewdef(viewoid);
>       PG_RETURN_TEXT_P(ruledef);
>   }
>
> --- 314,326 ----
>       RangeVar   *viewrel;
>       Oid            viewoid;
>       text       *ruledef;
> +     int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? 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,304 ****
>    * Common code for by-OID and by-name variants of pg_get_viewdef
>    */
>   static text *
> ! pg_do_getviewdef(Oid viewoid)
>   {
>       text       *ruledef;
>       Datum        args[2];
> --- 328,334 ----
>    * Common code for by-OID and by-name variants of pg_get_viewdef
>    */
>   static text *
> ! pg_do_getviewdef(Oid viewoid, int prettyFlags)
>   {
>       text       *ruledef;
>       Datum        args[2];
> ***************
> *** 353,359 ****
>            */
>           ruletup = SPI_tuptable->vals[0];
>           rulettc = SPI_tuptable->tupdesc;
> !         make_viewdef(&buf, ruletup, rulettc);
>       }
>       len = buf.len + VARHDRSZ;
>       ruledef = SPI_palloc(len);
> --- 383,389 ----
>            */
>           ruletup = SPI_tuptable->vals[0];
>           rulettc = SPI_tuptable->tupdesc;
> !         make_viewdef(&buf, ruletup, rulettc, prettyFlags);
>       }
>       len = buf.len + VARHDRSZ;
>       ruledef = SPI_palloc(len);
> ***************
> *** 544,549 ****
> --- 574,581 ----
>       StringInfoData buf;
>       char       *str;
>       char       *sep;
> +     int        colno = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);
> +     int        prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
>
>       /*
>        * Fetch the pg_index tuple by the Oid of the index
> ***************
> *** 582,587 ****
> --- 614,621 ----
>        * Get the index expressions, if any.  (NOTE: we do not use the relcache
>        * versions of the expressions and predicate, because we want to display
>        * non-const-folded expressions.)
> +          * if colno == 0, we want a complete index definition.
> +          * if colno > 0, we only want the nth expression.
>        */
>       if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
>       {
> ***************
> *** 607,613 ****
>        * never be schema-qualified, but the indexed rel's name may be.
>        */
>       initStringInfo(&buf);
> !     appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
>                        idxrec->indisunique ? "UNIQUE " : "",
>                        quote_identifier(NameStr(idxrelrec->relname)),
>                        generate_relation_name(indrelid),
> --- 641,649 ----
>        * never be schema-qualified, but the indexed rel's name may be.
>        */
>       initStringInfo(&buf);
> !
> !     if (!colno)
> !         appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
>                        idxrec->indisunique ? "UNIQUE " : "",
>                        quote_identifier(NameStr(idxrelrec->relname)),
>                        generate_relation_name(indrelid),
> ***************
> *** 621,627 ****
>       {
>           AttrNumber    attnum = idxrec->indkey[keyno];
>
> !         appendStringInfo(&buf, sep);
>           sep = ", ";
>
>           if (attnum != 0)
> --- 657,664 ----
>       {
>           AttrNumber    attnum = idxrec->indkey[keyno];
>
> !         if (!colno)
> !             appendStringInfo(&buf, sep);
>           sep = ", ";
>
>           if (attnum != 0)
> ***************
> *** 630,636 ****
>               char       *attname;
>
>               attname = get_relid_attribute_name(indrelid, attnum);
> !             appendStringInfo(&buf, "%s", quote_identifier(attname));
>               keycoltype = get_atttype(indrelid, attnum);
>           }
>           else
> --- 667,674 ----
>               char       *attname;
>
>               attname = get_relid_attribute_name(indrelid, attnum);
> !             if (!colno || colno == keyno+1)
> !                 appendStringInfo(&buf, "%s", quote_identifier(attname));
>               keycoltype = get_atttype(indrelid, attnum);
>           }
>           else
> ***************
> *** 643,672 ****
>               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);
>               keycoltype = exprType(indexkey);
>           }
>
>           /*
>            * Add the operator class name
>            */
> !         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))
>       {
>           Node       *node;
>           Datum        predDatum;
>           bool        isnull;
> --- 681,716 ----
>               indexkey = (Node *) lfirst(indexprs);
>               indexprs = lnext(indexprs);
>               /* Deparse */
> !             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
>            */
> !         if (!colno)
> !             get_opclass_name(idxrec->indclass[keyno], keycoltype,
>                            &buf);
>       }
>
> !     if (!colno)
>       {
> +         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;
> ***************
> *** 689,698 ****
>           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);
>       }
> -
>       /*
>        * Create the result as a TEXT datum, and free working data
>        */
> --- 733,742 ----
>           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);
> +         }
>       }
>       /*
>        * Create the result as a TEXT datum, and free working data
>        */
> ***************
> *** 729,734 ****
> --- 773,779 ----
>       ScanKeyData skey[1];
>       HeapTuple    tup;
>       Form_pg_constraint conForm;
> +     int      prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
>
>       /*
>        * Fetch the pg_constraint row.  There's no syscache for pg_constraint
> ***************
> *** 934,940 ****
>                       context = deparse_context_for(get_typname(conForm->contypid),
>                                                     InvalidOid);
>
> !                 consrc = deparse_expression(expr, context, false, false);
>
>                   /* Append the constraint source */
>                   appendStringInfoString(&buf, consrc);
> --- 979,985 ----
>                       context = deparse_context_for(get_typname(conForm->contypid),
>                                                     InvalidOid);
>
> !                 consrc = deparse_expression_pretty(expr, context, false, false, prettyFlags, 0);
>
>                   /* Append the constraint source */
>                   appendStringInfoString(&buf, consrc);
> ***************
> *** 1018,1023 ****
> --- 1063,1069 ----
>       char       *exprstr;
>       char       *relname;
>       char       *str;
> +     int      prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
>
>       /* Get the name for the relation */
>       relname = get_rel_name(relid);
> ***************
> *** 1041,1047 ****
>
>       /* Deparse */
>       context = deparse_context_for(relname, relid);
> !     str = deparse_expression(node, context, false, false);
>
>       /* Pass the result back as TEXT */
>       result = DatumGetTextP(DirectFunctionCall1(textin,
> --- 1087,1093 ----
>
>       /* Deparse */
>       context = deparse_context_for(relname, relid);
> !     str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0);
>
>       /* Pass the result back as TEXT */
>       result = DatumGetTextP(DirectFunctionCall1(textin,
> ***************
> *** 1090,1095 ****
> --- 1136,1152 ----
>
>   /* ----------
>    * 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).
> ***************
> *** 1100,1112 ****
>    * 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.
>    *
>    * The result is a palloc'd string.
>    * ----------
>    */
>   char *
> ! deparse_expression(Node *expr, List *dpcontext,
> !                    bool forceprefix, bool showimplicit)
>   {
>       StringInfoData buf;
>       deparse_context context;
> --- 1157,1171 ----
>    * 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
>    *
>    * The result is a palloc'd string.
>    * ----------
>    */
>   char *
> ! deparse_expression_pretty(Node *expr, List *dpcontext,
> !                    bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
>   {
>       StringInfoData buf;
>       deparse_context context;
> ***************
> *** 1115,1120 ****
> --- 1174,1181 ----
>       context.buf = &buf;
>       context.namespaces = dpcontext;
>       context.varprefix = forceprefix;
> +     context.prettyFlags = prettyFlags;
> +     context.indentLevel = startIndent;
>
>       get_rule_expr(expr, &context, showimplicit);
>
> ***************
> *** 1267,1273 ****
>    * ----------
>    */
>   static void
> ! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
>   {
>       char       *rulename;
>       char        ev_type;
> --- 1328,1334 ----
>    * ----------
>    */
>   static void
> ! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
>   {
>       char       *rulename;
>       char        ev_type;
> ***************
> *** 1321,1329 ****
>       /*
>        * Build the rules definition text
>        */
> !     appendStringInfo(buf, "CREATE RULE %s AS ON ",
>                        quote_identifier(rulename));
>
>       /* The event the rule is fired for */
>       switch (ev_type)
>       {
> --- 1382,1395 ----
>       /*
>        * Build the rules definition text
>        */
> !     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)
>       {
> ***************
> *** 1366,1371 ****
> --- 1432,1439 ----
>           deparse_context context;
>           deparse_namespace dpns;
>
> +         if (prettyFlags & PRETTYFLAG_INDENT)
> +             appendStringInfoString(buf, "\n  ");
>           appendStringInfo(buf, " WHERE ");
>
>           qual = stringToNode(ev_qual);
> ***************
> *** 1387,1392 ****
> --- 1455,1462 ----
>           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;
> ***************
> *** 1410,1417 ****
>           foreach(action, actions)
>           {
>               query = (Query *) lfirst(action);
> !             get_query_def(query, buf, NIL, NULL);
> !             appendStringInfo(buf, "; ");
>           }
>           appendStringInfo(buf, ");");
>       }
> --- 1480,1490 ----
>           foreach(action, actions)
>           {
>               query = (Query *) lfirst(action);
> !             get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
> !             if (prettyFlags)
> !                 appendStringInfo(buf, ";\n");
> !             else
> !                 appendStringInfo(buf, "; ");
>           }
>           appendStringInfo(buf, ");");
>       }
> ***************
> *** 1424,1430 ****
>           Query       *query;
>
>           query = (Query *) lfirst(actions);
> !         get_query_def(query, buf, NIL, NULL);
>           appendStringInfo(buf, ";");
>       }
>   }
> --- 1497,1503 ----
>           Query       *query;
>
>           query = (Query *) lfirst(actions);
> !         get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
>           appendStringInfo(buf, ";");
>       }
>   }
> ***************
> *** 1436,1442 ****
>    * ----------
>    */
>   static void
> ! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
>   {
>       Query       *query;
>       char        ev_type;
> --- 1509,1515 ----
>    * ----------
>    */
>   static void
> ! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
>   {
>       Query       *query;
>       char        ev_type;
> ***************
> *** 1490,1496 ****
>
>       ev_relation = heap_open(ev_class, AccessShareLock);
>
> !     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation));
>       appendStringInfo(buf, ";");
>
>       heap_close(ev_relation, AccessShareLock);
> --- 1563,1569 ----
>
>       ev_relation = heap_open(ev_class, AccessShareLock);
>
> !     get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), prettyFlags, 0);
>       appendStringInfo(buf, ";");
>
>       heap_close(ev_relation, AccessShareLock);
> ***************
> *** 1506,1512 ****
>    */
>   static void
>   get_query_def(Query *query, StringInfo buf, List *parentnamespace,
> !               TupleDesc resultDesc)
>   {
>       deparse_context context;
>       deparse_namespace dpns;
> --- 1579,1585 ----
>    */
>   static void
>   get_query_def(Query *query, StringInfo buf, List *parentnamespace,
> !               TupleDesc resultDesc, int prettyFlags, int startIndent)
>   {
>       deparse_context context;
>       deparse_namespace dpns;
> ***************
> *** 1515,1520 ****
> --- 1588,1596 ----
>       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;
> ***************
> *** 1586,1592 ****
>       /* Add the ORDER BY clause if given */
>       if (query->sortClause != NIL)
>       {
> !         appendStringInfo(buf, " ORDER BY ");
>           sep = "";
>           foreach(l, query->sortClause)
>           {
> --- 1662,1668 ----
>       /* Add the ORDER BY clause if given */
>       if (query->sortClause != NIL)
>       {
> !             appendContextKeyword(context, " ORDER BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
>           sep = "";
>           foreach(l, query->sortClause)
>           {
> ***************
> *** 1615,1626 ****
>       /* Add the LIMIT clause if given */
>       if (query->limitOffset != NULL)
>       {
> !         appendStringInfo(buf, " OFFSET ");
>           get_rule_expr(query->limitOffset, context, false);
>       }
>       if (query->limitCount != NULL)
>       {
> !         appendStringInfo(buf, " LIMIT ");
>           if (IsA(query->limitCount, Const) &&
>               ((Const *) query->limitCount)->constisnull)
>               appendStringInfo(buf, "ALL");
> --- 1691,1702 ----
>       /* Add the LIMIT clause if given */
>       if (query->limitOffset != NULL)
>       {
> !         appendContextKeyword(context, " OFFSET ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
>           get_rule_expr(query->limitOffset, context, false);
>       }
>       if (query->limitCount != NULL)
>       {
> !         appendContextKeyword(context, " LIMIT ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
>           if (IsA(query->limitCount, Const) &&
>               ((Const *) query->limitCount)->constisnull)
>               appendStringInfo(buf, "ALL");
> ***************
> *** 1641,1646 ****
> --- 1717,1727 ----
>       /*
>        * 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 */
> ***************
> *** 1720,1733 ****
>       /* Add the WHERE clause if given */
>       if (query->jointree->quals != NULL)
>       {
> !         appendStringInfo(buf, " WHERE ");
>           get_rule_expr(query->jointree->quals, context, false);
>       }
>
>       /* Add the GROUP BY clause if given */
>       if (query->groupClause != NULL)
>       {
> !         appendStringInfo(buf, " GROUP BY ");
>           sep = "";
>           foreach(l, query->groupClause)
>           {
> --- 1801,1814 ----
>       /* Add the WHERE clause if given */
>       if (query->jointree->quals != NULL)
>       {
> !         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)
>       {
> !         appendContextKeyword(context, " GROUP BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
>           sep = "";
>           foreach(l, query->groupClause)
>           {
> ***************
> *** 1743,1749 ****
>       /* Add the HAVING clause if given */
>       if (query->havingQual != NULL)
>       {
> !         appendStringInfo(buf, " HAVING ");
>           get_rule_expr(query->havingQual, context, false);
>       }
>   }
> --- 1824,1830 ----
>       /* Add the HAVING clause if given */
>       if (query->havingQual != NULL)
>       {
> !         appendContextKeyword(context, " HAVING ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
>           get_rule_expr(query->havingQual, context, false);
>       }
>   }
> ***************
> *** 1761,1795 ****
>           Query       *subquery = rte->subquery;
>
>           Assert(subquery != NULL);
> !         get_query_def(subquery, buf, context->namespaces, resultDesc);
>       }
>       else if (IsA(setOp, SetOperationStmt))
>       {
>           SetOperationStmt *op = (SetOperationStmt *) setOp;
>
> -         appendStringInfo(buf, "((");
>           get_setop_query(op->larg, query, context, resultDesc);
>           switch (op->op)
>           {
>               case SETOP_UNION:
> !                 appendStringInfo(buf, ") UNION ");
>                   break;
>               case SETOP_INTERSECT:
> !                 appendStringInfo(buf, ") INTERSECT ");
>                   break;
>               case SETOP_EXCEPT:
> !                 appendStringInfo(buf, ") EXCEPT ");
>                   break;
>               default:
>                   elog(ERROR, "get_setop_query: unexpected set op %d",
>                        (int) op->op);
>           }
>           if (op->all)
> !             appendStringInfo(buf, "ALL (");
>           else
> !             appendStringInfo(buf, "(");
>           get_setop_query(op->rarg, query, context, resultDesc);
> !         appendStringInfo(buf, "))");
>       }
>       else
>       {
> --- 1842,1905 ----
>           Query       *subquery = rte->subquery;
>
>           Assert(subquery != NULL);
> !         get_query_def(subquery, buf, context->namespaces, resultDesc, context->prettyFlags, context->indentLevel);
>       }
>       else if (IsA(setOp, SetOperationStmt))
>       {
>           SetOperationStmt *op = (SetOperationStmt *) setOp;
> +         bool need_paren=(PRETTY_PAREN(context) ? !IsA(op->rarg, RangeTblRef) : true);
> +
> +         if (!PRETTY_PAREN(context))
> +             appendStringInfoString(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:
> !                 appendContextKeyword(context, "UNION ", -PRETTYINDENT_STD, 0, 0);
>                   break;
>               case SETOP_INTERSECT:
> !                 appendContextKeyword(context, "INTERSECT ", -PRETTYINDENT_STD, 0, 0);
>                   break;
>               case SETOP_EXCEPT:
> !                 appendContextKeyword(context, "EXCEPT ", -PRETTYINDENT_STD, 0, 0);
>                   break;
>               default:
>                   elog(ERROR, "get_setop_query: unexpected set op %d",
>                        (int) op->op);
>           }
>           if (op->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
> !             appendStringInfoChar(buf, '(');
> !
>           get_setop_query(op->rarg, query, context, resultDesc);
> !
> !         if (PRETTY_PAREN(context))
> !         {
> !             if (need_paren)
> !             appendStringInfoChar(buf, ')');
> !         }
> !         else
> !             appendStringInfoString(buf, "))");
>       }
>       else
>       {
> ***************
> *** 1862,1867 ****
> --- 1972,1983 ----
>        */
>       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));
>
> ***************
> *** 1883,1889 ****
>       /* Add the VALUES or the SELECT */
>       if (select_rte == NULL)
>       {
> !         appendStringInfo(buf, "VALUES (");
>           sep = "";
>           foreach(l, query->targetList)
>           {
> --- 1999,2005 ----
>       /* Add the VALUES or the SELECT */
>       if (select_rte == NULL)
>       {
> !         appendContextKeyword(context, "VALUES (", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
>           sep = "";
>           foreach(l, query->targetList)
>           {
> ***************
> *** 1899,1905 ****
>           appendStringInfoChar(buf, ')');
>       }
>       else
> !         get_query_def(select_rte->subquery, buf, NIL, NULL);
>   }
>
>
> --- 2015,2021 ----
>           appendStringInfoChar(buf, ')');
>       }
>       else
> !         get_query_def(select_rte->subquery, buf, NIL, NULL, context->prettyFlags, context->indentLevel);
>   }
>
>
> ***************
> *** 1920,1925 ****
> --- 2036,2046 ----
>        */
>       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));
> ***************
> *** 1953,1959 ****
>       /* Finally add a WHERE clause if given */
>       if (query->jointree->quals != NULL)
>       {
> !         appendStringInfo(buf, " WHERE ");
>           get_rule_expr(query->jointree->quals, context, false);
>       }
>   }
> --- 2074,2080 ----
>       /* Finally add a WHERE clause if given */
>       if (query->jointree->quals != NULL)
>       {
> !         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
>           get_rule_expr(query->jointree->quals, context, false);
>       }
>   }
> ***************
> *** 1974,1979 ****
> --- 2095,2105 ----
>        */
>       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));
> ***************
> *** 1981,1987 ****
>       /* Add a WHERE clause if given */
>       if (query->jointree->quals != NULL)
>       {
> !         appendStringInfo(buf, " WHERE ");
>           get_rule_expr(query->jointree->quals, context, false);
>       }
>   }
> --- 2107,2113 ----
>       /* Add a WHERE clause if given */
>       if (query->jointree->quals != NULL)
>       {
> !         appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
>           get_rule_expr(query->jointree->quals, context, false);
>       }
>   }
> ***************
> *** 2000,2005 ****
> --- 2126,2132 ----
>       {
>           NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
>
> +         appendContextKeyword(context, "", 0, PRETTYINDENT_STD, 1);
>           appendStringInfo(buf, "NOTIFY %s",
>                      quote_qualified_identifier(stmt->relation->schemaname,
>                                                 stmt->relation->relname));
> ***************
> *** 2140,2145 ****
> --- 2267,2508 ----
>   }
>
>
> + /********************************************
> +  * get_simple_binary_op_name
> +  * helper function for isSimpleNode
> +  * will return single char binary operator
> +  *******************************************/
> +
> + static 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);
> +         char *op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
> +
> +         if (strlen(op) == 1)
> +             return op;
> +     }
> +     return 0;
> + }
> +
> +
> + /***************************************
> +  * check if given node is simple.
> +  *  false  : not simple
> +  *  true   : simple in the context of parent node's type
> +  ***************************************/
> +
> + static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
> + {
> +     if (!node)
> +     return true;
> +
> +     switch (nodeTag(node))
> +     {
> +     // single words: always simple
> +     case T_Var:
> +     case T_Const:
> +     case T_Param:
> +
> +     // function-like: name(..) or name[..]
> +     case T_ArrayRef:
> +     case T_ArrayExpr:
> +     case T_CoalesceExpr:
> +     case T_NullIfExpr:
> +     case T_Aggref:
> +     case T_FuncExpr:
> +
> +         // CASE keywords act as parentheses
> +     case T_CaseExpr:
> +         return true;
> +
> +         // appears simple since . has top precedence, unless parent is T_FieldSelect itself!
> +     case T_FieldSelect:
> +         return (nodeTag(parentNode) == T_FieldSelect ? false : true);
> +
> +
> +         // maybe simple, check args
> +     case T_CoerceToDomain:
> +         return isSimpleNode((Node*) ((CoerceToDomain*)node)->arg, node, prettyFlags);
> +     case T_RelabelType:
> +         return isSimpleNode((Node*) ((RelabelType*)node)->arg, node, prettyFlags);
> +
> +
> +     // depends on parent node type; needs further checking
> +     case T_OpExpr:
> +     {
> +         if (prettyFlags & PRETTYFLAG_PAREN && nodeTag(parentNode) == T_OpExpr)
> +         {
> +         char *op=get_simple_binary_op_name((OpExpr*)node);
> +         char *parentOp=get_simple_binary_op_name((OpExpr*)parentNode);
> +         if (!op || !parentOp)
> +             return false;
> +
> +                 // we know only these basic operators
> +         if (!strchr("+-*/%", *op) || !strchr("+-*/%", *parentOp))
> +             return false;
> +
> +         // natural operator precedence, so we don't need parentheses
> +         if (strchr("*/%", *op) || strchr("+-", *parentOp))
> +             return true;
> +
> +         return false;
> +         }
> +             // else do the same stuff as for T_SubLink et al.
> +     }
> +     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=((BoolExpr*)node)->boolop;
> +             BoolExprType 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;
> +         }
> +         // these are not completely implemented; so far, they're simple
> +     case T_SubPlan:
> +     case T_CoerceToDomainValue:
> +         return true;
> +
> +     case T_ScalarArrayOpExpr:
> +         // need to check
> +     default:
> +         break;
> +     }
> +     // those we don't know: in dubio complexo
> +     return false;
> + }
> +
> +
> + /******************************************
> +  * appendContextKeyword
> +  * append spaces to buffer
> +  ******************************************/
> + static void appendStringInfoSpace(StringInfo buf, int count)
> + {
> +     while (count-- > 0)
> +     appendStringInfoChar(buf, ' ');
> + }
> +
> + /******************************************
> +  * appendContextKeyword
> +  * performing a line break, and indentation
> +  * if prettyPrint is enabled.
> +  * Otherwise, only the keyword is appended
> +  *****************************************/
> +
> + static void appendContextKeyword(deparse_context *context, 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');
> +     appendStringInfoSpace(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  - parsing expr using get_rule_expr,
> +  * embracing the string with parentheses if necessary for prettyPrint.
> +  * never embracing 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 = 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
>    *
> ***************
> *** 2294,2305 ****
>                   List       *args = expr->args;
>                   Node       *arg1 = (Node *) lfirst(args);
>                   Node       *arg2 = (Node *) lsecond(args);
> !
> !                 appendStringInfoChar(buf, '(');
> !                 get_rule_expr(arg1, context, true);
>                   appendStringInfo(buf, " IS DISTINCT FROM ");
> !                 get_rule_expr(arg2, context, true);
> !                 appendStringInfoChar(buf, ')');
>               }
>               break;
>
> --- 2657,2669 ----
>                   List       *args = expr->args;
>                   Node       *arg1 = (Node *) lfirst(args);
>                   Node       *arg2 = (Node *) lsecond(args);
> !                 if (!PRETTY_PAREN(context))
> !                     appendStringInfoChar(buf, '(');
> !                 get_rule_expr_paren(arg1, context, true, node);
>                   appendStringInfo(buf, " IS DISTINCT FROM ");
> !                 get_rule_expr_paren(arg2, context, true, node);
> !                 if (!PRETTY_PAREN(context))
> !                     appendStringInfoChar(buf, ')');
>               }
>               break;
>
> ***************
> *** 2310,2324 ****
>                   Node       *arg1 = (Node *) lfirst(args);
>                   Node       *arg2 = (Node *) lsecond(args);
>
> !                 appendStringInfoChar(buf, '(');
> !                 get_rule_expr(arg1, context, true);
>                   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, "))");
>               }
>               break;
>
> --- 2674,2692 ----
>                   Node       *arg1 = (Node *) lfirst(args);
>                   Node       *arg2 = (Node *) lsecond(args);
>
> !                 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_paren(arg2, context, true, node);
> !                 appendStringInfoString(buf, ")");
> !
> !                 if (!PRETTY_PAREN(context))
> !                     appendStringInfoChar(buf, ')');
>               }
>               break;
>
> ***************
> *** 2330,2362 ****
>                   switch (expr->boolop)
>                   {
>                       case AND_EXPR:
> !                         appendStringInfoChar(buf, '(');
> !                         get_rule_expr((Node *) lfirst(args), context, false);
>                           while ((args = lnext(args)) != NIL)
>                           {
>                               appendStringInfo(buf, " AND ");
> !                             get_rule_expr((Node *) lfirst(args), context,
> !                                           false);
>                           }
> !                         appendStringInfoChar(buf, ')');
>                           break;
>
>                       case OR_EXPR:
> !                         appendStringInfoChar(buf, '(');
> !                         get_rule_expr((Node *) lfirst(args), context, false);
>                           while ((args = lnext(args)) != NIL)
>                           {
>                               appendStringInfo(buf, " OR ");
> !                             get_rule_expr((Node *) lfirst(args), context,
> !                                           false);
>                           }
> !                         appendStringInfoChar(buf, ')');
>                           break;
>
>                       case NOT_EXPR:
> !                         appendStringInfo(buf, "(NOT ");
> !                         get_rule_expr((Node *) lfirst(args), context, false);
> !                         appendStringInfoChar(buf, ')');
>                           break;
>
>                       default:
> --- 2698,2737 ----
>                   switch (expr->boolop)
>                   {
>                       case AND_EXPR:
> !                             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_paren((Node *) lfirst(args), context,
> !                                           false, node);
>                           }
> !                             if (!PRETTY_PAREN(context))
> !                             appendStringInfoChar(buf, ')');
>                           break;
>
>                       case OR_EXPR:
> !                             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_paren((Node *) lfirst(args), context,
> !                                           false, node);
>                           }
> !                             if (!PRETTY_PAREN(context))
> !                             appendStringInfoChar(buf, ')');
>                           break;
>
>                       case NOT_EXPR:
> !                             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:
> ***************
> *** 2404,2412 ****
>                    * 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));
>               }
>               break;
>
> --- 2779,2790 ----
>                    * arg.fieldname, but most cases where FieldSelect is used
>                    * are *not* simple.  So, always use parenthesized syntax.
>                    */
> !                     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;
>
> ***************
> *** 2419,2425 ****
>                       !showimplicit)
>                   {
>                       /* don't show the implicit cast */
> !                     get_rule_expr(arg, context, showimplicit);
>                   }
>                   else
>                   {
> --- 2797,2803 ----
>                       !showimplicit)
>                   {
>                       /* don't show the implicit cast */
> !                     get_rule_expr_paren(arg, context, showimplicit, node);
>                   }
>                   else
>                   {
> ***************
> *** 2431,2439 ****
>                        */
>                       arg = strip_type_coercion(arg, relabel->resulttype);
>
> !                     appendStringInfoChar(buf, '(');
> !                     get_rule_expr(arg, context, showimplicit);
> !                     appendStringInfo(buf, ")::%s",
>                               format_type_with_typemod(relabel->resulttype,
>                                                        relabel->resulttypmod));
>                   }
> --- 2809,2821 ----
>                        */
>                       arg = strip_type_coercion(arg, relabel->resulttype);
>
> !                     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));
>                   }
> ***************
> *** 2445,2463 ****
>                   CaseExpr   *caseexpr = (CaseExpr *) node;
>                   List       *temp;
>
> !                 appendStringInfo(buf, "CASE");
>                   foreach(temp, caseexpr->args)
>                   {
>                       CaseWhen   *when = (CaseWhen *) lfirst(temp);
>
> !                     appendStringInfo(buf, " WHEN ");
>                       get_rule_expr((Node *) when->expr, context, false);
>                       appendStringInfo(buf, " THEN ");
>                       get_rule_expr((Node *) when->result, context, true);
>                   }
> !                 appendStringInfo(buf, " ELSE ");
>                   get_rule_expr((Node *) caseexpr->defresult, context, true);
> !                 appendStringInfo(buf, " END");
>               }
>               break;
>
> --- 2827,2853 ----
>                   CaseExpr   *caseexpr = (CaseExpr *) node;
>                   List       *temp;
>
> !                 appendContextKeyword(context, "CASE", 0, PRETTYINDENT_VAR, 0);
>                   foreach(temp, caseexpr->args)
>                   {
>                       CaseWhen   *when = (CaseWhen *) lfirst(temp);
>
> !                     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);
>                   }
> !                 if (!PRETTY_INDENT(context))
> !                     appendStringInfoChar(buf, ' ');
> !                 appendContextKeyword(context, "ELSE ", 0, 0, 0);
>                   get_rule_expr((Node *) caseexpr->defresult, context, true);
> !                 if (!PRETTY_INDENT(context))
> !                     appendStringInfoChar(buf, ' ');
> !                 appendContextKeyword(context, "END", -PRETTYINDENT_VAR, 0, 0);
>               }
>               break;
>
> ***************
> *** 2525,2544 ****
>               {
>                   NullTest   *ntest = (NullTest *) node;
>
> !                 appendStringInfo(buf, "(");
> !                 get_rule_expr((Node *) ntest->arg, context, true);
>                   switch (ntest->nulltesttype)
>                   {
>                       case IS_NULL:
> !                         appendStringInfo(buf, " IS NULL)");
>                           break;
>                       case IS_NOT_NULL:
> !                         appendStringInfo(buf, " IS NOT NULL)");
>                           break;
>                       default:
>                           elog(ERROR, "get_rule_expr: unexpected nulltesttype %d",
>                                (int) ntest->nulltesttype);
>                   }
>               }
>               break;
>
> --- 2915,2937 ----
>               {
>                   NullTest   *ntest = (NullTest *) node;
>
> !                 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");
>                           break;
>                       case IS_NOT_NULL:
> !                         appendStringInfo(buf, " IS NOT NULL");
>                           break;
>                       default:
>                           elog(ERROR, "get_rule_expr: unexpected nulltesttype %d",
>                                (int) ntest->nulltesttype);
>                   }
> +                 if (!PRETTY_PAREN(context))
> +                     appendStringInfoChar(buf, ')');
>               }
>               break;
>
> ***************
> *** 2546,2577 ****
>               {
>                   BooleanTest *btest = (BooleanTest *) node;
>
> !                 appendStringInfo(buf, "(");
> !                 get_rule_expr((Node *) btest->arg, context, false);
>                   switch (btest->booltesttype)
>                   {
>                       case IS_TRUE:
> !                         appendStringInfo(buf, " IS TRUE)");
>                           break;
>                       case IS_NOT_TRUE:
> !                         appendStringInfo(buf, " IS NOT TRUE)");
>                           break;
>                       case IS_FALSE:
> !                         appendStringInfo(buf, " IS FALSE)");
>                           break;
>                       case IS_NOT_FALSE:
> !                         appendStringInfo(buf, " IS NOT FALSE)");
>                           break;
>                       case IS_UNKNOWN:
> !                         appendStringInfo(buf, " IS UNKNOWN)");
>                           break;
>                       case IS_NOT_UNKNOWN:
> !                         appendStringInfo(buf, " IS NOT UNKNOWN)");
>                           break;
>                       default:
>                           elog(ERROR, "get_rule_expr: unexpected booltesttype %d",
>                                (int) btest->booltesttype);
>                   }
>               }
>               break;
>
> --- 2939,2973 ----
>               {
>                   BooleanTest *btest = (BooleanTest *) node;
>
> !                 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");
>                           break;
>                       case IS_NOT_TRUE:
> !                         appendStringInfo(buf, " IS NOT TRUE");
>                           break;
>                       case IS_FALSE:
> !                         appendStringInfo(buf, " IS FALSE");
>                           break;
>                       case IS_NOT_FALSE:
> !                         appendStringInfo(buf, " IS NOT FALSE");
>                           break;
>                       case IS_UNKNOWN:
> !                         appendStringInfo(buf, " IS UNKNOWN");
>                           break;
>                       case IS_NOT_UNKNOWN:
> !                         appendStringInfo(buf, " IS NOT UNKNOWN");
>                           break;
>                       default:
>                           elog(ERROR, "get_rule_expr: unexpected booltesttype %d",
>                                (int) btest->booltesttype);
>                   }
> +                 if (!PRETTY_PAREN(context))
> +                     appendStringInfoChar(buf, ')');
>               }
>               break;
>
> ***************
> *** 2593,2601 ****
>                   }
>                   else
>                   {
> !                     appendStringInfoChar(buf, '(');
> !                     get_rule_expr(arg, context, false);
> !                     appendStringInfo(buf, ")::%s",
>                               format_type_with_typemod(ctest->resulttype,
>                                                        ctest->resulttypmod));
>                   }
> --- 2989,3002 ----
>                   }
>                   else
>                   {
> !                     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));
>                   }
> ***************
> *** 2627,2645 ****
>       Oid            opno = expr->opno;
>       List       *args = expr->args;
>
> !     appendStringInfoChar(buf, '(');
>       if (length(args) == 2)
>       {
>           /* binary operator */
>           Node       *arg1 = (Node *) lfirst(args);
>           Node       *arg2 = (Node *) lsecond(args);
> !
> !         get_rule_expr(arg1, context, true);
>           appendStringInfo(buf, " %s ",
>                            generate_operator_name(opno,
>                                                   exprType(arg1),
>                                                   exprType(arg2)));
> !         get_rule_expr(arg2, context, true);
>       }
>       else
>       {
> --- 3028,3046 ----
>       Oid            opno = expr->opno;
>       List       *args = expr->args;
>
> !     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_paren(arg1, context, true, (Node*)expr);
>           appendStringInfo(buf, " %s ",
>                            generate_operator_name(opno,
>                                                   exprType(arg1),
>                                                   exprType(arg2)));
> !         get_rule_expr_paren(arg2, context, true, (Node*)expr);
>       }
>       else
>       {
> ***************
> *** 2661,2670 ****
>                                    generate_operator_name(opno,
>                                                           InvalidOid,
>                                                           exprType(arg)));
> !                 get_rule_expr(arg, context, true);
>                   break;
>               case 'r':
> !                 get_rule_expr(arg, context, true);
>                   appendStringInfo(buf, " %s",
>                                    generate_operator_name(opno,
>                                                           exprType(arg),
> --- 3062,3071 ----
>                                    generate_operator_name(opno,
>                                                           InvalidOid,
>                                                           exprType(arg)));
> !                 get_rule_expr_paren(arg, context, true, (Node*)expr);
>                   break;
>               case 'r':
> !                 get_rule_expr_paren(arg, context, true, (Node*)expr);
>                   appendStringInfo(buf, " %s",
>                                    generate_operator_name(opno,
>                                                           exprType(arg),
> ***************
> *** 2675,2681 ****
>           }
>           ReleaseSysCache(tp);
>       }
> !     appendStringInfoChar(buf, ')');
>   }
>
>   /*
> --- 3076,3083 ----
>           }
>           ReleaseSysCache(tp);
>       }
> !     if (!PRETTY_PAREN(context))
> !         appendStringInfoChar(buf, ')');
>   }
>
>   /*
> ***************
> *** 2698,2704 ****
>        */
>       if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
>       {
> !         get_rule_expr((Node *) lfirst(expr->args), context, showimplicit);
>           return;
>       }
>
> --- 3100,3106 ----
>        */
>       if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
>       {
> !         get_rule_expr_paren((Node *) lfirst(expr->args), context, showimplicit, (Node*)expr);
>           return;
>       }
>
> ***************
> *** 2724,2732 ****
>            */
>           arg = strip_type_coercion(arg, rettype);
>
> !         appendStringInfoChar(buf, '(');
> !         get_rule_expr(arg, context, showimplicit);
> !         appendStringInfo(buf, ")::%s",
>                            format_type_with_typemod(rettype, coercedTypmod));
>
>           return;
> --- 3126,3139 ----
>            */
>           arg = strip_type_coercion(arg, rettype);
>
> !         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;
> ***************
> *** 3047,3053 ****
>       if (need_paren)
>           appendStringInfoChar(buf, '(');
>
> !     get_query_def(query, buf, context->namespaces, NULL);
>
>       if (need_paren)
>           appendStringInfo(buf, "))");
> --- 3454,3460 ----
>       if (need_paren)
>           appendStringInfoChar(buf, '(');
>
> !     get_query_def(query, buf, context->namespaces, NULL, context->prettyFlags, context->indentLevel);
>
>       if (need_paren)
>           appendStringInfo(buf, "))");
> ***************
> *** 3064,3070 ****
>   get_from_clause(Query *query, deparse_context *context)
>   {
>       StringInfo    buf = context->buf;
> !     char       *sep;
>       List       *l;
>
>       /*
> --- 3471,3477 ----
>   get_from_clause(Query *query, deparse_context *context)
>   {
>       StringInfo    buf = context->buf;
> !     char       *sep=0;
>       List       *l;
>
>       /*
> ***************
> *** 3074,3080 ****
>        * sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW
>        * and OLD.
>        */
> -     sep = " FROM ";
>
>       foreach(l, query->jointree->fromlist)
>       {
> --- 3481,3486 ----
> ***************
> *** 3093,3099 ****
>                   continue;
>           }
>
> !         appendStringInfo(buf, sep);
>           get_from_clause_item(jtnode, query, context);
>           sep = ", ";
>       }
> --- 3499,3509 ----
>                   continue;
>           }
>
> !         if (!sep)
> !             appendContextKeyword(context, " FROM ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
> !         else
> !             appendStringInfo(buf, sep);
> !
>           get_from_clause_item(jtnode, query, context);
>           sep = ", ";
>       }
> ***************
> *** 3122,3128 ****
>               case RTE_SUBQUERY:
>                   /* Subquery RTE */
>                   appendStringInfoChar(buf, '(');
> !                 get_query_def(rte->subquery, buf, context->namespaces, NULL);
>                   appendStringInfoChar(buf, ')');
>                   break;
>               case RTE_FUNCTION:
> --- 3532,3539 ----
>               case RTE_SUBQUERY:
>                   /* Subquery RTE */
>                   appendStringInfoChar(buf, '(');
> !                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
> !                           context->prettyFlags, context->indentLevel);
>                   appendStringInfoChar(buf, ')');
>                   break;
>               case RTE_FUNCTION:
> ***************
> *** 3144,3150 ****
>               {
>                   List       *col;
>
> !                 appendStringInfo(buf, "(");
>                   foreach(col, rte->alias->colnames)
>                   {
>                       if (col != rte->alias->colnames)
> --- 3555,3561 ----
>               {
>                   List       *col;
>
> !                 appendStringInfoChar(buf, '(');
>                   foreach(col, rte->alias->colnames)
>                   {
>                       if (col != rte->alias->colnames)
> ***************
> *** 3178,3213 ****
>       else if (IsA(jtnode, JoinExpr))
>       {
>           JoinExpr   *j = (JoinExpr *) jtnode;
>
> -         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, "get_from_clause_item: unknown join type %d",
>                        (int) j->jointype);
>           }
>           get_from_clause_item(j->rarg, query, context);
>           if (!j->isNatural)
>           {
>               if (j->using)
> --- 3589,3666 ----
>       else if (IsA(jtnode, JoinExpr))
>       {
>           JoinExpr   *j = (JoinExpr *) jtnode;
> +         bool need_paren_on_right = PRETTY_PAREN(context) && !IsA(j->rarg, RangeTblRef);
> +
> +         if (!PRETTY_PAREN(context) || j->alias != NULL)
> +             appendStringInfoChar(buf, '(');
>
>           get_from_clause_item(j->larg, query, context);
> +
>           if (j->isNatural)
>           {
> +             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, "get_from_clause_item: unknown 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, "get_from_clause_item: unknown 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)
> ***************
> *** 3226,3237 ****
>               }
>               else if (j->quals)
>               {
> !                 appendStringInfo(buf, " ON (");
>                   get_rule_expr(j->quals, context, false);
> !                 appendStringInfoChar(buf, ')');
>               }
>           }
> !         appendStringInfoChar(buf, ')');
>           /* Yes, it's correct to put alias after the right paren ... */
>           if (j->alias != NULL)
>           {
> --- 3679,3695 ----
>               }
>               else if (j->quals)
>               {
> !                 appendStringInfo(buf, " ON ");
> !                 if (!PRETTY_PAREN(context))
> !                     appendStringInfoChar(buf, '(');
>                   get_rule_expr(j->quals, context, false);
> !                 if (!PRETTY_PAREN(context))
> !                     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)
>           {
> ***************
> *** 3241,3247 ****
>               {
>                   List       *col;
>
> !                 appendStringInfo(buf, "(");
>                   foreach(col, j->alias->colnames)
>                   {
>                       if (col != j->alias->colnames)
> --- 3699,3705 ----
>               {
>                   List       *col;
>
> !                 appendStringInfoChar(buf, '(');
>                   foreach(col, j->alias->colnames)
>                   {
>                       if (col != j->alias->colnames)

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: ruleutils with pretty-print option

From
"Christopher Kings-Lynne"
Date:
Didn't Tom already apply that???

Chris

----- Original Message -----
From: "Bruce Momjian" <pgman@candle.pha.pa.us>
To: "Tom Lane" <tgl@sss.pgh.pa.us>
Cc: "Andreas Pflug" <pgadmin@pse-consulting.de>;
<pgsql-patches@postgresql.org>
Sent: Thursday, July 31, 2003 12:52 PM
Subject: Re: [PATCHES] ruleutils with pretty-print option


>
> I didn't like the functions ending in _ext.  I renamed them to _pp for
> pretty print.  Patch attached and applied.
>
> --------------------------------------------------------------------------
-
>
> Tom Lane wrote:
> > Andreas Pflug <pgadmin@pse-consulting.de> writes:
> > > I recoded the stuff as Tom recommended, leaving the non-pretty version
> > > function names as they used to be, inventing new pg_get_XXXX_ext
> > > functions for the extended stuff, and pushing the code down into
> > > pg_get_XXXX_worker functions when needed. We now need the additional
> > > prototype include patch from builtins.h.
> >
> > Applied with some editorializing.  In particular, I don't believe the
> > original did the right thing with (a - (b - c)).
> >
> > regards, tom lane
> >
> > ---------------------------(end of broadcast)---------------------------
> > TIP 4: Don't 'kill -9' the postmaster
> >
>
> --
>   Bruce Momjian                        |  http://candle.pha.pa.us
>   pgman@candle.pha.pa.us               |  (610) 359-1001
>   +  If your life is a hard drive,     |  13 Roberts Road
>   +  Christ can be your backup.        |  Newtown Square, Pennsylvania
19073
>


----------------------------------------------------------------------------
----


> Index: src/backend/utils/adt/ruleutils.c
> ===================================================================
> RCS file: /cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
> retrieving revision 1.147
> diff -c -c -r1.147 ruleutils.c
> *** src/backend/utils/adt/ruleutils.c 30 Jul 2003 22:56:23 -0000 1.147
> --- src/backend/utils/adt/ruleutils.c 31 Jul 2003 04:48:35 -0000
> ***************
> *** 228,234 ****
>
>
>   Datum
> ! pg_get_ruledef_ext(PG_FUNCTION_ARGS)
>   {
>   Oid ruleoid = PG_GETARG_OID(0);
>   bool pretty = PG_GETARG_BOOL(1);
> --- 228,234 ----
>
>
>   Datum
> ! pg_get_ruledef_pp(PG_FUNCTION_ARGS)
>   {
>   Oid ruleoid = PG_GETARG_OID(0);
>   bool pretty = PG_GETARG_BOOL(1);
> ***************
> *** 337,343 ****
>
>
>   Datum
> ! pg_get_viewdef_ext(PG_FUNCTION_ARGS)
>   {
>   /* By OID */
>   Oid viewoid = PG_GETARG_OID(0);
> --- 337,343 ----
>
>
>   Datum
> ! pg_get_viewdef_pp(PG_FUNCTION_ARGS)
>   {
>   /* By OID */
>   Oid viewoid = PG_GETARG_OID(0);
> ***************
> *** 369,375 ****
>
>
>   Datum
> ! pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
>   {
>   /* By qualified name */
>   text    *viewname = PG_GETARG_TEXT_P(0);
> --- 369,375 ----
>
>
>   Datum
> ! pg_get_viewdef_name_pp(PG_FUNCTION_ARGS)
>   {
>   /* By qualified name */
>   text    *viewname = PG_GETARG_TEXT_P(0);
> ***************
> *** 630,636 ****
>   }
>
>   Datum
> ! pg_get_indexdef_ext(PG_FUNCTION_ARGS)
>   {
>   Oid indexrelid = PG_GETARG_OID(0);
>   int32       colno = PG_GETARG_INT32(1);
> --- 630,636 ----
>   }
>
>   Datum
> ! pg_get_indexdef_pp(PG_FUNCTION_ARGS)
>   {
>   Oid indexrelid = PG_GETARG_OID(0);
>   int32       colno = PG_GETARG_INT32(1);
> ***************
> *** 856,862 ****
>   }
>
>   Datum
> ! pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
>   {
>   Oid constraintId = PG_GETARG_OID(0);
>   bool pretty = PG_GETARG_BOOL(1);
> --- 856,862 ----
>   }
>
>   Datum
> ! pg_get_constraintdef_pp(PG_FUNCTION_ARGS)
>   {
>   Oid constraintId = PG_GETARG_OID(0);
>   bool pretty = PG_GETARG_BOOL(1);
> ***************
> *** 1175,1181 ****
>   }
>
>   Datum
> ! pg_get_expr_ext(PG_FUNCTION_ARGS)
>   {
>   text *expr = PG_GETARG_TEXT_P(0);
>   Oid relid = PG_GETARG_OID(1);
> --- 1175,1181 ----
>   }
>
>   Datum
> ! pg_get_expr_pp(PG_FUNCTION_ARGS)
>   {
>   text *expr = PG_GETARG_TEXT_P(0);
>   Oid relid = PG_GETARG_OID(1);
> Index: src/include/catalog/pg_proc.h
> ===================================================================
> RCS file: /cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
> retrieving revision 1.310
> diff -c -c -r1.310 pg_proc.h
> *** src/include/catalog/pg_proc.h 30 Jul 2003 22:56:24 -0000 1.310
> --- src/include/catalog/pg_proc.h 31 Jul 2003 04:48:40 -0000
> ***************
> *** 3406,3422 ****
>   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");
>
>
> --- 3406,3422 ----
>   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_pp - _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_pp - _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_pp - _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_pp - _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_pp - _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_pp - _null_ ));
>   DESCR("deparse an encoded expression with pretty-print option");
>
>
> Index: src/include/utils/builtins.h
> ===================================================================
> RCS file: /cvsroot/pgsql-server/src/include/utils/builtins.h,v
> retrieving revision 1.224
> diff -c -c -r1.224 builtins.h
> *** src/include/utils/builtins.h 30 Jul 2003 22:56:24 -0000 1.224
> --- src/include/utils/builtins.h 31 Jul 2003 04:48:41 -0000
> ***************
> *** 441,459 ****
>
>   /* 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);
> --- 441,459 ----
>
>   /* ruleutils.c */
>   extern Datum pg_get_ruledef(PG_FUNCTION_ARGS);
> ! extern Datum pg_get_ruledef_pp(PG_FUNCTION_ARGS);
>   extern Datum pg_get_viewdef(PG_FUNCTION_ARGS);
> ! extern Datum pg_get_viewdef_pp(PG_FUNCTION_ARGS);
>   extern Datum pg_get_viewdef_name(PG_FUNCTION_ARGS);
> ! extern Datum pg_get_viewdef_name_pp(PG_FUNCTION_ARGS);
>   extern Datum pg_get_indexdef(PG_FUNCTION_ARGS);
> ! extern Datum pg_get_indexdef_pp(PG_FUNCTION_ARGS);
>   extern Datum pg_get_triggerdef(PG_FUNCTION_ARGS);
>   extern Datum pg_get_constraintdef(PG_FUNCTION_ARGS);
> ! extern Datum pg_get_constraintdef_pp(PG_FUNCTION_ARGS);
>   extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
>   extern Datum pg_get_expr(PG_FUNCTION_ARGS);
> ! extern Datum pg_get_expr_pp(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);
>


----------------------------------------------------------------------------
----


>
> ---------------------------(end of broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please send an appropriate
>       subscribe-nomail command to majordomo@postgresql.org so that your
>       message can get through to the mailing list cleanly
>


Re: ruleutils with pretty-print option

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> I didn't like the functions ending in _ext.  I renamed them to _pp for
> pretty print.  Patch attached and applied.

Seems to be shy a catversion bump; since you have just made an
incompatible change in the internal-function-names array, one is needed.

But I disagree with your opinion anyway --- _ext for "extended" made
perfect sense to me, especially for the get_indexdef one which adds more
than just prettyprint functionality.

            regards, tom lane

Re: ruleutils with pretty-print option

From
Andreas Pflug
Date:
Tom Lane wrote:

>
>Applied with some editorializing.  In particular, I don't believe the
>original did the right thing with (a - (b - c)).
>
>
>

Oops, missed that case...
But now, we have (a + ( b + c)) again.
A patch that removes parentheses for + and * is appended.

Regards,
Andfdsa


Re: ruleutils with pretty-print option

From
Bruce Momjian
Date:
Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > I didn't like the functions ending in _ext.  I renamed them to _pp for
> > pretty print.  Patch attached and applied.
>
> Seems to be shy a catversion bump; since you have just made an
> incompatible change in the internal-function-names array, one is needed.
>
> But I disagree with your opinion anyway --- _ext for "extended" made
> perfect sense to me, especially for the get_indexdef one which adds more
> than just prettyprint functionality.

OK. I never did the commit, so I will just discard the patch.

Thanks.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: ruleutils with pretty-print option

From
Bruce Momjian
Date:
Would you send over the patch --- it was missing.

---------------------------------------------------------------------------

Andreas Pflug wrote:
> Tom Lane wrote:
>
> >
> >Applied with some editorializing.  In particular, I don't believe the
> >original did the right thing with (a - (b - c)).
> >
> >
> >
>
> Oops, missed that case...
> But now, we have (a + ( b + c)) again.
> A patch that removes parentheses for + and * is appended.
>
> Regards,
> Andfdsa
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 2: you can get off all lists at once with the unregister command
>     (send "unregister YourEmailAddressHere" to majordomo@postgresql.org)
>

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073