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

From Bruce Momjian
Subject Re: ruleutils with pretty-print option
Date
Msg-id 200307221556.h6MFusZ20863@candle.pha.pa.us
Whole thread Raw
In response to Re: ruleutils with pretty-print option  (Andreas Pflug <pgadmin@pse-consulting.de>)
List pgsql-patches
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

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: timetravel.c
Next
From: Bruce Momjian
Date:
Subject: Re: ruleutils with pretty-print option