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)