Re: ruleutils with pretty-print option - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: ruleutils with pretty-print option
Date
Msg-id 200307200149.h6K1nZ503053@candle.pha.pa.us
Whole thread Raw
In response to ruleutils with pretty-print option  (Andreas Pflug <Andreas.Pflug@web.de>)
List pgsql-patches
Sorry I am getting to this patch late. I know you posted a newer
version, but this one has a better description.

I am uncertain if we are over-engineering the interface by having three
ways to control the output.  Is that valuable?  If it is, fine, but if
it isn't, the extra code just adds to confusion and possible bugs.

Basically, should we just have a boolean specifying pretty_print
true/false?

Comments?

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

Andreas Pflug wrote:
> 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.
>
>
> Regards,
> Andreas

> Index: ruleutils.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
> retrieving revision 1.143
> diff -c -r1.143 ruleutils.c
> *** ruleutils.c    29 Jun 2003 00:33:44 -0000    1.143
> --- ruleutils.c    29 Jun 2003 16:54:48 -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,582 ----
>       StringInfoData buf;
>       char       *str;
>       char       *sep;
> +     int             prettyFlags = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);
>
>       /*
>        * Fetch the pg_index tuple by the Oid of the index
> ***************
> *** 643,649 ****
>               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)
> --- 676,682 ----
>               indexkey = (Node *) lfirst(indexprs);
>               indexprs = lnext(indexprs);
>               /* Deparse */
> !             str = deparse_expression_pretty(indexkey, context, false, false, prettyFlags, 0);
>               /* Need parens if it's not a bare function call */
>               if (indexkey && IsA(indexkey, FuncExpr) &&
>                   ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
> ***************
> *** 689,695 ****
>           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);
>       }
>
> --- 722,728 ----
>           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);
>       }
>
> ***************
> *** 729,734 ****
> --- 762,768 ----
>       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);
> --- 968,974 ----
>                       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 ****
> --- 1052,1058 ----
>       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,
> --- 1076,1082 ----
>
>       /* 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 ****
> --- 1125,1141 ----
>
>   /* ----------
>    * 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;
> --- 1146,1160 ----
>    * 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 ****
> --- 1163,1170 ----
>       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;
> --- 1317,1323 ----
>    * ----------
>    */
>   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)
>       {
> --- 1371,1384 ----
>       /*
>        * 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 ****
> --- 1421,1428 ----
>           deparse_context context;
>           deparse_namespace dpns;
>
> +         if (prettyFlags & PRETTYFLAG_INDENT)
> +             appendStringInfoString(buf, "\n  ");
>           appendStringInfo(buf, " WHERE ");
>
>           qual = stringToNode(ev_qual);
> ***************
> *** 1387,1392 ****
> --- 1444,1451 ----
>           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, ");");
>       }
> --- 1469,1479 ----
>           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, ";");
>       }
>   }
> --- 1486,1492 ----
>           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;
> --- 1498,1504 ----
>    * ----------
>    */
>   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);
> --- 1552,1558 ----
>
>       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;
> --- 1568,1574 ----
>    */
>   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 ****
> --- 1577,1585 ----
>       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)
>           {
> --- 1651,1657 ----
>       /* 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");
> --- 1680,1691 ----
>       /* 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 ****
> --- 1706,1716 ----
>       /*
>        * 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)
>           {
> --- 1790,1803 ----
>       /* 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);
>       }
>   }
> --- 1813,1819 ----
>       /* 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
>       {
> --- 1831,1894 ----
>           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 ****
> --- 1961,1972 ----
>        */
>       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)
>           {
> --- 1988,1994 ----
>       /* 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);
>   }
>
>
> --- 2004,2010 ----
>           appendStringInfoChar(buf, ')');
>       }
>       else
> !         get_query_def(select_rte->subquery, buf, NIL, NULL, context->prettyFlags, context->indentLevel);
>   }
>
>
> ***************
> *** 1920,1925 ****
> --- 2025,2035 ----
>        */
>       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);
>       }
>   }
> --- 2063,2069 ----
>       /* 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 ****
> --- 2084,2094 ----
>        */
>       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);
>       }
>   }
> --- 2096,2102 ----
>       /* 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 ****
> --- 2115,2121 ----
>       {
>           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 ****
> --- 2256,2497 ----
>   }
>
>
> + /********************************************
> +  * 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;
>
> --- 2646,2658 ----
>                   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;
>
> --- 2663,2681 ----
>                   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:
> --- 2687,2726 ----
>                   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;
>
> --- 2768,2779 ----
>                    * 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
>                   {
> --- 2786,2792 ----
>                       !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));
>                   }
> --- 2798,2810 ----
>                        */
>                       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;
>
> --- 2816,2842 ----
>                   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;
>
> --- 2904,2926 ----
>               {
>                   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;
>
> --- 2928,2962 ----
>               {
>                   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));
>                   }
> --- 2978,2991 ----
>                   }
>                   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));
>                   }
> ***************
> *** 2623,2641 ****
>       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
>       {
> --- 3013,3031 ----
>       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
>       {
> ***************
> *** 2657,2666 ****
>                                    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),
> --- 3047,3056 ----
>                                    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),
> ***************
> *** 2671,2677 ****
>           }
>           ReleaseSysCache(tp);
>       }
> !     appendStringInfoChar(buf, ')');
>   }
>
>   /*
> --- 3061,3068 ----
>           }
>           ReleaseSysCache(tp);
>       }
> !     if (!PRETTY_PAREN(context))
> !         appendStringInfoChar(buf, ')');
>   }
>
>   /*
> ***************
> *** 2694,2700 ****
>        */
>       if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
>       {
> !         get_rule_expr((Node *) lfirst(expr->args), context, showimplicit);
>           return;
>       }
>
> --- 3085,3091 ----
>        */
>       if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
>       {
> !         get_rule_expr_paren((Node *) lfirst(expr->args), context, showimplicit, (Node*)expr);
>           return;
>       }
>
> ***************
> *** 2720,2728 ****
>            */
>           arg = strip_type_coercion(arg, rettype);
>
> !         appendStringInfoChar(buf, '(');
> !         get_rule_expr(arg, context, showimplicit);
> !         appendStringInfo(buf, ")::%s",
>                            format_type_with_typemod(rettype, coercedTypmod));
>
>           return;
> --- 3111,3124 ----
>            */
>           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;
> ***************
> *** 3043,3049 ****
>       if (need_paren)
>           appendStringInfoChar(buf, '(');
>
> !     get_query_def(query, buf, context->namespaces, NULL);
>
>       if (need_paren)
>           appendStringInfo(buf, "))");
> --- 3439,3445 ----
>       if (need_paren)
>           appendStringInfoChar(buf, '(');
>
> !     get_query_def(query, buf, context->namespaces, NULL, context->prettyFlags, context->indentLevel);
>
>       if (need_paren)
>           appendStringInfo(buf, "))");
> ***************
> *** 3060,3066 ****
>   get_from_clause(Query *query, deparse_context *context)
>   {
>       StringInfo    buf = context->buf;
> !     char       *sep;
>       List       *l;
>
>       /*
> --- 3456,3462 ----
>   get_from_clause(Query *query, deparse_context *context)
>   {
>       StringInfo    buf = context->buf;
> !     char       *sep=0;
>       List       *l;
>
>       /*
> ***************
> *** 3070,3076 ****
>        * sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW
>        * and OLD.
>        */
> -     sep = " FROM ";
>
>       foreach(l, query->jointree->fromlist)
>       {
> --- 3466,3471 ----
> ***************
> *** 3089,3095 ****
>                   continue;
>           }
>
> !         appendStringInfo(buf, sep);
>           get_from_clause_item(jtnode, query, context);
>           sep = ", ";
>       }
> --- 3484,3494 ----
>                   continue;
>           }
>
> !         if (!sep)
> !             appendContextKeyword(context, " FROM ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
> !         else
> !             appendStringInfo(buf, sep);
> !
>           get_from_clause_item(jtnode, query, context);
>           sep = ", ";
>       }
> ***************
> *** 3118,3124 ****
>               case RTE_SUBQUERY:
>                   /* Subquery RTE */
>                   appendStringInfoChar(buf, '(');
> !                 get_query_def(rte->subquery, buf, context->namespaces, NULL);
>                   appendStringInfoChar(buf, ')');
>                   break;
>               case RTE_FUNCTION:
> --- 3517,3524 ----
>               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:
> ***************
> *** 3140,3146 ****
>               {
>                   List       *col;
>
> !                 appendStringInfo(buf, "(");
>                   foreach(col, rte->alias->colnames)
>                   {
>                       if (col != rte->alias->colnames)
> --- 3540,3546 ----
>               {
>                   List       *col;
>
> !                 appendStringInfoChar(buf, '(');
>                   foreach(col, rte->alias->colnames)
>                   {
>                       if (col != rte->alias->colnames)
> ***************
> *** 3174,3209 ****
>       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)
> --- 3574,3651 ----
>       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)
> ***************
> *** 3222,3233 ****
>               }
>               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)
>           {
> --- 3664,3680 ----
>               }
>               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)
>           {
> ***************
> *** 3237,3243 ****
>               {
>                   List       *col;
>
> !                 appendStringInfo(buf, "(");
>                   foreach(col, j->alias->colnames)
>                   {
>                       if (col != j->alias->colnames)
> --- 3684,3690 ----
>               {
>                   List       *col;
>
> !                 appendStringInfoChar(buf, '(');
>                   foreach(col, j->alias->colnames)
>                   {
>                       if (col != j->alias->colnames)

> Index: pg_proc.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
> retrieving revision 1.308
> diff -c -r1.308 pg_proc.h
> *** pg_proc.h    27 Jun 2003 00:33:25 -0000    1.308
> --- pg_proc.h    29 Jun 2003 17:00:25 -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");
> + 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");
> + 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");
> + DATA(insert OID = 2507 (  pg_get_indexdef       PGNSP PGUID 12 f f t f s 2 25 "26 23"  pg_get_indexdef - _null_ ));
> + DESCR("index description");
> + 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");
> + 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");
> +
>
>   /*
>    * Symbolic values for provolatile column: these indicate whether the result

>
> ---------------------------(end of broadcast)---------------------------
> TIP 8: explain analyze is your friend

--
  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

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: Minor pager corrections in print.c and help.c (psql)
Next
From: Bruce Momjian
Date:
Subject: Re: UPDATED Patch for adding DATACUBE operator