Re: ruleutils with pretty-print option

Поиск
Список
Период
Сортировка
Искать
От
Andreas Pflug
Тема
Re: ruleutils with pretty-print option
Дата
Msg-id
3F2463E9.9010400@pse-consulting.de
Ответ на
Список
Дерево обсуждения
ruleutils with pretty-print option Andreas Pflug <pgadmin@pse-consulting.de>
Bruce Momjian wrote:

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

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

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

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

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

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

Regards,
Andreas



Index: include/catalog/pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_proc.h,v
retrieving revision 1.309
diff -c -r1.309 pg_proc.h
*** include/catalog/pg_proc.h	1 Jul 2003 00:04:38 -0000	1.309
--- include/catalog/pg_proc.h	27 Jul 2003 23:40:49 -0000
***************
*** 3405,3410 ****
--- 3405,3424 ----
  DATA(insert OID = 2503 (  anyarray_send		   PGNSP PGUID 12 f f t f s 1 17 "2277"  anyarray_send - _null_ ));
  DESCR("I/O");
  
+ /* System-view support functions with pretty-print option */
+ DATA(insert OID = 2504 (  pg_get_ruledef	   PGNSP PGUID 12 f f t f s 2 25 "26 16"  pg_get_ruledef_ext - _null_ ));
+ DESCR("source text of a rule with pretty-print option");
+ DATA(insert OID = 2505 (  pg_get_viewdef	   PGNSP PGUID 12 f f t f s 2 25 "25 16"  pg_get_viewdef_name_ext - _null_ ));
+ DESCR("select statement of a view with pretty-print option");
+ DATA(insert OID = 2506 (  pg_get_viewdef	   PGNSP PGUID 12 f f t f s 2 25 "26 16"  pg_get_viewdef_ext - _null_ ));
+ DESCR("select statement of a view with pretty-print option");
+ DATA(insert OID = 2507 (  pg_get_indexdef	   PGNSP PGUID 12 f f t f s 3 25 "26 23 16"  pg_get_indexdef_ext - _null_ ));
+ DESCR("index description (full create statement or single expression) with pretty-print option");
+ DATA(insert OID = 2508 (  pg_get_constraintdef PGNSP PGUID 12 f f t f s 2 25 "26 16"  pg_get_constraintdef_ext - _null_ ));
+ DESCR("constraint description with pretty-print option");
+ DATA(insert OID = 2509 (  pg_get_expr		   PGNSP PGUID 12 f f t f s 3 25 "25 26 16"	pg_get_expr_ext - _null_ ));
+ DESCR("deparse an encoded expression with pretty-print option");
+ 
  
  /*
   * Symbolic values for provolatile column: these indicate whether the result
Index: include/utils/builtins.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/utils/builtins.h,v
retrieving revision 1.223
diff -c -r1.223 builtins.h
*** include/utils/builtins.h	27 Jun 2003 00:33:26 -0000	1.223
--- include/utils/builtins.h	27 Jul 2003 23:41:58 -0000
***************
*** 441,453 ****
--- 441,459 ----
  
  /* ruleutils.c */
  extern Datum pg_get_ruledef(PG_FUNCTION_ARGS);
+ extern Datum pg_get_ruledef_ext(PG_FUNCTION_ARGS);
  extern Datum pg_get_viewdef(PG_FUNCTION_ARGS);
+ extern Datum pg_get_viewdef_ext(PG_FUNCTION_ARGS);
  extern Datum pg_get_viewdef_name(PG_FUNCTION_ARGS);
+ extern Datum pg_get_viewdef_name_ext(PG_FUNCTION_ARGS);
  extern Datum pg_get_indexdef(PG_FUNCTION_ARGS);
+ extern Datum pg_get_indexdef_ext(PG_FUNCTION_ARGS);
  extern Datum pg_get_triggerdef(PG_FUNCTION_ARGS);
  extern Datum pg_get_constraintdef(PG_FUNCTION_ARGS);
+ extern Datum pg_get_constraintdef_ext(PG_FUNCTION_ARGS);
  extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
  extern Datum pg_get_expr(PG_FUNCTION_ARGS);
+ extern Datum pg_get_expr_ext(PG_FUNCTION_ARGS);
  extern char *deparse_expression(Node *expr, List *dpcontext,
  				   bool forceprefix, bool showimplicit);
  extern List *deparse_context_for(const char *aliasname, Oid relid);
Index: backend/utils/adt/ruleutils.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.146
diff -c -r1.146 ruleutils.c
*** backend/utils/adt/ruleutils.c	27 Jul 2003 04:53:09 -0000	1.146
--- backend/utils/adt/ruleutils.c	27 Jul 2003 23:42:40 -0000
***************
*** 71,76 ****
--- 71,95 ----
  #include "utils/lsyscache.h"
  
  
+ /******************************
+  * Pretty formatting constants
+  ******************************/
+ 
+ /* Indent counts */
+ #define PRETTYINDENT_STD        8
+ #define PRETTYINDENT_JOIN      13
+ #define PRETTYINDENT_JOIN_ON    (PRETTYINDENT_JOIN-PRETTYINDENT_STD)
+ #define PRETTYINDENT_VAR        4
+ 
+ /* Pretty flags */
+ #define PRETTYFLAG_PAREN        1
+ #define PRETTYFLAG_INDENT       2
+ 
+ /* macro to test if pretty action needed */
+ #define PRETTY_PAREN(context)   (context->prettyFlags & PRETTYFLAG_PAREN)
+ #define PRETTY_INDENT(context)  (context->prettyFlags & PRETTYFLAG_INDENT)
+ 
+ 
  /* ----------
   * Local data types
   * ----------
***************
*** 81,86 ****
--- 100,107 ----
  {
  	StringInfo	buf;			/* output buffer to append to */
  	List	   *namespaces;		/* List of deparse_namespace nodes */
+         int             prettyFlags;            /* enabling/disabling of pretty-print functions */
+         int             indentLevel;            /* for prettyPrint, current space indents are counted */
  	bool		varprefix;		/* TRUE to print prefixes on Vars */
  } deparse_context;
  
***************
*** 123,135 ****
   * as a parameter, and append their text output to its contents.
   * ----------
   */
! static text *pg_do_getviewdef(Oid viewoid);
  static void decompile_column_index_array(Datum column_index_array, Oid relId,
  							 StringInfo buf);
! static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
! static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
  static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
! 			  TupleDesc resultDesc);
  static void get_select_query_def(Query *query, deparse_context *context,
  					 TupleDesc resultDesc);
  static void get_insert_query_def(Query *query, deparse_context *context);
--- 144,166 ----
   * as a parameter, and append their text output to its contents.
   * ----------
   */
! static char *get_simple_binary_op_name(OpExpr *expr);
! static void appendStringInfoSpace(StringInfo buf, int count);
! static void appendContextKeyword(deparse_context *context, char *str, int indentBefore, int indentAfter, int indentPlus);
! static char *deparse_expression_pretty(Node *expr, List *dpcontext,
! 			  bool forceprefix, bool showimplicit, int prettyFlags, int startIndent);
! static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
! static text *pg_do_getviewdef(Oid viewoid, int prettyFlags);
  static void decompile_column_index_array(Datum column_index_array, Oid relId,
  							 StringInfo buf);
! static Datum pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
! static Datum pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags);
! static Datum pg_get_constraintdef_worker(Oid constraintId, int prettyFlags);
! static Datum pg_get_expr_worker(text *expr, Oid relid, char *relname, int prettyFlags);
! static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags);
! static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags);
  static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
! 			  TupleDesc resultDesc, int prettyFlags, int startIndent);
  static void get_select_query_def(Query *query, deparse_context *context,
  					 TupleDesc resultDesc);
  static void get_insert_query_def(Query *query, deparse_context *context);
***************
*** 184,189 ****
--- 215,236 ----
  pg_get_ruledef(PG_FUNCTION_ARGS)
  {
  	Oid			ruleoid = PG_GETARG_OID(0);
+ 	return pg_get_ruledef_worker(ruleoid, 0);
+ }
+ 
+ 
+ Datum
+ pg_get_ruledef_ext(PG_FUNCTION_ARGS)
+ {
+ 	Oid			ruleoid = PG_GETARG_OID(0);
+ 	int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
+ 	return pg_get_ruledef_worker(ruleoid, prettyFlags);
+ }
+ 
+ 
+ static Datum
+ pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
+ {
  	text	   *ruledef;
  	Datum		args[1];
  	char		nulls[1];
***************
*** 241,247 ****
  	 * Get the rules definition and put it into executors memory
  	 */
  	initStringInfo(&buf);
! 	make_ruledef(&buf, ruletup, rulettc);
  	len = buf.len + VARHDRSZ;
  	ruledef = SPI_palloc(len);
  	VARATT_SIZEP(ruledef) = len;
--- 288,294 ----
  	 * Get the rules definition and put it into executors memory
  	 */
  	initStringInfo(&buf);
! 	make_ruledef(&buf, ruletup, rulettc, prettyFlags);
  	len = buf.len + VARHDRSZ;
  	ruledef = SPI_palloc(len);
  	VARATT_SIZEP(ruledef) = len;
***************
*** 273,279 ****
  	Oid			viewoid = PG_GETARG_OID(0);
  	text	   *ruledef;
  
! 	ruledef = pg_do_getviewdef(viewoid);
  	PG_RETURN_TEXT_P(ruledef);
  }
  
--- 320,339 ----
  	Oid			viewoid = PG_GETARG_OID(0);
  	text	   *ruledef;
  
! 	ruledef = pg_do_getviewdef(viewoid, 0);
! 	PG_RETURN_TEXT_P(ruledef);
! }
! 
! 
! Datum
! pg_get_viewdef_ext(PG_FUNCTION_ARGS)
! {
! 	/* By OID */
! 	Oid			viewoid = PG_GETARG_OID(0);
! 	text	   *ruledef;
! 	int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
! 
! 	ruledef = pg_do_getviewdef(viewoid, prettyFlags);
  	PG_RETURN_TEXT_P(ruledef);
  }
  
***************
*** 290,296 ****
  														 "get_viewdef"));
  	viewoid = RangeVarGetRelid(viewrel, false);
  
! 	ruledef = pg_do_getviewdef(viewoid);
  	PG_RETURN_TEXT_P(ruledef);
  }
  
--- 350,375 ----
  														 "get_viewdef"));
  	viewoid = RangeVarGetRelid(viewrel, false);
  
! 	ruledef = pg_do_getviewdef(viewoid, 0);
! 	PG_RETURN_TEXT_P(ruledef);
! }
! 
! 
! Datum
! pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
! {
! 	/* By qualified name */
! 	text	   *viewname = PG_GETARG_TEXT_P(0);
! 	RangeVar   *viewrel;
! 	Oid			viewoid;
! 	text	   *ruledef;
! 	int             prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
! 
! 	viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname,
! 														 "get_viewdef"));
! 	viewoid = RangeVarGetRelid(viewrel, false);
! 
! 	ruledef = pg_do_getviewdef(viewoid, prettyFlags);
  	PG_RETURN_TEXT_P(ruledef);
  }
  
***************
*** 298,304 ****
   * Common code for by-OID and by-name variants of pg_get_viewdef
   */
  static text *
! pg_do_getviewdef(Oid viewoid)
  {
  	text	   *ruledef;
  	Datum		args[2];
--- 377,383 ----
   * Common code for by-OID and by-name variants of pg_get_viewdef
   */
  static text *
! pg_do_getviewdef(Oid viewoid, int prettyFlags)
  {
  	text	   *ruledef;
  	Datum		args[2];
***************
*** 353,359 ****
  		 */
  		ruletup = SPI_tuptable->vals[0];
  		rulettc = SPI_tuptable->tupdesc;
! 		make_viewdef(&buf, ruletup, rulettc);
  	}
  	len = buf.len + VARHDRSZ;
  	ruledef = SPI_palloc(len);
--- 432,438 ----
  		 */
  		ruletup = SPI_tuptable->vals[0];
  		rulettc = SPI_tuptable->tupdesc;
! 		make_viewdef(&buf, ruletup, rulettc, prettyFlags);
  	}
  	len = buf.len + VARHDRSZ;
  	ruledef = SPI_palloc(len);
***************
*** 527,532 ****
--- 606,626 ----
  pg_get_indexdef(PG_FUNCTION_ARGS)
  {
  	Oid			indexrelid = PG_GETARG_OID(0);
+ 	return pg_get_indexdef_worker(indexrelid, 0, 0);
+ }
+ 
+ Datum
+ pg_get_indexdef_ext(PG_FUNCTION_ARGS)
+ {
+ 	Oid			indexrelid = PG_GETARG_OID(0);
+ 	int        colno = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);
+ 	int        prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
+ 	return pg_get_indexdef_worker(indexrelid, colno, prettyFlags);
+ }
+ 
+ static Datum
+ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
+ {
  	text	   *indexdef;
  	HeapTuple	ht_idx;
  	HeapTuple	ht_idxrel;
***************
*** 582,587 ****
--- 676,683 ----
  	 * Get the index expressions, if any.  (NOTE: we do not use the relcache
  	 * versions of the expressions and predicate, because we want to display
  	 * non-const-folded expressions.)
+          * if colno == 0, we want a complete index definition.
+          * if colno > 0, we only want the nth expression.
  	 */
  	if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
  	{
***************
*** 607,613 ****
  	 * never be schema-qualified, but the indexed rel's name may be.
  	 */
  	initStringInfo(&buf);
! 	appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
  					 idxrec->indisunique ? "UNIQUE " : "",
  					 quote_identifier(NameStr(idxrelrec->relname)),
  					 generate_relation_name(indrelid),
--- 703,711 ----
  	 * never be schema-qualified, but the indexed rel's name may be.
  	 */
  	initStringInfo(&buf);
! 
! 	if (!colno)
! 	    appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
  					 idxrec->indisunique ? "UNIQUE " : "",
  					 quote_identifier(NameStr(idxrelrec->relname)),
  					 generate_relation_name(indrelid),
***************
*** 621,627 ****
  	{
  		AttrNumber	attnum = idxrec->indkey[keyno];
  
! 		appendStringInfo(&buf, sep);
  		sep = ", ";
  
  		if (attnum != 0)
--- 719,726 ----
  	{
  		AttrNumber	attnum = idxrec->indkey[keyno];
  
! 		if (!colno)
! 		    appendStringInfo(&buf, sep);
  		sep = ", ";
  
  		if (attnum != 0)
***************
*** 630,636 ****
  			char	   *attname;
  
  			attname = get_relid_attribute_name(indrelid, attnum);
! 			appendStringInfo(&buf, "%s", quote_identifier(attname));
  			keycoltype = get_atttype(indrelid, attnum);
  		}
  		else
--- 729,736 ----
  			char	   *attname;
  
  			attname = get_relid_attribute_name(indrelid, attnum);
! 			if (!colno || colno == keyno+1)
! 			    appendStringInfo(&buf, "%s", quote_identifier(attname));
  			keycoltype = get_atttype(indrelid, attnum);
  		}
  		else
***************
*** 643,672 ****
  			indexkey = (Node *) lfirst(indexprs);
  			indexprs = lnext(indexprs);
  			/* Deparse */
! 			str = deparse_expression(indexkey, context, false, false);
! 			/* Need parens if it's not a bare function call */
! 			if (indexkey && IsA(indexkey, FuncExpr) &&
  				((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
  				appendStringInfo(&buf, "%s", str);
! 			else
  				appendStringInfo(&buf, "(%s)", str);
  			keycoltype = exprType(indexkey);
  		}
  
  		/*
  		 * Add the operator class name
  		 */
! 		get_opclass_name(idxrec->indclass[keyno], keycoltype,
  						 &buf);
  	}
  
! 	appendStringInfoChar(&buf, ')');
! 
! 	/*
! 	 * If it's a partial index, decompile and append the predicate
! 	 */
! 	if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
  	{
  		Node	   *node;
  		Datum		predDatum;
  		bool		isnull;
--- 743,778 ----
  			indexkey = (Node *) lfirst(indexprs);
  			indexprs = lnext(indexprs);
  			/* Deparse */
! 			str = deparse_expression_pretty(indexkey, context, false, false, prettyFlags, 0);
! 			if (!colno || colno == keyno+1)
! 			{
! 			    /* Need parens if it's not a bare function call */
! 			    if (indexkey && IsA(indexkey, FuncExpr) &&
  				((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
  				appendStringInfo(&buf, "%s", str);
! 			    else
  				appendStringInfo(&buf, "(%s)", str);
+ 			}
  			keycoltype = exprType(indexkey);
  		}
  
  		/*
  		 * Add the operator class name
  		 */
! 		if (!colno)
! 		    get_opclass_name(idxrec->indclass[keyno], keycoltype,
  						 &buf);
  	}
  
! 	if (!colno)
  	{
+ 	    appendStringInfoChar(&buf, ')');
+ 
+ 	    /*
+ 	     * If it's a partial index, decompile and append the predicate
+ 	     */
+ 	    if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
+ 	    {
  		Node	   *node;
  		Datum		predDatum;
  		bool		isnull;
***************
*** 689,698 ****
  		if (node && IsA(node, List))
  			node = (Node *) make_ands_explicit((List *) node);
  		/* Deparse */
! 		str = deparse_expression(node, context, false, false);
  		appendStringInfo(&buf, " WHERE %s", str);
  	}
- 
  	/*
  	 * Create the result as a TEXT datum, and free working data
  	 */
--- 795,804 ----
  		if (node && IsA(node, List))
  			node = (Node *) make_ands_explicit((List *) node);
  		/* Deparse */
! 		str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0);
  		appendStringInfo(&buf, " WHERE %s", str);
+ 	    }
  	}
  	/*
  	 * Create the result as a TEXT datum, and free working data
  	 */
***************
*** 721,726 ****
--- 827,847 ----
  pg_get_constraintdef(PG_FUNCTION_ARGS)
  {
  	Oid			constraintId = PG_GETARG_OID(0);
+ 	return pg_get_constraintdef_worker(constraintId, 0);
+ }
+ 
+ Datum
+ pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
+ {
+ 	Oid			constraintId = PG_GETARG_OID(0);
+ 	int      prettyFlags = !PG_ARGISNULL(1) && PG_GETARG_BOOL(1) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
+ 	return pg_get_constraintdef_worker(constraintId, prettyFlags);
+ }
+ 
+ 
+ static Datum
+ pg_get_constraintdef_worker(Oid constraintId, int prettyFlags)
+ {
  	text	   *result;
  	StringInfoData buf;
  	int			len;
***************
*** 934,940 ****
  					context = deparse_context_for(get_typname(conForm->contypid),
  												  InvalidOid);
  
! 				consrc = deparse_expression(expr, context, false, false);
  
  				/* Append the constraint source */
  				appendStringInfoString(&buf, consrc); 
--- 1055,1061 ----
  					context = deparse_context_for(get_typname(conForm->contypid),
  												  InvalidOid);
  
! 				consrc = deparse_expression_pretty(expr, context, false, false, prettyFlags, 0);
  
  				/* Append the constraint source */
  				appendStringInfoString(&buf, consrc); 
***************
*** 1012,1031 ****
  Datum
  pg_get_expr(PG_FUNCTION_ARGS)
  {
- 	text	   *expr = PG_GETARG_TEXT_P(0);
- 	Oid			relid = PG_GETARG_OID(1);
- 	text	   *result;
- 	Node	   *node;
- 	List	   *context;
- 	char	   *exprstr;
  	char	   *relname;
! 	char	   *str;
  
  	/* Get the name for the relation */
  	relname = get_rel_name(relid);
  	if (relname == NULL)
  		PG_RETURN_NULL();		/* should we raise an error? */
  
  	/* Convert input TEXT object to C string */
  	exprstr = DatumGetCString(DirectFunctionCall1(textout,
  												  PointerGetDatum(expr)));
--- 1133,1176 ----
  Datum
  pg_get_expr(PG_FUNCTION_ARGS)
  {
  	char	   *relname;
! 	text	*expr = PG_GETARG_TEXT_P(0);
! 	Oid	relid = PG_GETARG_OID(1);
! 
! 	/* Get the name for the relation */
! 	relname = get_rel_name(relid);
! 	if (relname == NULL)
! 		PG_RETURN_NULL();		/* should we raise an error? */
! 
! 	return pg_get_expr_worker(expr, relid, relname, 0);
! }
! 
! Datum
! pg_get_expr_ext(PG_FUNCTION_ARGS)
! {
! 	char	   *relname;
! 	text	*expr = PG_GETARG_TEXT_P(0);
! 	Oid	relid = PG_GETARG_OID(1);
! 	int     prettyFlags = !PG_ARGISNULL(2) && PG_GETARG_BOOL(2) ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
  
  	/* Get the name for the relation */
  	relname = get_rel_name(relid);
  	if (relname == NULL)
  		PG_RETURN_NULL();		/* should we raise an error? */
  
+ 
+ 	return pg_get_expr_worker(expr, relid, relname, prettyFlags);
+ }
+ 
+ static Datum
+ pg_get_expr_worker(text *expr, Oid relid, char *relname, int prettyFlags)
+ {
+ 	text	   *result;
+ 	Node	   *node;
+ 	List	   *context;
+ 	char	   *exprstr;
+ 	char	   *str;
+ 
  	/* Convert input TEXT object to C string */
  	exprstr = DatumGetCString(DirectFunctionCall1(textout,
  												  PointerGetDatum(expr)));
***************
*** 1043,1049 ****
  
  	/* Deparse */
  	context = deparse_context_for(relname, relid);
! 	str = deparse_expression(node, context, false, false);
  
  	/* Pass the result back as TEXT */
  	result = DatumGetTextP(DirectFunctionCall1(textin,
--- 1188,1194 ----
  
  	/* Deparse */
  	context = deparse_context_for(relname, relid);
! 	str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0);
  
  	/* Pass the result back as TEXT */
  	result = DatumGetTextP(DirectFunctionCall1(textin,
***************
*** 1092,1097 ****
--- 1237,1253 ----
  
  /* ----------
   * deparse_expression			- General utility for deparsing expressions
+  * calls deparse_expression_pretty with all prettyPrinting disabled
+  */
+ char *
+ deparse_expression(Node *expr, List *dpcontext,
+ 		   bool forceprefix, bool showimplicit)
+ {
+     return deparse_expression_pretty(expr, dpcontext, forceprefix, showimplicit, 0, 0);
+ }
+ 
+ /* ----------
+  * deparse_expression_pretty			- General utility for deparsing expressions
   *
   * expr is the node tree to be deparsed.  It must be a transformed expression
   * tree (ie, not the raw output of gram.y).
***************
*** 1102,1114 ****
   * forceprefix is TRUE to force all Vars to be prefixed with their table names.
   *
   * showimplicit is TRUE to force all implicit casts to be shown explicitly.
   *
   * The result is a palloc'd string.
   * ----------
   */
  char *
! deparse_expression(Node *expr, List *dpcontext,
! 				   bool forceprefix, bool showimplicit)
  {
  	StringInfoData buf;
  	deparse_context context;
--- 1258,1272 ----
   * forceprefix is TRUE to force all Vars to be prefixed with their table names.
   *
   * showimplicit is TRUE to force all implicit casts to be shown explicitly.
+  * 
+  * tries to pretty up the output according to prettyFlags
   *
   * The result is a palloc'd string.
   * ----------
   */
  char *
! deparse_expression_pretty(Node *expr, List *dpcontext,
! 				   bool forceprefix, bool showimplicit, int prettyFlags, int startIndent)
  {
  	StringInfoData buf;
  	deparse_context context;
***************
*** 1117,1122 ****
--- 1275,1282 ----
  	context.buf = &buf;
  	context.namespaces = dpcontext;
  	context.varprefix = forceprefix;
+ 	context.prettyFlags = prettyFlags;
+ 	context.indentLevel = startIndent;
  
  	get_rule_expr(expr, &context, showimplicit);
  
***************
*** 1269,1275 ****
   * ----------
   */
  static void
! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
  {
  	char	   *rulename;
  	char		ev_type;
--- 1429,1435 ----
   * ----------
   */
  static void
! make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
  {
  	char	   *rulename;
  	char		ev_type;
***************
*** 1323,1331 ****
  	/*
  	 * Build the rules definition text
  	 */
! 	appendStringInfo(buf, "CREATE RULE %s AS ON ",
  					 quote_identifier(rulename));
  
  	/* The event the rule is fired for */
  	switch (ev_type)
  	{
--- 1483,1496 ----
  	/*
  	 * Build the rules definition text
  	 */
! 	appendStringInfo(buf, "CREATE RULE %s AS",
  					 quote_identifier(rulename));
  
+ 	if (prettyFlags & PRETTYFLAG_INDENT)
+ 	    appendStringInfoString(buf, "\n    ON ");
+ 	else
+ 	    appendStringInfoString(buf, "ON ");
+ 
  	/* The event the rule is fired for */
  	switch (ev_type)
  	{
***************
*** 1370,1375 ****
--- 1535,1542 ----
  		deparse_context context;
  		deparse_namespace dpns;
  
+ 		if (prettyFlags & PRETTYFLAG_INDENT)
+ 		    appendStringInfoString(buf, "\n  ");
  		appendStringInfo(buf, " WHERE ");
  
  		qual = stringToNode(ev_qual);
***************
*** 1391,1396 ****
--- 1558,1565 ----
  		context.buf = buf;
  		context.namespaces = makeList1(&dpns);
  		context.varprefix = (length(query->rtable) != 1);
+ 		context.prettyFlags = prettyFlags;
+ 		context.indentLevel = PRETTYINDENT_STD;
  		dpns.rtable = query->rtable;
  		dpns.outer_varno = dpns.inner_varno = 0;
  		dpns.outer_rte = dpns.inner_rte = NULL;
***************
*** 1414,1421 ****
  		foreach(action, actions)
  		{
  			query = (Query *) lfirst(action);
! 			get_query_def(query, buf, NIL, NULL);
! 			appendStringInfo(buf, "; ");
  		}
  		appendStringInfo(buf, ");");
  	}
--- 1583,1593 ----
  		foreach(action, actions)
  		{
  			query = (Query *) lfirst(action);
! 			get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
! 			if (prettyFlags)
! 			    appendStringInfo(buf, ";\n");
! 			else
! 			    appendStringInfo(buf, "; ");
  		}
  		appendStringInfo(buf, ");");
  	}
***************
*** 1428,1434 ****
  		Query	   *query;
  
  		query = (Query *) lfirst(actions);
! 		get_query_def(query, buf, NIL, NULL);
  		appendStringInfo(buf, ";");
  	}
  }
--- 1600,1606 ----
  		Query	   *query;
  
  		query = (Query *) lfirst(actions);
! 		get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
  		appendStringInfo(buf, ";");
  	}
  }
***************
*** 1440,1446 ****
   * ----------
   */
  static void
! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
  {
  	Query	   *query;
  	char		ev_type;
--- 1612,1618 ----
   * ----------
   */
  static void
! make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags)
  {
  	Query	   *query;
  	char		ev_type;
***************
*** 1494,1500 ****
  
  	ev_relation = heap_open(ev_class, AccessShareLock);
  
! 	get_query_def(query, buf, NIL, RelationGetDescr(ev_relation));
  	appendStringInfo(buf, ";");
  
  	heap_close(ev_relation, AccessShareLock);
--- 1666,1672 ----
  
  	ev_relation = heap_open(ev_class, AccessShareLock);
  
! 	get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), prettyFlags, 0);
  	appendStringInfo(buf, ";");
  
  	heap_close(ev_relation, AccessShareLock);
***************
*** 1510,1516 ****
   */
  static void
  get_query_def(Query *query, StringInfo buf, List *parentnamespace,
! 			  TupleDesc resultDesc)
  {
  	deparse_context context;
  	deparse_namespace dpns;
--- 1682,1688 ----
   */
  static void
  get_query_def(Query *query, StringInfo buf, List *parentnamespace,
! 			  TupleDesc resultDesc, int prettyFlags, int startIndent)
  {
  	deparse_context context;
  	deparse_namespace dpns;
***************
*** 1519,1524 ****
--- 1691,1699 ----
  	context.namespaces = lcons(&dpns, parentnamespace);
  	context.varprefix = (parentnamespace != NIL ||
  						 length(query->rtable) != 1);
+ 	context.prettyFlags = prettyFlags;
+ 	context.indentLevel = startIndent;
+ 
  	dpns.rtable = query->rtable;
  	dpns.outer_varno = dpns.inner_varno = 0;
  	dpns.outer_rte = dpns.inner_rte = NULL;
***************
*** 1590,1596 ****
  	/* Add the ORDER BY clause if given */
  	if (query->sortClause != NIL)
  	{
! 		appendStringInfo(buf, " ORDER BY ");
  		sep = "";
  		foreach(l, query->sortClause)
  		{
--- 1765,1771 ----
  	/* Add the ORDER BY clause if given */
  	if (query->sortClause != NIL)
  	{
! 	        appendContextKeyword(context, " ORDER BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
  		sep = "";
  		foreach(l, query->sortClause)
  		{
***************
*** 1619,1630 ****
  	/* Add the LIMIT clause if given */
  	if (query->limitOffset != NULL)
  	{
! 		appendStringInfo(buf, " OFFSET ");
  		get_rule_expr(query->limitOffset, context, false);
  	}
  	if (query->limitCount != NULL)
  	{
! 		appendStringInfo(buf, " LIMIT ");
  		if (IsA(query->limitCount, Const) &&
  			((Const *) query->limitCount)->constisnull)
  			appendStringInfo(buf, "ALL");
--- 1794,1805 ----
  	/* Add the LIMIT clause if given */
  	if (query->limitOffset != NULL)
  	{
! 		appendContextKeyword(context, " OFFSET ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
  		get_rule_expr(query->limitOffset, context, false);
  	}
  	if (query->limitCount != NULL)
  	{
! 		appendContextKeyword(context, " LIMIT ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
  		if (IsA(query->limitCount, Const) &&
  			((Const *) query->limitCount)->constisnull)
  			appendStringInfo(buf, "ALL");
***************
*** 1645,1650 ****
--- 1820,1830 ----
  	/*
  	 * Build up the query string - first we say SELECT
  	 */
+ 	if (PRETTY_INDENT(context))
+ 	{
+ 	    context->indentLevel += PRETTYINDENT_STD;
+ 	    appendStringInfoChar(buf, ' ');
+ 	}
  	appendStringInfo(buf, "SELECT");
  
  	/* Add the DISTINCT clause if given */
***************
*** 1724,1737 ****
  	/* Add the WHERE clause if given */
  	if (query->jointree->quals != NULL)
  	{
! 		appendStringInfo(buf, " WHERE ");
  		get_rule_expr(query->jointree->quals, context, false);
  	}
  
  	/* Add the GROUP BY clause if given */
  	if (query->groupClause != NULL)
  	{
! 		appendStringInfo(buf, " GROUP BY ");
  		sep = "";
  		foreach(l, query->groupClause)
  		{
--- 1904,1917 ----
  	/* Add the WHERE clause if given */
  	if (query->jointree->quals != NULL)
  	{
! 		appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
  		get_rule_expr(query->jointree->quals, context, false);
  	}
  
  	/* Add the GROUP BY clause if given */
  	if (query->groupClause != NULL)
  	{
! 		appendContextKeyword(context, " GROUP BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
  		sep = "";
  		foreach(l, query->groupClause)
  		{
***************
*** 1747,1753 ****
  	/* Add the HAVING clause if given */
  	if (query->havingQual != NULL)
  	{
! 		appendStringInfo(buf, " HAVING ");
  		get_rule_expr(query->havingQual, context, false);
  	}
  }
--- 1927,1933 ----
  	/* Add the HAVING clause if given */
  	if (query->havingQual != NULL)
  	{
! 		appendContextKeyword(context, " HAVING ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
  		get_rule_expr(query->havingQual, context, false);
  	}
  }
***************
*** 1765,1799 ****
  		Query	   *subquery = rte->subquery;
  
  		Assert(subquery != NULL);
! 		get_query_def(subquery, buf, context->namespaces, resultDesc);
  	}
  	else if (IsA(setOp, SetOperationStmt))
  	{
  		SetOperationStmt *op = (SetOperationStmt *) setOp;
  
- 		appendStringInfo(buf, "((");
  		get_setop_query(op->larg, query, context, resultDesc);
  		switch (op->op)
  		{
  			case SETOP_UNION:
! 				appendStringInfo(buf, ") UNION ");
  				break;
  			case SETOP_INTERSECT:
! 				appendStringInfo(buf, ") INTERSECT ");
  				break;
  			case SETOP_EXCEPT:
! 				appendStringInfo(buf, ") EXCEPT ");
  				break;
  			default:
  				elog(ERROR, "unrecognized set op: %d",
  					 (int) op->op);
  		}
  		if (op->all)
! 			appendStringInfo(buf, "ALL (");
  		else
! 			appendStringInfo(buf, "(");
  		get_setop_query(op->rarg, query, context, resultDesc);
! 		appendStringInfo(buf, "))");
  	}
  	else
  	{
--- 1945,2008 ----
  		Query	   *subquery = rte->subquery;
  
  		Assert(subquery != NULL);
! 		get_query_def(subquery, buf, context->namespaces, resultDesc, context->prettyFlags, context->indentLevel);
  	}
  	else if (IsA(setOp, SetOperationStmt))
  	{
  		SetOperationStmt *op = (SetOperationStmt *) setOp;
+ 		bool need_paren=(PRETTY_PAREN(context) ? !IsA(op->rarg, RangeTblRef) : true);
+ 
+ 		if (!PRETTY_PAREN(context))
+ 		    appendStringInfoString(buf, "((");
  
  		get_setop_query(op->larg, query, context, resultDesc);
+ 
+ 		if (!PRETTY_PAREN(context))
+ 		    appendStringInfoChar(buf, ')');
+ 		if (!PRETTY_INDENT(context))
+ 		    appendStringInfoChar(buf, ' ');
  		switch (op->op)
  		{
  			case SETOP_UNION:
! 				appendContextKeyword(context, "UNION ", -PRETTYINDENT_STD, 0, 0);
  				break;
  			case SETOP_INTERSECT:
! 				appendContextKeyword(context, "INTERSECT ", -PRETTYINDENT_STD, 0, 0);
  				break;
  			case SETOP_EXCEPT:
! 				appendContextKeyword(context, "EXCEPT ", -PRETTYINDENT_STD, 0, 0);
  				break;
  			default:
  				elog(ERROR, "unrecognized set op: %d",
  					 (int) op->op);
  		}
  		if (op->all)
! 			appendStringInfo(buf, "ALL ");
! 
! 		if (PRETTY_INDENT(context))
! 		    appendStringInfoChar(buf, '\n');
! 
! 		if (PRETTY_PAREN(context))
! 		{
! 		    if (need_paren)
! 		    {
! 			appendStringInfoChar(buf, '(');
! 			if (PRETTY_INDENT(context))
! 			    appendStringInfoChar(buf, '\n');
! 		    }
! 		}
  		else
! 		    appendStringInfoChar(buf, '(');
! 
  		get_setop_query(op->rarg, query, context, resultDesc);
! 
! 		if (PRETTY_PAREN(context))
! 		{
! 		    if (need_paren)
! 			appendStringInfoChar(buf, ')');
! 		}
! 		else
! 		    appendStringInfoString(buf, "))");
  	}
  	else
  	{
***************
*** 1866,1871 ****
--- 2075,2086 ----
  	 */
  	rte = rt_fetch(query->resultRelation, query->rtable);
  	Assert(rte->rtekind == RTE_RELATION);
+ 
+ 	if (PRETTY_INDENT(context))
+ 	{
+ 	    context->indentLevel += PRETTYINDENT_STD;
+ 	    appendStringInfoChar(buf, ' ');
+ 	}
  	appendStringInfo(buf, "INSERT INTO %s",
  					 generate_relation_name(rte->relid));
  
***************
*** 1887,1893 ****
  	/* Add the VALUES or the SELECT */
  	if (select_rte == NULL)
  	{
! 		appendStringInfo(buf, "VALUES (");
  		sep = "";
  		foreach(l, query->targetList)
  		{
--- 2102,2108 ----
  	/* Add the VALUES or the SELECT */
  	if (select_rte == NULL)
  	{
! 		appendContextKeyword(context, "VALUES (", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
  		sep = "";
  		foreach(l, query->targetList)
  		{
***************
*** 1903,1909 ****
  		appendStringInfoChar(buf, ')');
  	}
  	else
! 		get_query_def(select_rte->subquery, buf, NIL, NULL);
  }
  
  
--- 2118,2124 ----
  		appendStringInfoChar(buf, ')');
  	}
  	else
! 		get_query_def(select_rte->subquery, buf, NIL, NULL, context->prettyFlags, context->indentLevel);
  }
  
  
***************
*** 1924,1929 ****
--- 2139,2149 ----
  	 */
  	rte = rt_fetch(query->resultRelation, query->rtable);
  	Assert(rte->rtekind == RTE_RELATION);
+ 	if (PRETTY_INDENT(context))
+ 	{
+ 	    appendStringInfoChar(buf, ' ');
+ 	    context->indentLevel += PRETTYINDENT_STD;
+ 	}
  	appendStringInfo(buf, "UPDATE %s%s SET ",
  					 only_marker(rte),
  					 generate_relation_name(rte->relid));
***************
*** 1957,1963 ****
  	/* Finally add a WHERE clause if given */
  	if (query->jointree->quals != NULL)
  	{
! 		appendStringInfo(buf, " WHERE ");
  		get_rule_expr(query->jointree->quals, context, false);
  	}
  }
--- 2177,2183 ----
  	/* Finally add a WHERE clause if given */
  	if (query->jointree->quals != NULL)
  	{
! 		appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
  		get_rule_expr(query->jointree->quals, context, false);
  	}
  }
***************
*** 1978,1983 ****
--- 2198,2208 ----
  	 */
  	rte = rt_fetch(query->resultRelation, query->rtable);
  	Assert(rte->rtekind == RTE_RELATION);
+ 	if (PRETTY_INDENT(context))
+ 	{
+ 	    context->indentLevel += PRETTYINDENT_STD;
+ 	    appendStringInfoChar(buf, ' ');
+ 	}
  	appendStringInfo(buf, "DELETE FROM %s%s",
  					 only_marker(rte),
  					 generate_relation_name(rte->relid));
***************
*** 1985,1991 ****
  	/* Add a WHERE clause if given */
  	if (query->jointree->quals != NULL)
  	{
! 		appendStringInfo(buf, " WHERE ");
  		get_rule_expr(query->jointree->quals, context, false);
  	}
  }
--- 2210,2216 ----
  	/* Add a WHERE clause if given */
  	if (query->jointree->quals != NULL)
  	{
! 		appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
  		get_rule_expr(query->jointree->quals, context, false);
  	}
  }
***************
*** 2004,2009 ****
--- 2229,2235 ----
  	{
  		NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
  
+ 		appendContextKeyword(context, "", 0, PRETTYINDENT_STD, 1);
  		appendStringInfo(buf, "NOTIFY %s",
  				   quote_qualified_identifier(stmt->relation->schemaname,
  											  stmt->relation->relname));
***************
*** 2145,2150 ****
--- 2371,2612 ----
  }
  
  
+ /********************************************
+  * get_simple_binary_op_name
+  * helper function for isSimpleNode
+  * will return single char binary operator
+  *******************************************/
+ 
+ static char *get_simple_binary_op_name(OpExpr *expr)
+ {
+ 	List	   *args = expr->args;
+ 
+ 	if (length(args) == 2)
+ 	{
+ 		/* binary operator */
+ 		Node	   *arg1 = (Node *) lfirst(args);
+ 		Node	   *arg2 = (Node *) lsecond(args);
+ 		char *op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
+ 
+ 		if (strlen(op) == 1)
+ 		    return op;
+ 	}
+ 	return 0;
+ }
+ 
+ 
+ /***************************************
+  * check if given node is simple.
+  *  false  : not simple
+  *  true   : simple in the context of parent node's type
+  ***************************************/
+ 
+ static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
+ {
+     if (!node)
+ 	return true;
+ 
+     switch (nodeTag(node))
+     {
+ 	// single words: always simple
+ 	case T_Var:
+ 	case T_Const:
+ 	case T_Param:
+ 
+ 	// function-like: name(..) or name[..]
+ 	case T_ArrayRef:
+ 	case T_ArrayExpr:
+ 	case T_CoalesceExpr:
+ 	case T_NullIfExpr:
+ 	case T_Aggref:
+ 	case T_FuncExpr:
+ 
+         // CASE keywords act as parentheses
+ 	case T_CaseExpr:
+ 	    return true;
+ 
+         // appears simple since . has top precedence, unless parent is T_FieldSelect itself!
+ 	case T_FieldSelect:
+ 	    return (nodeTag(parentNode) == T_FieldSelect ? false : true);
+ 
+ 
+         // maybe simple, check args
+ 	case T_CoerceToDomain:
+ 	    return isSimpleNode((Node*) ((CoerceToDomain*)node)->arg, node, prettyFlags);
+ 	case T_RelabelType:
+ 	    return isSimpleNode((Node*) ((RelabelType*)node)->arg, node, prettyFlags);
+ 
+ 
+ 	// depends on parent node type; needs further checking
+ 	case T_OpExpr:
+ 	{
+ 	    if (prettyFlags & PRETTYFLAG_PAREN && nodeTag(parentNode) == T_OpExpr)
+ 	    {
+ 		char *op=get_simple_binary_op_name((OpExpr*)node);
+ 		char *parentOp=get_simple_binary_op_name((OpExpr*)parentNode);
+ 		if (!op || !parentOp)
+ 		    return false;
+ 
+                 // we know only these basic operators
+ 		if (!strchr("+-*/%", *op) || !strchr("+-*/%", *parentOp))
+ 		    return false;
+ 
+ 		// natural operator precedence, so we don't need parentheses
+ 		if (strchr("*/%", *op) || strchr("+-", *parentOp))
+ 		    return true;
+ 
+ 		return false;
+ 	    }
+             // else do the same stuff as for T_SubLink et al.
+ 	}
+ 	case T_SubLink:
+ 	case T_NullTest:
+ 	case T_BooleanTest:
+ 	case T_DistinctExpr:
+ 	{
+ 	    switch (nodeTag(parentNode))
+ 	    {
+ 		case T_FuncExpr:
+ 		{
+ 		    // special handling for casts
+ 		    CoercionForm type=((FuncExpr*)parentNode)->funcformat;
+ 		    if (type == COERCE_EXPLICIT_CAST ||	type == COERCE_IMPLICIT_CAST)
+ 			return false;
+                     return true;      // own parentheses
+ 		}
+ 		case T_BoolExpr:      // lower precedence
+ 		case T_ArrayRef:      // other separators
+ 		case T_ArrayExpr:     // other separators
+ 		case T_CoalesceExpr:  // own parentheses
+ 		case T_NullIfExpr:    // other separators
+ 		case T_Aggref:        // own parentheses
+ 		case T_CaseExpr:      // other separators
+ 		    return true;
+ 		default:
+ 		    return false;
+ 	    }
+ 	}
+ 	case T_BoolExpr:
+ 	    switch (nodeTag(parentNode))
+ 	    {
+ 		case T_BoolExpr:
+ 		    if (prettyFlags & PRETTYFLAG_PAREN)
+ 		    {
+ 			BoolExprType type=((BoolExpr*)node)->boolop;
+ 			BoolExprType parentType=((BoolExpr*)parentNode)->boolop;
+ 			switch (type)
+ 			{
+ 			    case NOT_EXPR:
+ 			    case AND_EXPR:
+ 				if (parentType == AND_EXPR || parentType == OR_EXPR)
+ 				    return true;
+ 				break;
+ 			    case OR_EXPR:
+ 				if (parentType == OR_EXPR)
+ 				    return true;
+ 				break;
+ 			}
+ 		    }
+ 		    return false;
+ 		case T_FuncExpr:
+ 		{
+ 		    // special handling for casts
+ 		    CoercionForm type=((FuncExpr*)parentNode)->funcformat;
+ 		    if (type == COERCE_EXPLICIT_CAST ||	type == COERCE_IMPLICIT_CAST)
+ 			return false;
+                     return true;      // own parentheses
+ 		}
+ 		case T_ArrayRef:      // other separators
+ 		case T_ArrayExpr:     // other separators
+ 		case T_CoalesceExpr:  // own parentheses
+ 		case T_NullIfExpr:    // other separators
+ 		case T_Aggref:        // own parentheses
+ 		case T_CaseExpr:      // other separators
+ 		    return true;
+ 		default:
+ 		    return false;
+ 	    }
+         // these are not completely implemented; so far, they're simple
+ 	case T_SubPlan:
+ 	case T_CoerceToDomainValue:
+ 	    return true;
+ 
+ 	case T_ScalarArrayOpExpr:
+         // need to check
+ 	default:
+ 	    break;
+     }
+     // those we don't know: in dubio complexo
+     return false;
+ }
+ 
+ 
+ /******************************************
+  * appendContextKeyword
+  * append spaces to buffer
+  ******************************************/
+ static void appendStringInfoSpace(StringInfo buf, int count)
+ {
+     while (count-- > 0)
+ 	appendStringInfoChar(buf, ' ');
+ }
+ 
+ /******************************************
+  * appendContextKeyword
+  * performing a line break, and indentation
+  * if prettyPrint is enabled.
+  * Otherwise, only the keyword is appended
+  *****************************************/
+ 
+ static void appendContextKeyword(deparse_context *context, char *str, int indentBefore, int indentAfter, int indentPlus)
+ {
+     if (PRETTY_INDENT(context))
+     {
+ 	context->indentLevel += indentBefore;
+ 	if (context->indentLevel < 0)
+ 	    context->indentLevel=0;
+ 
+ 	appendStringInfoChar(context->buf, '\n');
+ 	appendStringInfoSpace(context->buf, context->indentLevel + indentPlus);
+     }
+ 
+     appendStringInfoString(context->buf, str);
+ 
+     if (PRETTY_INDENT(context))
+     {
+ 	context->indentLevel += indentAfter;
+ 	if (context->indentLevel < 0)
+ 	    context->indentLevel=0;
+     }
+ }
+ 
+ 
+ /*
+  * get_rule_expr_paren  - parsing expr using get_rule_expr, 
+  * embracing the string with parentheses if necessary for prettyPrint.
+  * never embracing if prettyFlags=0, because it's done in the calling node.
+  *
+  * Any node that does *not* embrace its argument node by sql syntax (with parentheses, non-operator keywords 
+  * like CASE/WHEN/ON, or comma etc) should use get_rule_expr_paren instead of get_rule_expr 
+  * so parentheses can be added.
+  */
+ 
+ static void
+ get_rule_expr_paren(Node *node, deparse_context *context, 
+ 		    bool showimplicit, Node *parentNode)
+ {
+ 	bool need_paren = PRETTY_PAREN(context) && !isSimpleNode(node, parentNode, context->prettyFlags);
+ 
+ 	if (need_paren)
+ 	    appendStringInfoChar(context->buf, '(');
+ 
+ 	get_rule_expr(node, context, showimplicit);
+ 
+ 	if (need_paren)
+ 	    appendStringInfoChar(context->buf, ')');
+ }
+ 
+ 
  /* ----------
   * get_rule_expr			- Parse back an expression
   *
***************
*** 2299,2310 ****
  				List	   *args = expr->args;
  				Node	   *arg1 = (Node *) lfirst(args);
  				Node	   *arg2 = (Node *) lsecond(args);
! 
! 				appendStringInfoChar(buf, '(');
! 				get_rule_expr(arg1, context, true);
  				appendStringInfo(buf, " IS DISTINCT FROM ");
! 				get_rule_expr(arg2, context, true);
! 				appendStringInfoChar(buf, ')');
  			}
  			break;
  
--- 2761,2773 ----
  				List	   *args = expr->args;
  				Node	   *arg1 = (Node *) lfirst(args);
  				Node	   *arg2 = (Node *) lsecond(args);
! 				if (!PRETTY_PAREN(context))
! 				    appendStringInfoChar(buf, '(');
! 				get_rule_expr_paren(arg1, context, true, node);
  				appendStringInfo(buf, " IS DISTINCT FROM ");
! 				get_rule_expr_paren(arg2, context, true, node);
! 				if (!PRETTY_PAREN(context))
! 				    appendStringInfoChar(buf, ')');
  			}
  			break;
  
***************
*** 2315,2329 ****
  				Node	   *arg1 = (Node *) lfirst(args);
  				Node	   *arg2 = (Node *) lsecond(args);
  
! 				appendStringInfoChar(buf, '(');
! 				get_rule_expr(arg1, context, true);
  				appendStringInfo(buf, " %s %s (",
  								 generate_operator_name(expr->opno,
  														exprType(arg1),
  										get_element_type(exprType(arg2))),
  								 expr->useOr ? "ANY" : "ALL");
! 				get_rule_expr(arg2, context, true);
! 				appendStringInfo(buf, "))");
  			}
  			break;
  
--- 2778,2796 ----
  				Node	   *arg1 = (Node *) lfirst(args);
  				Node	   *arg2 = (Node *) lsecond(args);
  
! 				if (!PRETTY_PAREN(context))
! 				    appendStringInfoChar(buf, '(');
! 				get_rule_expr_paren(arg1, context, true, node);
  				appendStringInfo(buf, " %s %s (",
  								 generate_operator_name(expr->opno,
  														exprType(arg1),
  										get_element_type(exprType(arg2))),
  								 expr->useOr ? "ANY" : "ALL");
! 				get_rule_expr_paren(arg2, context, true, node);
! 				appendStringInfoString(buf, ")");
! 
! 				if (!PRETTY_PAREN(context))
! 				    appendStringInfoChar(buf, ')');
  			}
  			break;
  
***************
*** 2335,2367 ****
  				switch (expr->boolop)
  				{
  					case AND_EXPR:
! 						appendStringInfoChar(buf, '(');
! 						get_rule_expr((Node *) lfirst(args), context, false);
  						while ((args = lnext(args)) != NIL)
  						{
  							appendStringInfo(buf, " AND ");
! 							get_rule_expr((Node *) lfirst(args), context,
! 										  false);
  						}
! 						appendStringInfoChar(buf, ')');
  						break;
  
  					case OR_EXPR:
! 						appendStringInfoChar(buf, '(');
! 						get_rule_expr((Node *) lfirst(args), context, false);
  						while ((args = lnext(args)) != NIL)
  						{
  							appendStringInfo(buf, " OR ");
! 							get_rule_expr((Node *) lfirst(args), context,
! 										  false);
  						}
! 						appendStringInfoChar(buf, ')');
  						break;
  
  					case NOT_EXPR:
! 						appendStringInfo(buf, "(NOT ");
! 						get_rule_expr((Node *) lfirst(args), context, false);
! 						appendStringInfoChar(buf, ')');
  						break;
  
  					default:
--- 2802,2841 ----
  				switch (expr->boolop)
  				{
  					case AND_EXPR:
! 					        if (!PRETTY_PAREN(context))
! 						    appendStringInfoChar(buf, '(');
! 						get_rule_expr_paren((Node *) lfirst(args), context, false, node);
  						while ((args = lnext(args)) != NIL)
  						{
  							appendStringInfo(buf, " AND ");
! 							get_rule_expr_paren((Node *) lfirst(args), context,
! 										  false, node);
  						}
! 					        if (!PRETTY_PAREN(context))
! 						    appendStringInfoChar(buf, ')');
  						break;
  
  					case OR_EXPR:
! 					        if (!PRETTY_PAREN(context))
! 						    appendStringInfoChar(buf, '(');
! 						get_rule_expr_paren((Node *) lfirst(args), context, false, node);
  						while ((args = lnext(args)) != NIL)
  						{
  							appendStringInfo(buf, " OR ");
! 							get_rule_expr_paren((Node *) lfirst(args), context,
! 										  false, node);
  						}
! 					        if (!PRETTY_PAREN(context))
! 						    appendStringInfoChar(buf, ')');
  						break;
  
  					case NOT_EXPR:
! 					        if (!PRETTY_PAREN(context))
! 						    appendStringInfoChar(buf, '(');
! 						appendStringInfo(buf, "NOT ");
! 						get_rule_expr_paren((Node *) lfirst(args), context, false, node);
! 					        if (!PRETTY_PAREN(context))
! 						    appendStringInfoChar(buf, ')');
  						break;
  
  					default:
***************
*** 2409,2417 ****
  				 * arg.fieldname, but most cases where FieldSelect is used
  				 * are *not* simple.  So, always use parenthesized syntax.
  				 */
! 				appendStringInfoChar(buf, '(');
! 				get_rule_expr((Node *) fselect->arg, context, true);
! 				appendStringInfo(buf, ").%s", quote_identifier(fieldname));
  			}
  			break;
  
--- 2883,2894 ----
  				 * arg.fieldname, but most cases where FieldSelect is used
  				 * are *not* simple.  So, always use parenthesized syntax.
  				 */
! 			        if (!PRETTY_PAREN(context))
! 				    appendStringInfoChar(buf, '(');
! 				get_rule_expr_paren((Node *) fselect->arg, context, true, node);
! 			        if (!PRETTY_PAREN(context))
! 				    appendStringInfoChar(buf, ')');
! 				appendStringInfo(buf, ".%s", quote_identifier(fieldname));
  			}
  			break;
  
***************
*** 2424,2430 ****
  					!showimplicit)
  				{
  					/* don't show the implicit cast */
! 					get_rule_expr(arg, context, showimplicit);
  				}
  				else
  				{
--- 2901,2907 ----
  					!showimplicit)
  				{
  					/* don't show the implicit cast */
! 					get_rule_expr_paren(arg, context, showimplicit, node);
  				}
  				else
  				{
***************
*** 2436,2444 ****
  					 */
  					arg = strip_type_coercion(arg, relabel->resulttype);
  
! 					appendStringInfoChar(buf, '(');
! 					get_rule_expr(arg, context, showimplicit);
! 					appendStringInfo(buf, ")::%s",
  							format_type_with_typemod(relabel->resulttype,
  													 relabel->resulttypmod));
  				}
--- 2913,2925 ----
  					 */
  					arg = strip_type_coercion(arg, relabel->resulttype);
  
! 					if (!PRETTY_PAREN(context))
! 					    appendStringInfoChar(buf, '(');
! 
! 					get_rule_expr_paren(arg, context, showimplicit, node);
! 					if (!PRETTY_PAREN(context))
! 					    appendStringInfoChar(buf, ')');
! 					appendStringInfo(buf, "::%s",
  							format_type_with_typemod(relabel->resulttype,
  													 relabel->resulttypmod));
  				}
***************
*** 2450,2468 ****
  				CaseExpr   *caseexpr = (CaseExpr *) node;
  				List	   *temp;
  
! 				appendStringInfo(buf, "CASE");
  				foreach(temp, caseexpr->args)
  				{
  					CaseWhen   *when = (CaseWhen *) lfirst(temp);
  
! 					appendStringInfo(buf, " WHEN ");
  					get_rule_expr((Node *) when->expr, context, false);
  					appendStringInfo(buf, " THEN ");
  					get_rule_expr((Node *) when->result, context, true);
  				}
! 				appendStringInfo(buf, " ELSE ");
  				get_rule_expr((Node *) caseexpr->defresult, context, true);
! 				appendStringInfo(buf, " END");
  			}
  			break;
  
--- 2931,2957 ----
  				CaseExpr   *caseexpr = (CaseExpr *) node;
  				List	   *temp;
  
! 				appendContextKeyword(context, "CASE", 0, PRETTYINDENT_VAR, 0);
  				foreach(temp, caseexpr->args)
  				{
  					CaseWhen   *when = (CaseWhen *) lfirst(temp);
  
! 					if (!PRETTY_INDENT(context))
! 					    appendStringInfoChar(buf, ' ');
! 
! 					appendContextKeyword(context, "WHEN ", 0, 0, 0);
  					get_rule_expr((Node *) when->expr, context, false);
+ 
  					appendStringInfo(buf, " THEN ");
  					get_rule_expr((Node *) when->result, context, true);
  				}
! 				if (!PRETTY_INDENT(context))
! 				    appendStringInfoChar(buf, ' ');
! 				appendContextKeyword(context, "ELSE ", 0, 0, 0);
  				get_rule_expr((Node *) caseexpr->defresult, context, true);
! 				if (!PRETTY_INDENT(context))
! 				    appendStringInfoChar(buf, ' ');
! 				appendContextKeyword(context, "END", -PRETTYINDENT_VAR, 0, 0);
  			}
  			break;
  
***************
*** 2530,2549 ****
  			{
  				NullTest   *ntest = (NullTest *) node;
  
! 				appendStringInfo(buf, "(");
! 				get_rule_expr((Node *) ntest->arg, context, true);
  				switch (ntest->nulltesttype)
  				{
  					case IS_NULL:
! 						appendStringInfo(buf, " IS NULL)");
  						break;
  					case IS_NOT_NULL:
! 						appendStringInfo(buf, " IS NOT NULL)");
  						break;
  					default:
  						elog(ERROR, "unrecognized nulltesttype: %d",
  							 (int) ntest->nulltesttype);
  				}
  			}
  			break;
  
--- 3019,3041 ----
  			{
  				NullTest   *ntest = (NullTest *) node;
  
! 				if (!PRETTY_PAREN(context))
! 				    appendStringInfoChar(buf, '(');
! 				get_rule_expr_paren((Node *) ntest->arg, context, true, node);
  				switch (ntest->nulltesttype)
  				{
  					case IS_NULL:
! 						appendStringInfo(buf, " IS NULL");
  						break;
  					case IS_NOT_NULL:
! 						appendStringInfo(buf, " IS NOT NULL");
  						break;
  					default:
  						elog(ERROR, "unrecognized nulltesttype: %d",
  							 (int) ntest->nulltesttype);
  				}
+ 				if (!PRETTY_PAREN(context))
+ 				    appendStringInfoChar(buf, ')');
  			}
  			break;
  
***************
*** 2551,2582 ****
  			{
  				BooleanTest *btest = (BooleanTest *) node;
  
! 				appendStringInfo(buf, "(");
! 				get_rule_expr((Node *) btest->arg, context, false);
  				switch (btest->booltesttype)
  				{
  					case IS_TRUE:
! 						appendStringInfo(buf, " IS TRUE)");
  						break;
  					case IS_NOT_TRUE:
! 						appendStringInfo(buf, " IS NOT TRUE)");
  						break;
  					case IS_FALSE:
! 						appendStringInfo(buf, " IS FALSE)");
  						break;
  					case IS_NOT_FALSE:
! 						appendStringInfo(buf, " IS NOT FALSE)");
  						break;
  					case IS_UNKNOWN:
! 						appendStringInfo(buf, " IS UNKNOWN)");
  						break;
  					case IS_NOT_UNKNOWN:
! 						appendStringInfo(buf, " IS NOT UNKNOWN)");
  						break;
  					default:
  						elog(ERROR, "unrecognized booltesttype: %d",
  							 (int) btest->booltesttype);
  				}
  			}
  			break;
  
--- 3043,3077 ----
  			{
  				BooleanTest *btest = (BooleanTest *) node;
  
! 				if (!PRETTY_PAREN(context))
! 				    appendStringInfoChar(buf, '(');
! 				get_rule_expr_paren((Node *) btest->arg, context, false, node);
  				switch (btest->booltesttype)
  				{
  					case IS_TRUE:
! 						appendStringInfo(buf, " IS TRUE");
  						break;
  					case IS_NOT_TRUE:
! 						appendStringInfo(buf, " IS NOT TRUE");
  						break;
  					case IS_FALSE:
! 						appendStringInfo(buf, " IS FALSE");
  						break;
  					case IS_NOT_FALSE:
! 						appendStringInfo(buf, " IS NOT FALSE");
  						break;
  					case IS_UNKNOWN:
! 						appendStringInfo(buf, " IS UNKNOWN");
  						break;
  					case IS_NOT_UNKNOWN:
! 						appendStringInfo(buf, " IS NOT UNKNOWN");
  						break;
  					default:
  						elog(ERROR, "unrecognized booltesttype: %d",
  							 (int) btest->booltesttype);
  				}
+ 				if (!PRETTY_PAREN(context))
+ 				    appendStringInfoChar(buf, ')');
  			}
  			break;
  
***************
*** 2598,2606 ****
  				}
  				else
  				{
! 					appendStringInfoChar(buf, '(');
! 					get_rule_expr(arg, context, false);
! 					appendStringInfo(buf, ")::%s",
  							format_type_with_typemod(ctest->resulttype,
  													 ctest->resulttypmod));
  				}
--- 3093,3106 ----
  				}
  				else
  				{
! 					if (!PRETTY_PAREN(context))
! 					    appendStringInfoChar(buf, '(');
! 
! 					get_rule_expr_paren(arg, context, false, node);
! 
! 					if (!PRETTY_PAREN(context))
! 					    appendStringInfoChar(buf, ')');
! 					appendStringInfo(buf, "::%s",
  							format_type_with_typemod(ctest->resulttype,
  													 ctest->resulttypmod));
  				}
***************
*** 2632,2650 ****
  	Oid			opno = expr->opno;
  	List	   *args = expr->args;
  
! 	appendStringInfoChar(buf, '(');
  	if (length(args) == 2)
  	{
  		/* binary operator */
  		Node	   *arg1 = (Node *) lfirst(args);
  		Node	   *arg2 = (Node *) lsecond(args);
! 
! 		get_rule_expr(arg1, context, true);
  		appendStringInfo(buf, " %s ",
  						 generate_operator_name(opno,
  												exprType(arg1),
  												exprType(arg2)));
! 		get_rule_expr(arg2, context, true);
  	}
  	else
  	{
--- 3132,3150 ----
  	Oid			opno = expr->opno;
  	List	   *args = expr->args;
  
! 	if (!PRETTY_PAREN(context))
! 	    appendStringInfoChar(buf, '(');
  	if (length(args) == 2)
  	{
  		/* binary operator */
  		Node	   *arg1 = (Node *) lfirst(args);
  		Node	   *arg2 = (Node *) lsecond(args);
! 		get_rule_expr_paren(arg1, context, true, (Node*)expr);
  		appendStringInfo(buf, " %s ",
  						 generate_operator_name(opno,
  												exprType(arg1),
  												exprType(arg2)));
! 		get_rule_expr_paren(arg2, context, true, (Node*)expr);
  	}
  	else
  	{
***************
*** 2666,2675 ****
  								 generate_operator_name(opno,
  														InvalidOid,
  														exprType(arg)));
! 				get_rule_expr(arg, context, true);
  				break;
  			case 'r':
! 				get_rule_expr(arg, context, true);
  				appendStringInfo(buf, " %s",
  								 generate_operator_name(opno,
  														exprType(arg),
--- 3166,3175 ----
  								 generate_operator_name(opno,
  														InvalidOid,
  														exprType(arg)));
! 				get_rule_expr_paren(arg, context, true, (Node*)expr);
  				break;
  			case 'r':
! 				get_rule_expr_paren(arg, context, true, (Node*)expr);
  				appendStringInfo(buf, " %s",
  								 generate_operator_name(opno,
  														exprType(arg),
***************
*** 2680,2686 ****
  		}
  		ReleaseSysCache(tp);
  	}
! 	appendStringInfoChar(buf, ')');
  }
  
  /*
--- 3180,3187 ----
  		}
  		ReleaseSysCache(tp);
  	}
! 	if (!PRETTY_PAREN(context))
! 	    appendStringInfoChar(buf, ')');
  }
  
  /*
***************
*** 2703,2709 ****
  	 */
  	if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
  	{
! 		get_rule_expr((Node *) lfirst(expr->args), context, showimplicit);
  		return;
  	}
  
--- 3204,3210 ----
  	 */
  	if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
  	{
! 		get_rule_expr_paren((Node *) lfirst(expr->args), context, showimplicit, (Node*)expr);
  		return;
  	}
  
***************
*** 2729,2737 ****
  		 */
  		arg = strip_type_coercion(arg, rettype);
  
! 		appendStringInfoChar(buf, '(');
! 		get_rule_expr(arg, context, showimplicit);
! 		appendStringInfo(buf, ")::%s",
  						 format_type_with_typemod(rettype, coercedTypmod));
  
  		return;
--- 3230,3243 ----
  		 */
  		arg = strip_type_coercion(arg, rettype);
  
! 		if (!PRETTY_PAREN(context))
! 		    appendStringInfoChar(buf, '(');
! 		
! 		get_rule_expr_paren(arg, context, showimplicit, (Node*)expr);
! 
! 		if (!PRETTY_PAREN(context))
! 		    appendStringInfoChar(buf, ')');
! 		appendStringInfo(buf, "::%s",
  						 format_type_with_typemod(rettype, coercedTypmod));
  
  		return;
***************
*** 3052,3058 ****
  	if (need_paren)
  		appendStringInfoChar(buf, '(');
  
! 	get_query_def(query, buf, context->namespaces, NULL);
  
  	if (need_paren)
  		appendStringInfo(buf, "))");
--- 3558,3564 ----
  	if (need_paren)
  		appendStringInfoChar(buf, '(');
  
! 	get_query_def(query, buf, context->namespaces, NULL, context->prettyFlags, context->indentLevel);
  
  	if (need_paren)
  		appendStringInfo(buf, "))");
***************
*** 3069,3075 ****
  get_from_clause(Query *query, deparse_context *context)
  {
  	StringInfo	buf = context->buf;
! 	char	   *sep;
  	List	   *l;
  
  	/*
--- 3575,3581 ----
  get_from_clause(Query *query, deparse_context *context)
  {
  	StringInfo	buf = context->buf;
! 	char	   *sep=0;
  	List	   *l;
  
  	/*
***************
*** 3079,3085 ****
  	 * sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW
  	 * and OLD.
  	 */
- 	sep = " FROM ";
  
  	foreach(l, query->jointree->fromlist)
  	{
--- 3585,3590 ----
***************
*** 3098,3104 ****
  				continue;
  		}
  
! 		appendStringInfo(buf, sep);
  		get_from_clause_item(jtnode, query, context);
  		sep = ", ";
  	}
--- 3603,3613 ----
  				continue;
  		}
  
! 		if (!sep)
! 		    appendContextKeyword(context, " FROM ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
! 		else
! 		    appendStringInfo(buf, sep);
! 
  		get_from_clause_item(jtnode, query, context);
  		sep = ", ";
  	}
***************
*** 3127,3133 ****
  			case RTE_SUBQUERY:
  				/* Subquery RTE */
  				appendStringInfoChar(buf, '(');
! 				get_query_def(rte->subquery, buf, context->namespaces, NULL);
  				appendStringInfoChar(buf, ')');
  				break;
  			case RTE_FUNCTION:
--- 3636,3643 ----
  			case RTE_SUBQUERY:
  				/* Subquery RTE */
  				appendStringInfoChar(buf, '(');
! 				get_query_def(rte->subquery, buf, context->namespaces, NULL, 
! 					      context->prettyFlags, context->indentLevel);
  				appendStringInfoChar(buf, ')');
  				break;
  			case RTE_FUNCTION:
***************
*** 3149,3155 ****
  			{
  				List	   *col;
  
! 				appendStringInfo(buf, "(");
  				foreach(col, rte->alias->colnames)
  				{
  					if (col != rte->alias->colnames)
--- 3659,3665 ----
  			{
  				List	   *col;
  
! 				appendStringInfoChar(buf, '(');
  				foreach(col, rte->alias->colnames)
  				{
  					if (col != rte->alias->colnames)
***************
*** 3183,3218 ****
  	else if (IsA(jtnode, JoinExpr))
  	{
  		JoinExpr   *j = (JoinExpr *) jtnode;
  
- 		appendStringInfoChar(buf, '(');
  		get_from_clause_item(j->larg, query, context);
  		if (j->isNatural)
- 			appendStringInfo(buf, " NATURAL");
- 		switch (j->jointype)
  		{
  			case JOIN_INNER:
  				if (j->quals)
! 					appendStringInfo(buf, " JOIN ");
  				else
! 					appendStringInfo(buf, " CROSS JOIN ");
  				break;
  			case JOIN_LEFT:
! 				appendStringInfo(buf, " LEFT JOIN ");
  				break;
  			case JOIN_FULL:
! 				appendStringInfo(buf, " FULL JOIN ");
  				break;
  			case JOIN_RIGHT:
! 				appendStringInfo(buf, " RIGHT JOIN ");
  				break;
  			case JOIN_UNION:
! 				appendStringInfo(buf, " UNION JOIN ");
  				break;
  			default:
  				elog(ERROR, "unrecognized join type: %d",
  					 (int) j->jointype);
  		}
  		get_from_clause_item(j->rarg, query, context);
  		if (!j->isNatural)
  		{
  			if (j->using)
--- 3693,3770 ----
  	else if (IsA(jtnode, JoinExpr))
  	{
  		JoinExpr   *j = (JoinExpr *) jtnode;
+ 		bool need_paren_on_right = PRETTY_PAREN(context) && !IsA(j->rarg, RangeTblRef);
+ 
+ 		if (!PRETTY_PAREN(context) || j->alias != NULL)
+ 		    appendStringInfoChar(buf, '(');
  
  		get_from_clause_item(j->larg, query, context);
+ 
  		if (j->isNatural)
  		{
+ 		    if (!PRETTY_INDENT(context))
+ 			appendStringInfoChar(buf, ' ');
+ 		    switch (j->jointype)
+ 		    {
  			case JOIN_INNER:
  				if (j->quals)
! 					appendContextKeyword(context, "NATURAL JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 0);
  				else
! 					appendContextKeyword(context, "NATURAL CROSS JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 0);
  				break;
  			case JOIN_LEFT:
! 				appendContextKeyword(context, "NATURAL LEFT JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 0);
  				break;
  			case JOIN_FULL:
! 				appendContextKeyword(context, "NATURAL FULL JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 0);
  				break;
  			case JOIN_RIGHT:
! 				appendContextKeyword(context, "NATURAL RIGHT JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 0);
  				break;
  			case JOIN_UNION:
! 				appendContextKeyword(context, "NATURAL UNION JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 0);
! 				break;
! 			default:
! 				elog(ERROR, "get_from_clause_item: unknown join type %d",
! 					 (int) j->jointype);
! 		    }
! 		}
! 		else
! 		{
! 		    switch (j->jointype)
! 		    {
! 			case JOIN_INNER:
! 				if (j->quals)
! 					appendContextKeyword(context, " JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
! 				else
! 					appendContextKeyword(context, " CROSS JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 1);
! 				break;
! 			case JOIN_LEFT:
! 				appendContextKeyword(context, " LEFT JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
! 				break;
! 			case JOIN_FULL:
! 				appendContextKeyword(context, " FULL JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
! 				break;
! 			case JOIN_RIGHT:
! 				appendContextKeyword(context, " RIGHT JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
! 				break;
! 			case JOIN_UNION:
! 				appendContextKeyword(context, " UNION JOIN ", -PRETTYINDENT_JOIN, PRETTYINDENT_JOIN, 2);
  				break;
  			default:
  				elog(ERROR, "unrecognized join type: %d",
  					 (int) j->jointype);
+ 		    }
  		}
+ 
+ 		if (need_paren_on_right)
+ 		    appendStringInfoChar(buf, '(');
  		get_from_clause_item(j->rarg, query, context);
+ 		if (need_paren_on_right)
+ 		    appendStringInfoChar(buf, ')');
+ 
+ 	        context->indentLevel -= PRETTYINDENT_JOIN_ON;
+ 
  		if (!j->isNatural)
  		{
  			if (j->using)
***************
*** 3231,3242 ****
  			}
  			else if (j->quals)
  			{
! 				appendStringInfo(buf, " ON (");
  				get_rule_expr(j->quals, context, false);
! 				appendStringInfoChar(buf, ')');
  			}
  		}
! 		appendStringInfoChar(buf, ')');
  		/* Yes, it's correct to put alias after the right paren ... */
  		if (j->alias != NULL)
  		{
--- 3783,3799 ----
  			}
  			else if (j->quals)
  			{
! 				appendStringInfo(buf, " ON ");
! 				if (!PRETTY_PAREN(context))
! 				    appendStringInfoChar(buf, '(');
  				get_rule_expr(j->quals, context, false);
! 				if (!PRETTY_PAREN(context))
! 				    appendStringInfoChar(buf, ')');
  			}
  		}
! 		if (!PRETTY_PAREN(context) || j->alias != NULL)
! 		    appendStringInfoChar(buf, ')');
! 
  		/* Yes, it's correct to put alias after the right paren ... */
  		if (j->alias != NULL)
  		{
***************
*** 3246,3252 ****
  			{
  				List	   *col;
  
! 				appendStringInfo(buf, "(");
  				foreach(col, j->alias->colnames)
  				{
  					if (col != j->alias->colnames)
--- 3803,3809 ----
  			{
  				List	   *col;
  
! 				appendStringInfoChar(buf, '(');
  				foreach(col, j->alias->colnames)
  				{
  					if (col != j->alias->colnames)
В списке pgsql-patches по дате отправления
От: Bruce Momjian
Дата:
От: Tom Lane
Дата:
FAQ