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)