Commit 52347b66 authored by Tom Lane's avatar Tom Lane

Add pretty-printing variants of pg_get_viewdef and related functions.

Patch from Andreas Pflug.
parent 12911ea2
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.161 2003/07/29 00:03:17 tgl Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.162 2003/07/30 22:56:23 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -6494,10 +6494,9 @@ SET search_path TO <replaceable>schema</> <optional>, <replaceable>schema</>, .. ...@@ -6494,10 +6494,9 @@ SET search_path TO <replaceable>schema</> <optional>, <replaceable>schema</>, ..
<para> <para>
The function <function>current_setting</function> yields the The function <function>current_setting</function> yields the
current value of the setting <parameter>setting_name</parameter>, current value of the setting <parameter>setting_name</parameter>.
as part of a query result. It corresponds to the It corresponds to the <acronym>SQL</acronym> command
<acronym>SQL</acronym> command <command>SHOW</command>. An <command>SHOW</command>. An example:
example:
<programlisting> <programlisting>
SELECT current_setting('datestyle'); SELECT current_setting('datestyle');
...@@ -6832,6 +6831,10 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); ...@@ -6832,6 +6831,10 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<primary>pg_get_constraintdef</primary> <primary>pg_get_constraintdef</primary>
</indexterm> </indexterm>
<indexterm zone="functions-misc">
<primary>pg_get_expr</primary>
</indexterm>
<indexterm zone="functions-misc"> <indexterm zone="functions-misc">
<primary>pg_get_userbyid</primary> <primary>pg_get_userbyid</primary>
</indexterm> </indexterm>
...@@ -6846,7 +6849,16 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); ...@@ -6846,7 +6849,16 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<function>pg_get_constraintdef</function> respectively <function>pg_get_constraintdef</function> respectively
reconstruct the creating command for a view, rule, index, or reconstruct the creating command for a view, rule, index, or
constraint. (Note that this is a decompiled reconstruction, not constraint. (Note that this is a decompiled reconstruction, not
the verbatim text of the command.) the original text of the command.) Most of these come in two
variants, one of which can optionally <quote>pretty-print</> the result.
The pretty-printed form is more readable but is less likely to be
interpreted the same way by future versions of <productname>PostgreSQL</>;
avoid using pretty-printed output for dump purposes.
Passing <literal>false</> for the pretty-print parameter yields the
same result as the variant that does not have the parameter at all.
<function>pg_get_expr</function> decompiles the internal form of an
individual expression, such as the default value for a column. It
may be useful when examining the contents of system catalogs.
<function>pg_get_userbyid</function> <function>pg_get_userbyid</function>
extracts a user's name given a user ID number. extracts a user's name given a user ID number.
</para> </para>
...@@ -6864,21 +6876,43 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); ...@@ -6864,21 +6876,43 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>get <command>CREATE VIEW</> command for view (<emphasis>deprecated</emphasis>)</entry> <entry>get <command>CREATE VIEW</> command for view (<emphasis>deprecated</emphasis>)</entry>
</row> </row>
<row>
<entry><literal><function>pg_get_viewdef</function>(<parameter>view_name</parameter>, <parameter>pretty_bool</>)</literal></entry>
<entry><type>text</type></entry>
<entry>get <command>CREATE VIEW</> command for view (<emphasis>deprecated</emphasis>)</entry>
</row>
<row> <row>
<entry><literal><function>pg_get_viewdef</function>(<parameter>view_oid</parameter>)</literal></entry> <entry><literal><function>pg_get_viewdef</function>(<parameter>view_oid</parameter>)</literal></entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>get <command>CREATE VIEW</> command for view</entry> <entry>get <command>CREATE VIEW</> command for view</entry>
</row> </row>
<row>
<entry><literal><function>pg_get_viewdef</function>(<parameter>view_oid</parameter>, <parameter>pretty_bool</>)</literal></entry>
<entry><type>text</type></entry>
<entry>get <command>CREATE VIEW</> command for view</entry>
</row>
<row> <row>
<entry><literal><function>pg_get_ruledef</function>(<parameter>rule_oid</parameter>)</literal></entry> <entry><literal><function>pg_get_ruledef</function>(<parameter>rule_oid</parameter>)</literal></entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>get <command>CREATE RULE</> command for rule</entry> <entry>get <command>CREATE RULE</> command for rule</entry>
</row> </row>
<row>
<entry><literal><function>pg_get_ruledef</function>(<parameter>rule_oid</parameter>, <parameter>pretty_bool</>)</literal></entry>
<entry><type>text</type></entry>
<entry>get <command>CREATE RULE</> command for rule</entry>
</row>
<row> <row>
<entry><literal><function>pg_get_indexdef</function>(<parameter>index_oid</parameter>)</literal></entry> <entry><literal><function>pg_get_indexdef</function>(<parameter>index_oid</parameter>)</literal></entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>get <command>CREATE INDEX</> command for index</entry> <entry>get <command>CREATE INDEX</> command for index</entry>
</row> </row>
<row>
<entry><literal><function>pg_get_indexdef</function>(<parameter>index_oid</parameter>, <parameter>column_no</>, <parameter>pretty_bool</>)</literal></entry>
<entry><type>text</type></entry>
<entry>get <command>CREATE INDEX</> command for index,
or definition of just one index column when
<parameter>column_no</> is not zero</entry>
</row>
<row> <row>
<entry><function>pg_get_triggerdef</function>(<parameter>trigger_oid</parameter>)</entry> <entry><function>pg_get_triggerdef</function>(<parameter>trigger_oid</parameter>)</entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
...@@ -6889,6 +6923,23 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); ...@@ -6889,6 +6923,23 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>get definition of a constraint</entry> <entry>get definition of a constraint</entry>
</row> </row>
<row>
<entry><literal><function>pg_get_constraintdef</function>(<parameter>constraint_oid</parameter>, <parameter>pretty_bool</>)</literal></entry>
<entry><type>text</type></entry>
<entry>get definition of a constraint</entry>
</row>
<row>
<entry><literal><function>pg_get_expr</function>(<parameter>expr_text</parameter>, <parameter>relation_oid</>)</literal></entry>
<entry><type>text</type></entry>
<entry>decompile internal form of an expression, assuming that any Vars
in it refer to the relation indicated by the second parameter</entry>
</row>
<row>
<entry><literal><function>pg_get_expr</function>(<parameter>expr_text</parameter>, <parameter>relation_oid</>, <parameter>pretty_bool</>)</literal></entry>
<entry><type>text</type></entry>
<entry>decompile internal form of an expression, assuming that any Vars
in it refer to the relation indicated by the second parameter</entry>
</row>
<row> <row>
<entry><literal><function>pg_get_userbyid</function>(<parameter>userid</parameter>)</literal></entry> <entry><literal><function>pg_get_userbyid</function>(<parameter>userid</parameter>)</literal></entry>
<entry><type>name</type></entry> <entry><type>name</type></entry>
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* back to source text * back to source text
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.146 2003/07/27 04:53:09 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.147 2003/07/30 22:56:23 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -71,6 +71,26 @@ ...@@ -71,6 +71,26 @@
#include "utils/lsyscache.h" #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 * Local data types
* ---------- * ----------
...@@ -81,6 +101,8 @@ typedef struct ...@@ -81,6 +101,8 @@ typedef struct
{ {
StringInfo buf; /* output buffer to append to */ StringInfo buf; /* output buffer to append to */
List *namespaces; /* List of deparse_namespace nodes */ List *namespaces; /* List of deparse_namespace nodes */
int prettyFlags; /* enabling of pretty-print functions */
int indentLevel; /* current indent level for prettyprint */
bool varprefix; /* TRUE to print prefixes on Vars */ bool varprefix; /* TRUE to print prefixes on Vars */
} deparse_context; } deparse_context;
...@@ -123,13 +145,24 @@ static char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_c ...@@ -123,13 +145,24 @@ static char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_c
* as a parameter, and append their text output to its contents. * as a parameter, and append their text output to its contents.
* ---------- * ----------
*/ */
static text *pg_do_getviewdef(Oid viewoid); static char *deparse_expression_pretty(Node *expr, List *dpcontext,
bool forceprefix, bool showimplicit,
int prettyFlags, int startIndent);
static text *pg_do_getviewdef(Oid viewoid, int prettyFlags);
static void decompile_column_index_array(Datum column_index_array, Oid relId, static void decompile_column_index_array(Datum column_index_array, Oid relId,
StringInfo buf); StringInfo buf);
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc); static Datum pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc); 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, static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
TupleDesc resultDesc); TupleDesc resultDesc, int prettyFlags, int startIndent);
static void get_select_query_def(Query *query, deparse_context *context, static void get_select_query_def(Query *query, deparse_context *context,
TupleDesc resultDesc); TupleDesc resultDesc);
static void get_insert_query_def(Query *query, deparse_context *context); static void get_insert_query_def(Query *query, deparse_context *context);
...@@ -148,6 +181,11 @@ static void get_names_for_var(Var *var, deparse_context *context, ...@@ -148,6 +181,11 @@ static void get_names_for_var(Var *var, deparse_context *context,
char **schemaname, char **refname, char **attname); char **schemaname, char **refname, char **attname);
static RangeTblEntry *find_rte_by_refname(const char *refname, static RangeTblEntry *find_rte_by_refname(const char *refname,
deparse_context *context); deparse_context *context);
static const char *get_simple_binary_op_name(OpExpr *expr);
static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
static void appendStringInfoSpaces(StringInfo buf, int count);
static void appendContextKeyword(deparse_context *context, const char *str,
int indentBefore, int indentAfter, int indentPlus);
static void get_rule_expr(Node *node, deparse_context *context, static void get_rule_expr(Node *node, deparse_context *context,
bool showimplicit); bool showimplicit);
static void get_oper_expr(OpExpr *expr, deparse_context *context); static void get_oper_expr(OpExpr *expr, deparse_context *context);
...@@ -184,6 +222,26 @@ Datum ...@@ -184,6 +222,26 @@ Datum
pg_get_ruledef(PG_FUNCTION_ARGS) pg_get_ruledef(PG_FUNCTION_ARGS)
{ {
Oid ruleoid = PG_GETARG_OID(0); 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);
bool pretty = PG_GETARG_BOOL(1);
int prettyFlags;
prettyFlags = pretty ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
return pg_get_ruledef_worker(ruleoid, prettyFlags);
}
static Datum
pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
{
text *ruledef; text *ruledef;
Datum args[1]; Datum args[1];
char nulls[1]; char nulls[1];
...@@ -241,7 +299,7 @@ pg_get_ruledef(PG_FUNCTION_ARGS) ...@@ -241,7 +299,7 @@ pg_get_ruledef(PG_FUNCTION_ARGS)
* Get the rules definition and put it into executors memory * Get the rules definition and put it into executors memory
*/ */
initStringInfo(&buf); initStringInfo(&buf);
make_ruledef(&buf, ruletup, rulettc); make_ruledef(&buf, ruletup, rulettc, prettyFlags);
len = buf.len + VARHDRSZ; len = buf.len + VARHDRSZ;
ruledef = SPI_palloc(len); ruledef = SPI_palloc(len);
VARATT_SIZEP(ruledef) = len; VARATT_SIZEP(ruledef) = len;
...@@ -273,7 +331,22 @@ pg_get_viewdef(PG_FUNCTION_ARGS) ...@@ -273,7 +331,22 @@ pg_get_viewdef(PG_FUNCTION_ARGS)
Oid viewoid = PG_GETARG_OID(0); Oid viewoid = PG_GETARG_OID(0);
text *ruledef; text *ruledef;
ruledef = pg_do_getviewdef(viewoid); 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);
bool pretty = PG_GETARG_BOOL(1);
text *ruledef;
int prettyFlags;
prettyFlags = pretty ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
ruledef = pg_do_getviewdef(viewoid, prettyFlags);
PG_RETURN_TEXT_P(ruledef); PG_RETURN_TEXT_P(ruledef);
} }
...@@ -290,7 +363,28 @@ pg_get_viewdef_name(PG_FUNCTION_ARGS) ...@@ -290,7 +363,28 @@ pg_get_viewdef_name(PG_FUNCTION_ARGS)
"get_viewdef")); "get_viewdef"));
viewoid = RangeVarGetRelid(viewrel, false); viewoid = RangeVarGetRelid(viewrel, false);
ruledef = pg_do_getviewdef(viewoid); 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);
bool pretty = PG_GETARG_BOOL(1);
int prettyFlags;
RangeVar *viewrel;
Oid viewoid;
text *ruledef;
prettyFlags = pretty ? 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); PG_RETURN_TEXT_P(ruledef);
} }
...@@ -298,7 +392,7 @@ pg_get_viewdef_name(PG_FUNCTION_ARGS) ...@@ -298,7 +392,7 @@ pg_get_viewdef_name(PG_FUNCTION_ARGS)
* Common code for by-OID and by-name variants of pg_get_viewdef * Common code for by-OID and by-name variants of pg_get_viewdef
*/ */
static text * static text *
pg_do_getviewdef(Oid viewoid) pg_do_getviewdef(Oid viewoid, int prettyFlags)
{ {
text *ruledef; text *ruledef;
Datum args[2]; Datum args[2];
...@@ -353,7 +447,7 @@ pg_do_getviewdef(Oid viewoid) ...@@ -353,7 +447,7 @@ pg_do_getviewdef(Oid viewoid)
*/ */
ruletup = SPI_tuptable->vals[0]; ruletup = SPI_tuptable->vals[0];
rulettc = SPI_tuptable->tupdesc; rulettc = SPI_tuptable->tupdesc;
make_viewdef(&buf, ruletup, rulettc); make_viewdef(&buf, ruletup, rulettc, prettyFlags);
} }
len = buf.len + VARHDRSZ; len = buf.len + VARHDRSZ;
ruledef = SPI_palloc(len); ruledef = SPI_palloc(len);
...@@ -521,12 +615,35 @@ pg_get_triggerdef(PG_FUNCTION_ARGS) ...@@ -521,12 +615,35 @@ pg_get_triggerdef(PG_FUNCTION_ARGS)
/* ---------- /* ----------
* get_indexdef - Get the definition of an index * get_indexdef - Get the definition of an index
*
* In the extended version, there is a colno argument as well as pretty bool.
* if colno == 0, we want a complete index definition.
* if colno > 0, we only want the Nth index key's variable or expression.
* ---------- * ----------
*/ */
Datum Datum
pg_get_indexdef(PG_FUNCTION_ARGS) pg_get_indexdef(PG_FUNCTION_ARGS)
{ {
Oid indexrelid = PG_GETARG_OID(0); 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);
int32 colno = PG_GETARG_INT32(1);
bool pretty = PG_GETARG_BOOL(2);
int prettyFlags;
prettyFlags = pretty ? 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; text *indexdef;
HeapTuple ht_idx; HeapTuple ht_idx;
HeapTuple ht_idxrel; HeapTuple ht_idxrel;
...@@ -607,6 +724,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS) ...@@ -607,6 +724,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
* never be schema-qualified, but the indexed rel's name may be. * never be schema-qualified, but the indexed rel's name may be.
*/ */
initStringInfo(&buf); initStringInfo(&buf);
if (!colno)
appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (", appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
idxrec->indisunique ? "UNIQUE " : "", idxrec->indisunique ? "UNIQUE " : "",
quote_identifier(NameStr(idxrelrec->relname)), quote_identifier(NameStr(idxrelrec->relname)),
...@@ -621,6 +740,7 @@ pg_get_indexdef(PG_FUNCTION_ARGS) ...@@ -621,6 +740,7 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
{ {
AttrNumber attnum = idxrec->indkey[keyno]; AttrNumber attnum = idxrec->indkey[keyno];
if (!colno)
appendStringInfo(&buf, sep); appendStringInfo(&buf, sep);
sep = ", "; sep = ", ";
...@@ -630,6 +750,7 @@ pg_get_indexdef(PG_FUNCTION_ARGS) ...@@ -630,6 +750,7 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
char *attname; char *attname;
attname = get_relid_attribute_name(indrelid, attnum); attname = get_relid_attribute_name(indrelid, attnum);
if (!colno || colno == keyno+1)
appendStringInfo(&buf, "%s", quote_identifier(attname)); appendStringInfo(&buf, "%s", quote_identifier(attname));
keycoltype = get_atttype(indrelid, attnum); keycoltype = get_atttype(indrelid, attnum);
} }
...@@ -643,23 +764,30 @@ pg_get_indexdef(PG_FUNCTION_ARGS) ...@@ -643,23 +764,30 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
indexkey = (Node *) lfirst(indexprs); indexkey = (Node *) lfirst(indexprs);
indexprs = lnext(indexprs); indexprs = lnext(indexprs);
/* Deparse */ /* Deparse */
str = deparse_expression(indexkey, context, false, false); 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 */ /* Need parens if it's not a bare function call */
if (indexkey && IsA(indexkey, FuncExpr) && if (indexkey && IsA(indexkey, FuncExpr) &&
((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL) ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
appendStringInfo(&buf, "%s", str); appendStringInfo(&buf, "%s", str);
else else
appendStringInfo(&buf, "(%s)", str); appendStringInfo(&buf, "(%s)", str);
}
keycoltype = exprType(indexkey); keycoltype = exprType(indexkey);
} }
/* /*
* Add the operator class name * Add the operator class name
*/ */
if (!colno)
get_opclass_name(idxrec->indclass[keyno], keycoltype, get_opclass_name(idxrec->indclass[keyno], keycoltype,
&buf); &buf);
} }
if (!colno)
{
appendStringInfoChar(&buf, ')'); appendStringInfoChar(&buf, ')');
/* /*
...@@ -689,9 +817,11 @@ pg_get_indexdef(PG_FUNCTION_ARGS) ...@@ -689,9 +817,11 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
if (node && IsA(node, List)) if (node && IsA(node, List))
node = (Node *) make_ands_explicit((List *) node); node = (Node *) make_ands_explicit((List *) node);
/* Deparse */ /* Deparse */
str = deparse_expression(node, context, false, false); str = deparse_expression_pretty(node, context, false, false,
prettyFlags, 0);
appendStringInfo(&buf, " WHERE %s", str); appendStringInfo(&buf, " WHERE %s", str);
} }
}
/* /*
* Create the result as a TEXT datum, and free working data * Create the result as a TEXT datum, and free working data
...@@ -721,6 +851,25 @@ Datum ...@@ -721,6 +851,25 @@ Datum
pg_get_constraintdef(PG_FUNCTION_ARGS) pg_get_constraintdef(PG_FUNCTION_ARGS)
{ {
Oid constraintId = PG_GETARG_OID(0); 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);
bool pretty = PG_GETARG_BOOL(1);
int prettyFlags;
prettyFlags = pretty ? PRETTYFLAG_PAREN|PRETTYFLAG_INDENT : 0;
return pg_get_constraintdef_worker(constraintId, prettyFlags);
}
static Datum
pg_get_constraintdef_worker(Oid constraintId, int prettyFlags)
{
text *result; text *result;
StringInfoData buf; StringInfoData buf;
int len; int len;
...@@ -934,7 +1083,8 @@ pg_get_constraintdef(PG_FUNCTION_ARGS) ...@@ -934,7 +1083,8 @@ pg_get_constraintdef(PG_FUNCTION_ARGS)
context = deparse_context_for(get_typname(conForm->contypid), context = deparse_context_for(get_typname(conForm->contypid),
InvalidOid); InvalidOid);
consrc = deparse_expression(expr, context, false, false); consrc = deparse_expression_pretty(expr, context, false, false,
prettyFlags, 0);
/* Append the constraint source */ /* Append the constraint source */
appendStringInfoString(&buf, consrc); appendStringInfoString(&buf, consrc);
...@@ -1014,18 +1164,44 @@ pg_get_expr(PG_FUNCTION_ARGS) ...@@ -1014,18 +1164,44 @@ pg_get_expr(PG_FUNCTION_ARGS)
{ {
text *expr = PG_GETARG_TEXT_P(0); text *expr = PG_GETARG_TEXT_P(0);
Oid relid = PG_GETARG_OID(1); Oid relid = PG_GETARG_OID(1);
text *result;
Node *node;
List *context;
char *exprstr;
char *relname; char *relname;
char *str;
/* Get the name for the relation */ /* Get the name for the relation */
relname = get_rel_name(relid); relname = get_rel_name(relid);
if (relname == NULL) if (relname == NULL)
PG_RETURN_NULL(); /* should we raise an error? */ 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)
{
text *expr = PG_GETARG_TEXT_P(0);
Oid relid = PG_GETARG_OID(1);
bool pretty = PG_GETARG_BOOL(2);
int prettyFlags;
char *relname;
prettyFlags = pretty ? 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 */ /* Convert input TEXT object to C string */
exprstr = DatumGetCString(DirectFunctionCall1(textout, exprstr = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(expr))); PointerGetDatum(expr)));
...@@ -1043,7 +1219,8 @@ pg_get_expr(PG_FUNCTION_ARGS) ...@@ -1043,7 +1219,8 @@ pg_get_expr(PG_FUNCTION_ARGS)
/* Deparse */ /* Deparse */
context = deparse_context_for(relname, relid); context = deparse_context_for(relname, relid);
str = deparse_expression(node, context, false, false); str = deparse_expression_pretty(node, context, false, false,
prettyFlags, 0);
/* Pass the result back as TEXT */ /* Pass the result back as TEXT */
result = DatumGetTextP(DirectFunctionCall1(textin, result = DatumGetTextP(DirectFunctionCall1(textin,
...@@ -1093,6 +1270,19 @@ pg_get_userbyid(PG_FUNCTION_ARGS) ...@@ -1093,6 +1270,19 @@ pg_get_userbyid(PG_FUNCTION_ARGS)
/* ---------- /* ----------
* deparse_expression - General utility for deparsing expressions * 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 * expr is the node tree to be deparsed. It must be a transformed expression
* tree (ie, not the raw output of gram.y). * tree (ie, not the raw output of gram.y).
* *
...@@ -1103,12 +1293,15 @@ pg_get_userbyid(PG_FUNCTION_ARGS) ...@@ -1103,12 +1293,15 @@ pg_get_userbyid(PG_FUNCTION_ARGS)
* *
* showimplicit is TRUE to force all implicit casts to be shown explicitly. * showimplicit is TRUE to force all implicit casts to be shown explicitly.
* *
* tries to pretty up the output according to prettyFlags and startIndent.
*
* The result is a palloc'd string. * The result is a palloc'd string.
* ---------- * ----------
*/ */
char * char *
deparse_expression(Node *expr, List *dpcontext, deparse_expression_pretty(Node *expr, List *dpcontext,
bool forceprefix, bool showimplicit) bool forceprefix, bool showimplicit,
int prettyFlags, int startIndent)
{ {
StringInfoData buf; StringInfoData buf;
deparse_context context; deparse_context context;
...@@ -1117,6 +1310,8 @@ deparse_expression(Node *expr, List *dpcontext, ...@@ -1117,6 +1310,8 @@ deparse_expression(Node *expr, List *dpcontext,
context.buf = &buf; context.buf = &buf;
context.namespaces = dpcontext; context.namespaces = dpcontext;
context.varprefix = forceprefix; context.varprefix = forceprefix;
context.prettyFlags = prettyFlags;
context.indentLevel = startIndent;
get_rule_expr(expr, &context, showimplicit); get_rule_expr(expr, &context, showimplicit);
...@@ -1269,7 +1464,8 @@ deparse_context_for_subplan(const char *name, List *tlist, ...@@ -1269,7 +1464,8 @@ deparse_context_for_subplan(const char *name, List *tlist,
* ---------- * ----------
*/ */
static void static void
make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
int prettyFlags)
{ {
char *rulename; char *rulename;
char ev_type; char ev_type;
...@@ -1323,9 +1519,14 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -1323,9 +1519,14 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
/* /*
* Build the rules definition text * Build the rules definition text
*/ */
appendStringInfo(buf, "CREATE RULE %s AS ON ", appendStringInfo(buf, "CREATE RULE %s AS",
quote_identifier(rulename)); quote_identifier(rulename));
if (prettyFlags & PRETTYFLAG_INDENT)
appendStringInfoString(buf, "\n ON ");
else
appendStringInfoString(buf, " ON ");
/* The event the rule is fired for */ /* The event the rule is fired for */
switch (ev_type) switch (ev_type)
{ {
...@@ -1370,6 +1571,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -1370,6 +1571,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
deparse_context context; deparse_context context;
deparse_namespace dpns; deparse_namespace dpns;
if (prettyFlags & PRETTYFLAG_INDENT)
appendStringInfoString(buf, "\n ");
appendStringInfo(buf, " WHERE "); appendStringInfo(buf, " WHERE ");
qual = stringToNode(ev_qual); qual = stringToNode(ev_qual);
...@@ -1391,6 +1594,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -1391,6 +1594,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
context.buf = buf; context.buf = buf;
context.namespaces = makeList1(&dpns); context.namespaces = makeList1(&dpns);
context.varprefix = (length(query->rtable) != 1); context.varprefix = (length(query->rtable) != 1);
context.prettyFlags = prettyFlags;
context.indentLevel = PRETTYINDENT_STD;
dpns.rtable = query->rtable; dpns.rtable = query->rtable;
dpns.outer_varno = dpns.inner_varno = 0; dpns.outer_varno = dpns.inner_varno = 0;
dpns.outer_rte = dpns.inner_rte = NULL; dpns.outer_rte = dpns.inner_rte = NULL;
...@@ -1414,7 +1619,10 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -1414,7 +1619,10 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
foreach(action, actions) foreach(action, actions)
{ {
query = (Query *) lfirst(action); query = (Query *) lfirst(action);
get_query_def(query, buf, NIL, NULL); get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
if (prettyFlags)
appendStringInfo(buf, ";\n");
else
appendStringInfo(buf, "; "); appendStringInfo(buf, "; ");
} }
appendStringInfo(buf, ");"); appendStringInfo(buf, ");");
...@@ -1428,7 +1636,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -1428,7 +1636,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
Query *query; Query *query;
query = (Query *) lfirst(actions); query = (Query *) lfirst(actions);
get_query_def(query, buf, NIL, NULL); get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
appendStringInfo(buf, ";"); appendStringInfo(buf, ";");
} }
} }
...@@ -1440,7 +1648,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -1440,7 +1648,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
* ---------- * ----------
*/ */
static void static void
make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
int prettyFlags)
{ {
Query *query; Query *query;
char ev_type; char ev_type;
...@@ -1494,7 +1703,8 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -1494,7 +1703,8 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
ev_relation = heap_open(ev_class, AccessShareLock); ev_relation = heap_open(ev_class, AccessShareLock);
get_query_def(query, buf, NIL, RelationGetDescr(ev_relation)); get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),
prettyFlags, 0);
appendStringInfo(buf, ";"); appendStringInfo(buf, ";");
heap_close(ev_relation, AccessShareLock); heap_close(ev_relation, AccessShareLock);
...@@ -1510,7 +1720,7 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc) ...@@ -1510,7 +1720,7 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
*/ */
static void static void
get_query_def(Query *query, StringInfo buf, List *parentnamespace, get_query_def(Query *query, StringInfo buf, List *parentnamespace,
TupleDesc resultDesc) TupleDesc resultDesc, int prettyFlags, int startIndent)
{ {
deparse_context context; deparse_context context;
deparse_namespace dpns; deparse_namespace dpns;
...@@ -1519,6 +1729,9 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace, ...@@ -1519,6 +1729,9 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace,
context.namespaces = lcons(&dpns, parentnamespace); context.namespaces = lcons(&dpns, parentnamespace);
context.varprefix = (parentnamespace != NIL || context.varprefix = (parentnamespace != NIL ||
length(query->rtable) != 1); length(query->rtable) != 1);
context.prettyFlags = prettyFlags;
context.indentLevel = startIndent;
dpns.rtable = query->rtable; dpns.rtable = query->rtable;
dpns.outer_varno = dpns.inner_varno = 0; dpns.outer_varno = dpns.inner_varno = 0;
dpns.outer_rte = dpns.inner_rte = NULL; dpns.outer_rte = dpns.inner_rte = NULL;
...@@ -1590,7 +1803,8 @@ get_select_query_def(Query *query, deparse_context *context, ...@@ -1590,7 +1803,8 @@ get_select_query_def(Query *query, deparse_context *context,
/* Add the ORDER BY clause if given */ /* Add the ORDER BY clause if given */
if (query->sortClause != NIL) if (query->sortClause != NIL)
{ {
appendStringInfo(buf, " ORDER BY "); appendContextKeyword(context, " ORDER BY ",
-PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
sep = ""; sep = "";
foreach(l, query->sortClause) foreach(l, query->sortClause)
{ {
...@@ -1619,12 +1833,14 @@ get_select_query_def(Query *query, deparse_context *context, ...@@ -1619,12 +1833,14 @@ get_select_query_def(Query *query, deparse_context *context,
/* Add the LIMIT clause if given */ /* Add the LIMIT clause if given */
if (query->limitOffset != NULL) if (query->limitOffset != NULL)
{ {
appendStringInfo(buf, " OFFSET "); appendContextKeyword(context, " OFFSET ",
-PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
get_rule_expr(query->limitOffset, context, false); get_rule_expr(query->limitOffset, context, false);
} }
if (query->limitCount != NULL) if (query->limitCount != NULL)
{ {
appendStringInfo(buf, " LIMIT "); appendContextKeyword(context, " LIMIT ",
-PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
if (IsA(query->limitCount, Const) && if (IsA(query->limitCount, Const) &&
((Const *) query->limitCount)->constisnull) ((Const *) query->limitCount)->constisnull)
appendStringInfo(buf, "ALL"); appendStringInfo(buf, "ALL");
...@@ -1645,6 +1861,11 @@ get_basic_select_query(Query *query, deparse_context *context, ...@@ -1645,6 +1861,11 @@ get_basic_select_query(Query *query, deparse_context *context,
/* /*
* Build up the query string - first we say SELECT * Build up the query string - first we say SELECT
*/ */
if (PRETTY_INDENT(context))
{
context->indentLevel += PRETTYINDENT_STD;
appendStringInfoChar(buf, ' ');
}
appendStringInfo(buf, "SELECT"); appendStringInfo(buf, "SELECT");
/* Add the DISTINCT clause if given */ /* Add the DISTINCT clause if given */
...@@ -1724,14 +1945,16 @@ get_basic_select_query(Query *query, deparse_context *context, ...@@ -1724,14 +1945,16 @@ get_basic_select_query(Query *query, deparse_context *context,
/* Add the WHERE clause if given */ /* Add the WHERE clause if given */
if (query->jointree->quals != NULL) if (query->jointree->quals != NULL)
{ {
appendStringInfo(buf, " WHERE "); appendContextKeyword(context, " WHERE ",
-PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
get_rule_expr(query->jointree->quals, context, false); get_rule_expr(query->jointree->quals, context, false);
} }
/* Add the GROUP BY clause if given */ /* Add the GROUP BY clause if given */
if (query->groupClause != NULL) if (query->groupClause != NULL)
{ {
appendStringInfo(buf, " GROUP BY "); appendContextKeyword(context, " GROUP BY ",
-PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
sep = ""; sep = "";
foreach(l, query->groupClause) foreach(l, query->groupClause)
{ {
...@@ -1747,7 +1970,8 @@ get_basic_select_query(Query *query, deparse_context *context, ...@@ -1747,7 +1970,8 @@ get_basic_select_query(Query *query, deparse_context *context,
/* Add the HAVING clause if given */ /* Add the HAVING clause if given */
if (query->havingQual != NULL) if (query->havingQual != NULL)
{ {
appendStringInfo(buf, " HAVING "); appendContextKeyword(context, " HAVING ",
-PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
get_rule_expr(query->havingQual, context, false); get_rule_expr(query->havingQual, context, false);
} }
} }
...@@ -1765,35 +1989,71 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context, ...@@ -1765,35 +1989,71 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context,
Query *subquery = rte->subquery; Query *subquery = rte->subquery;
Assert(subquery != NULL); Assert(subquery != NULL);
get_query_def(subquery, buf, context->namespaces, resultDesc); get_query_def(subquery, buf, context->namespaces, resultDesc,
context->prettyFlags, context->indentLevel);
} }
else if (IsA(setOp, SetOperationStmt)) else if (IsA(setOp, SetOperationStmt))
{ {
SetOperationStmt *op = (SetOperationStmt *) setOp; SetOperationStmt *op = (SetOperationStmt *) setOp;
bool need_paren;
need_paren = (PRETTY_PAREN(context) ?
!IsA(op->rarg, RangeTblRef) : true);
if (!PRETTY_PAREN(context))
appendStringInfoString(buf, "((");
appendStringInfo(buf, "((");
get_setop_query(op->larg, query, context, resultDesc); get_setop_query(op->larg, query, context, resultDesc);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
if (!PRETTY_INDENT(context))
appendStringInfoChar(buf, ' ');
switch (op->op) switch (op->op)
{ {
case SETOP_UNION: case SETOP_UNION:
appendStringInfo(buf, ") UNION "); appendContextKeyword(context, "UNION ",
-PRETTYINDENT_STD, 0, 0);
break; break;
case SETOP_INTERSECT: case SETOP_INTERSECT:
appendStringInfo(buf, ") INTERSECT "); appendContextKeyword(context, "INTERSECT ",
-PRETTYINDENT_STD, 0, 0);
break; break;
case SETOP_EXCEPT: case SETOP_EXCEPT:
appendStringInfo(buf, ") EXCEPT "); appendContextKeyword(context, "EXCEPT ",
-PRETTYINDENT_STD, 0, 0);
break; break;
default: default:
elog(ERROR, "unrecognized set op: %d", elog(ERROR, "unrecognized set op: %d",
(int) op->op); (int) op->op);
} }
if (op->all) if (op->all)
appendStringInfo(buf, "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 else
appendStringInfo(buf, "("); appendStringInfoChar(buf, '(');
get_setop_query(op->rarg, query, context, resultDesc); get_setop_query(op->rarg, query, context, resultDesc);
appendStringInfo(buf, "))");
if (PRETTY_PAREN(context))
{
if (need_paren)
appendStringInfoChar(buf, ')');
}
else
appendStringInfoString(buf, "))");
} }
else else
{ {
...@@ -1866,6 +2126,12 @@ get_insert_query_def(Query *query, deparse_context *context) ...@@ -1866,6 +2126,12 @@ get_insert_query_def(Query *query, deparse_context *context)
*/ */
rte = rt_fetch(query->resultRelation, query->rtable); rte = rt_fetch(query->resultRelation, query->rtable);
Assert(rte->rtekind == RTE_RELATION); Assert(rte->rtekind == RTE_RELATION);
if (PRETTY_INDENT(context))
{
context->indentLevel += PRETTYINDENT_STD;
appendStringInfoChar(buf, ' ');
}
appendStringInfo(buf, "INSERT INTO %s", appendStringInfo(buf, "INSERT INTO %s",
generate_relation_name(rte->relid)); generate_relation_name(rte->relid));
...@@ -1887,7 +2153,8 @@ get_insert_query_def(Query *query, deparse_context *context) ...@@ -1887,7 +2153,8 @@ get_insert_query_def(Query *query, deparse_context *context)
/* Add the VALUES or the SELECT */ /* Add the VALUES or the SELECT */
if (select_rte == NULL) if (select_rte == NULL)
{ {
appendStringInfo(buf, "VALUES ("); appendContextKeyword(context, "VALUES (",
-PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
sep = ""; sep = "";
foreach(l, query->targetList) foreach(l, query->targetList)
{ {
...@@ -1903,7 +2170,8 @@ get_insert_query_def(Query *query, deparse_context *context) ...@@ -1903,7 +2170,8 @@ get_insert_query_def(Query *query, deparse_context *context)
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
} }
else else
get_query_def(select_rte->subquery, buf, NIL, NULL); get_query_def(select_rte->subquery, buf, NIL, NULL,
context->prettyFlags, context->indentLevel);
} }
...@@ -1924,6 +2192,11 @@ get_update_query_def(Query *query, deparse_context *context) ...@@ -1924,6 +2192,11 @@ get_update_query_def(Query *query, deparse_context *context)
*/ */
rte = rt_fetch(query->resultRelation, query->rtable); rte = rt_fetch(query->resultRelation, query->rtable);
Assert(rte->rtekind == RTE_RELATION); Assert(rte->rtekind == RTE_RELATION);
if (PRETTY_INDENT(context))
{
appendStringInfoChar(buf, ' ');
context->indentLevel += PRETTYINDENT_STD;
}
appendStringInfo(buf, "UPDATE %s%s SET ", appendStringInfo(buf, "UPDATE %s%s SET ",
only_marker(rte), only_marker(rte),
generate_relation_name(rte->relid)); generate_relation_name(rte->relid));
...@@ -1957,7 +2230,8 @@ get_update_query_def(Query *query, deparse_context *context) ...@@ -1957,7 +2230,8 @@ get_update_query_def(Query *query, deparse_context *context)
/* Finally add a WHERE clause if given */ /* Finally add a WHERE clause if given */
if (query->jointree->quals != NULL) if (query->jointree->quals != NULL)
{ {
appendStringInfo(buf, " WHERE "); appendContextKeyword(context, " WHERE ",
-PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
get_rule_expr(query->jointree->quals, context, false); get_rule_expr(query->jointree->quals, context, false);
} }
} }
...@@ -1978,6 +2252,11 @@ get_delete_query_def(Query *query, deparse_context *context) ...@@ -1978,6 +2252,11 @@ get_delete_query_def(Query *query, deparse_context *context)
*/ */
rte = rt_fetch(query->resultRelation, query->rtable); rte = rt_fetch(query->resultRelation, query->rtable);
Assert(rte->rtekind == RTE_RELATION); Assert(rte->rtekind == RTE_RELATION);
if (PRETTY_INDENT(context))
{
context->indentLevel += PRETTYINDENT_STD;
appendStringInfoChar(buf, ' ');
}
appendStringInfo(buf, "DELETE FROM %s%s", appendStringInfo(buf, "DELETE FROM %s%s",
only_marker(rte), only_marker(rte),
generate_relation_name(rte->relid)); generate_relation_name(rte->relid));
...@@ -1985,7 +2264,8 @@ get_delete_query_def(Query *query, deparse_context *context) ...@@ -1985,7 +2264,8 @@ get_delete_query_def(Query *query, deparse_context *context)
/* Add a WHERE clause if given */ /* Add a WHERE clause if given */
if (query->jointree->quals != NULL) if (query->jointree->quals != NULL)
{ {
appendStringInfo(buf, " WHERE "); appendContextKeyword(context, " WHERE ",
-PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
get_rule_expr(query->jointree->quals, context, false); get_rule_expr(query->jointree->quals, context, false);
} }
} }
...@@ -2004,6 +2284,8 @@ get_utility_query_def(Query *query, deparse_context *context) ...@@ -2004,6 +2284,8 @@ get_utility_query_def(Query *query, deparse_context *context)
{ {
NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt; NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
appendContextKeyword(context, "",
0, PRETTYINDENT_STD, 1);
appendStringInfo(buf, "NOTIFY %s", appendStringInfo(buf, "NOTIFY %s",
quote_qualified_identifier(stmt->relation->schemaname, quote_qualified_identifier(stmt->relation->schemaname,
stmt->relation->relname)); stmt->relation->relname));
...@@ -2145,6 +2427,285 @@ find_rte_by_refname(const char *refname, deparse_context *context) ...@@ -2145,6 +2427,285 @@ find_rte_by_refname(const char *refname, deparse_context *context)
} }
/*
* get_simple_binary_op_name
*
* helper function for isSimpleNode
* will return single char binary operator name, or NULL if it's not
*/
static const 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);
const char *op;
op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
if (strlen(op) == 1)
return op;
}
return NULL;
}
/*
* isSimpleNode - check if given node is simple (doesn't need parenthesizing)
*
* true : simple in the context of parent node's type
* false : not simple
*/
static bool
isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
{
if (!node)
return false;
switch (nodeTag(node))
{
case T_Var:
case T_Const:
case T_Param:
case T_CoerceToDomainValue:
case T_SetToDefault:
/* single words: always simple */
return true;
case T_ArrayRef:
case T_ArrayExpr:
case T_CoalesceExpr:
case T_NullIfExpr:
case T_Aggref:
case T_FuncExpr:
/* function-like: name(..) or name[..] */
return true;
/* CASE keywords act as parentheses */
case T_CaseExpr:
return true;
case T_FieldSelect:
/*
* appears simple since . has top precedence, unless parent is
* T_FieldSelect itself!
*/
return (IsA(parentNode, FieldSelect) ? false : true);
case T_CoerceToDomain:
/* maybe simple, check args */
return isSimpleNode((Node*) ((CoerceToDomain*)node)->arg,
node, prettyFlags);
case T_RelabelType:
return isSimpleNode((Node*) ((RelabelType*)node)->arg,
node, prettyFlags);
case T_OpExpr:
{
/* depends on parent node type; needs further checking */
if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
{
const char *op;
const char *parentOp;
bool is_lopriop;
bool is_hipriop;
bool is_lopriparent;
bool is_hipriparent;
op = get_simple_binary_op_name((OpExpr*) node);
if (!op)
return false;
/* We know only the basic operators + - and * / % */
is_lopriop = (strchr("+-", *op) != NULL);
is_hipriop = (strchr("*/%", *op) != NULL);
if (!(is_lopriop || is_hipriop))
return false;
parentOp = get_simple_binary_op_name((OpExpr*) parentNode);
if (!parentOp)
return false;
is_lopriparent = (strchr("+-", *parentOp) != NULL);
is_hipriparent = (strchr("*/%", *parentOp) != NULL);
if (!(is_lopriparent || is_hipriparent))
return false;
if (is_hipriop && is_lopriparent)
return true; /* op binds tighter than parent */
if (is_lopriop && is_hipriparent)
return false;
/*
* Operators are same priority --- can skip parens only
* if we have (a - b) - c, not a - (b - c).
*/
if (node == (Node *) lfirst(((OpExpr *) parentNode)->args))
return true;
return false;
}
/* else do the same stuff as for T_SubLink et al. */
/* FALL THROUGH */
}
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;
BoolExprType parentType;
type = ((BoolExpr*)node)->boolop;
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;
}
default:
break;
}
/* those we don't know: in dubio complexo */
return false;
}
/*
* appendStringInfoSpaces - append spaces to buffer
*/
static void
appendStringInfoSpaces(StringInfo buf, int count)
{
while (count-- > 0)
appendStringInfoChar(buf, ' ');
}
/*
* appendContextKeyword - append a keyword to buffer
*
* If prettyPrint is enabled, perform a line break, and adjust indentation.
* Otherwise, just append the keyword.
*/
static void
appendContextKeyword(deparse_context *context, const 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');
appendStringInfoSpaces(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 - deparse expr using get_rule_expr,
* embracing the string with parentheses if necessary for prettyPrint.
*
* Never embrace 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;
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 * get_rule_expr - Parse back an expression
* *
...@@ -2300,10 +2861,12 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -2300,10 +2861,12 @@ get_rule_expr(Node *node, deparse_context *context,
Node *arg1 = (Node *) lfirst(args); Node *arg1 = (Node *) lfirst(args);
Node *arg2 = (Node *) lsecond(args); Node *arg2 = (Node *) lsecond(args);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_rule_expr(arg1, context, true); get_rule_expr_paren(arg1, context, true, node);
appendStringInfo(buf, " IS DISTINCT FROM "); appendStringInfo(buf, " IS DISTINCT FROM ");
get_rule_expr(arg2, context, true); get_rule_expr_paren(arg2, context, true, node);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
} }
break; break;
...@@ -2315,15 +2878,18 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -2315,15 +2878,18 @@ get_rule_expr(Node *node, deparse_context *context,
Node *arg1 = (Node *) lfirst(args); Node *arg1 = (Node *) lfirst(args);
Node *arg2 = (Node *) lsecond(args); Node *arg2 = (Node *) lsecond(args);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_rule_expr(arg1, context, true); get_rule_expr_paren(arg1, context, true, node);
appendStringInfo(buf, " %s %s (", appendStringInfo(buf, " %s %s (",
generate_operator_name(expr->opno, generate_operator_name(expr->opno,
exprType(arg1), exprType(arg1),
get_element_type(exprType(arg2))), get_element_type(exprType(arg2))),
expr->useOr ? "ANY" : "ALL"); expr->useOr ? "ANY" : "ALL");
get_rule_expr(arg2, context, true); get_rule_expr_paren(arg2, context, true, node);
appendStringInfo(buf, "))"); appendStringInfoChar(buf, ')');
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
} }
break; break;
...@@ -2335,32 +2901,42 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -2335,32 +2901,42 @@ get_rule_expr(Node *node, deparse_context *context,
switch (expr->boolop) switch (expr->boolop)
{ {
case AND_EXPR: case AND_EXPR:
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_rule_expr((Node *) lfirst(args), context, false); get_rule_expr_paren((Node *) lfirst(args), context,
false, node);
while ((args = lnext(args)) != NIL) while ((args = lnext(args)) != NIL)
{ {
appendStringInfo(buf, " AND "); appendStringInfo(buf, " AND ");
get_rule_expr((Node *) lfirst(args), context, get_rule_expr_paren((Node *) lfirst(args), context,
false); false, node);
} }
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
break; break;
case OR_EXPR: case OR_EXPR:
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_rule_expr((Node *) lfirst(args), context, false); get_rule_expr_paren((Node *) lfirst(args), context,
false, node);
while ((args = lnext(args)) != NIL) while ((args = lnext(args)) != NIL)
{ {
appendStringInfo(buf, " OR "); appendStringInfo(buf, " OR ");
get_rule_expr((Node *) lfirst(args), context, get_rule_expr_paren((Node *) lfirst(args), context,
false); false, node);
} }
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
break; break;
case NOT_EXPR: case NOT_EXPR:
appendStringInfo(buf, "(NOT "); if (!PRETTY_PAREN(context))
get_rule_expr((Node *) lfirst(args), context, false); appendStringInfoChar(buf, '(');
appendStringInfo(buf, "NOT ");
get_rule_expr_paren((Node *) lfirst(args), context,
false, node);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
break; break;
...@@ -2409,9 +2985,12 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -2409,9 +2985,12 @@ get_rule_expr(Node *node, deparse_context *context,
* arg.fieldname, but most cases where FieldSelect is used * arg.fieldname, but most cases where FieldSelect is used
* are *not* simple. So, always use parenthesized syntax. * are *not* simple. So, always use parenthesized syntax.
*/ */
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_rule_expr((Node *) fselect->arg, context, true); get_rule_expr_paren((Node *) fselect->arg, context, true, node);
appendStringInfo(buf, ").%s", quote_identifier(fieldname)); if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
appendStringInfo(buf, ".%s", quote_identifier(fieldname));
} }
break; break;
...@@ -2424,7 +3003,7 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -2424,7 +3003,7 @@ get_rule_expr(Node *node, deparse_context *context,
!showimplicit) !showimplicit)
{ {
/* don't show the implicit cast */ /* don't show the implicit cast */
get_rule_expr(arg, context, showimplicit); get_rule_expr_paren(arg, context, showimplicit, node);
} }
else else
{ {
...@@ -2436,9 +3015,12 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -2436,9 +3015,12 @@ get_rule_expr(Node *node, deparse_context *context,
*/ */
arg = strip_type_coercion(arg, relabel->resulttype); arg = strip_type_coercion(arg, relabel->resulttype);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_rule_expr(arg, context, showimplicit); get_rule_expr_paren(arg, context, showimplicit, node);
appendStringInfo(buf, ")::%s", if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
appendStringInfo(buf, "::%s",
format_type_with_typemod(relabel->resulttype, format_type_with_typemod(relabel->resulttype,
relabel->resulttypmod)); relabel->resulttypmod));
} }
...@@ -2450,19 +3032,29 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -2450,19 +3032,29 @@ get_rule_expr(Node *node, deparse_context *context,
CaseExpr *caseexpr = (CaseExpr *) node; CaseExpr *caseexpr = (CaseExpr *) node;
List *temp; List *temp;
appendStringInfo(buf, "CASE"); appendContextKeyword(context, "CASE",
0, PRETTYINDENT_VAR, 0);
foreach(temp, caseexpr->args) foreach(temp, caseexpr->args)
{ {
CaseWhen *when = (CaseWhen *) lfirst(temp); CaseWhen *when = (CaseWhen *) lfirst(temp);
appendStringInfo(buf, " WHEN "); if (!PRETTY_INDENT(context))
appendStringInfoChar(buf, ' ');
appendContextKeyword(context, "WHEN ",
0, 0, 0);
get_rule_expr((Node *) when->expr, context, false); get_rule_expr((Node *) when->expr, context, false);
appendStringInfo(buf, " THEN "); appendStringInfo(buf, " THEN ");
get_rule_expr((Node *) when->result, context, true); get_rule_expr((Node *) when->result, context, true);
} }
appendStringInfo(buf, " ELSE "); if (!PRETTY_INDENT(context))
appendStringInfoChar(buf, ' ');
appendContextKeyword(context, "ELSE ",
0, 0, 0);
get_rule_expr((Node *) caseexpr->defresult, context, true); get_rule_expr((Node *) caseexpr->defresult, context, true);
appendStringInfo(buf, " END"); if (!PRETTY_INDENT(context))
appendStringInfoChar(buf, ' ');
appendContextKeyword(context, "END",
-PRETTYINDENT_VAR, 0, 0);
} }
break; break;
...@@ -2530,20 +3122,23 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -2530,20 +3122,23 @@ get_rule_expr(Node *node, deparse_context *context,
{ {
NullTest *ntest = (NullTest *) node; NullTest *ntest = (NullTest *) node;
appendStringInfo(buf, "("); if (!PRETTY_PAREN(context))
get_rule_expr((Node *) ntest->arg, context, true); appendStringInfoChar(buf, '(');
get_rule_expr_paren((Node *) ntest->arg, context, true, node);
switch (ntest->nulltesttype) switch (ntest->nulltesttype)
{ {
case IS_NULL: case IS_NULL:
appendStringInfo(buf, " IS NULL)"); appendStringInfo(buf, " IS NULL");
break; break;
case IS_NOT_NULL: case IS_NOT_NULL:
appendStringInfo(buf, " IS NOT NULL)"); appendStringInfo(buf, " IS NOT NULL");
break; break;
default: default:
elog(ERROR, "unrecognized nulltesttype: %d", elog(ERROR, "unrecognized nulltesttype: %d",
(int) ntest->nulltesttype); (int) ntest->nulltesttype);
} }
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
} }
break; break;
...@@ -2551,32 +3146,35 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -2551,32 +3146,35 @@ get_rule_expr(Node *node, deparse_context *context,
{ {
BooleanTest *btest = (BooleanTest *) node; BooleanTest *btest = (BooleanTest *) node;
appendStringInfo(buf, "("); if (!PRETTY_PAREN(context))
get_rule_expr((Node *) btest->arg, context, false); appendStringInfoChar(buf, '(');
get_rule_expr_paren((Node *) btest->arg, context, false, node);
switch (btest->booltesttype) switch (btest->booltesttype)
{ {
case IS_TRUE: case IS_TRUE:
appendStringInfo(buf, " IS TRUE)"); appendStringInfo(buf, " IS TRUE");
break; break;
case IS_NOT_TRUE: case IS_NOT_TRUE:
appendStringInfo(buf, " IS NOT TRUE)"); appendStringInfo(buf, " IS NOT TRUE");
break; break;
case IS_FALSE: case IS_FALSE:
appendStringInfo(buf, " IS FALSE)"); appendStringInfo(buf, " IS FALSE");
break; break;
case IS_NOT_FALSE: case IS_NOT_FALSE:
appendStringInfo(buf, " IS NOT FALSE)"); appendStringInfo(buf, " IS NOT FALSE");
break; break;
case IS_UNKNOWN: case IS_UNKNOWN:
appendStringInfo(buf, " IS UNKNOWN)"); appendStringInfo(buf, " IS UNKNOWN");
break; break;
case IS_NOT_UNKNOWN: case IS_NOT_UNKNOWN:
appendStringInfo(buf, " IS NOT UNKNOWN)"); appendStringInfo(buf, " IS NOT UNKNOWN");
break; break;
default: default:
elog(ERROR, "unrecognized booltesttype: %d", elog(ERROR, "unrecognized booltesttype: %d",
(int) btest->booltesttype); (int) btest->booltesttype);
} }
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
} }
break; break;
...@@ -2598,9 +3196,12 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -2598,9 +3196,12 @@ get_rule_expr(Node *node, deparse_context *context,
} }
else else
{ {
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_rule_expr(arg, context, false); get_rule_expr_paren(arg, context, false, node);
appendStringInfo(buf, ")::%s", if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
appendStringInfo(buf, "::%s",
format_type_with_typemod(ctest->resulttype, format_type_with_typemod(ctest->resulttype,
ctest->resulttypmod)); ctest->resulttypmod));
} }
...@@ -2632,19 +3233,19 @@ get_oper_expr(OpExpr *expr, deparse_context *context) ...@@ -2632,19 +3233,19 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
Oid opno = expr->opno; Oid opno = expr->opno;
List *args = expr->args; List *args = expr->args;
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
if (length(args) == 2) if (length(args) == 2)
{ {
/* binary operator */ /* binary operator */
Node *arg1 = (Node *) lfirst(args); Node *arg1 = (Node *) lfirst(args);
Node *arg2 = (Node *) lsecond(args); Node *arg2 = (Node *) lsecond(args);
get_rule_expr_paren(arg1, context, true, (Node*)expr);
get_rule_expr(arg1, context, true);
appendStringInfo(buf, " %s ", appendStringInfo(buf, " %s ",
generate_operator_name(opno, generate_operator_name(opno,
exprType(arg1), exprType(arg1),
exprType(arg2))); exprType(arg2)));
get_rule_expr(arg2, context, true); get_rule_expr_paren(arg2, context, true, (Node*)expr);
} }
else else
{ {
...@@ -2666,10 +3267,10 @@ get_oper_expr(OpExpr *expr, deparse_context *context) ...@@ -2666,10 +3267,10 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
generate_operator_name(opno, generate_operator_name(opno,
InvalidOid, InvalidOid,
exprType(arg))); exprType(arg)));
get_rule_expr(arg, context, true); get_rule_expr_paren(arg, context, true, (Node*)expr);
break; break;
case 'r': case 'r':
get_rule_expr(arg, context, true); get_rule_expr_paren(arg, context, true, (Node*)expr);
appendStringInfo(buf, " %s", appendStringInfo(buf, " %s",
generate_operator_name(opno, generate_operator_name(opno,
exprType(arg), exprType(arg),
...@@ -2680,6 +3281,7 @@ get_oper_expr(OpExpr *expr, deparse_context *context) ...@@ -2680,6 +3281,7 @@ get_oper_expr(OpExpr *expr, deparse_context *context)
} }
ReleaseSysCache(tp); ReleaseSysCache(tp);
} }
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
} }
...@@ -2703,7 +3305,8 @@ get_func_expr(FuncExpr *expr, deparse_context *context, ...@@ -2703,7 +3305,8 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
*/ */
if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit) if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
{ {
get_rule_expr((Node *) lfirst(expr->args), context, showimplicit); get_rule_expr_paren((Node *) lfirst(expr->args), context,
showimplicit, (Node*)expr);
return; return;
} }
...@@ -2729,9 +3332,12 @@ get_func_expr(FuncExpr *expr, deparse_context *context, ...@@ -2729,9 +3332,12 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
*/ */
arg = strip_type_coercion(arg, rettype); arg = strip_type_coercion(arg, rettype);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_rule_expr(arg, context, showimplicit); get_rule_expr_paren(arg, context, showimplicit, (Node*)expr);
appendStringInfo(buf, ")::%s", if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
appendStringInfo(buf, "::%s",
format_type_with_typemod(rettype, coercedTypmod)); format_type_with_typemod(rettype, coercedTypmod));
return; return;
...@@ -3052,7 +3658,8 @@ get_sublink_expr(SubLink *sublink, deparse_context *context) ...@@ -3052,7 +3658,8 @@ get_sublink_expr(SubLink *sublink, deparse_context *context)
if (need_paren) if (need_paren)
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_query_def(query, buf, context->namespaces, NULL); get_query_def(query, buf, context->namespaces, NULL,
context->prettyFlags, context->indentLevel);
if (need_paren) if (need_paren)
appendStringInfo(buf, "))"); appendStringInfo(buf, "))");
...@@ -3069,7 +3676,7 @@ static void ...@@ -3069,7 +3676,7 @@ static void
get_from_clause(Query *query, deparse_context *context) get_from_clause(Query *query, deparse_context *context)
{ {
StringInfo buf = context->buf; StringInfo buf = context->buf;
char *sep; bool first = true;
List *l; List *l;
/* /*
...@@ -3079,8 +3686,6 @@ get_from_clause(Query *query, deparse_context *context) ...@@ -3079,8 +3686,6 @@ get_from_clause(Query *query, deparse_context *context)
* sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW * sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW
* and OLD. * and OLD.
*/ */
sep = " FROM ";
foreach(l, query->jointree->fromlist) foreach(l, query->jointree->fromlist)
{ {
Node *jtnode = (Node *) lfirst(l); Node *jtnode = (Node *) lfirst(l);
...@@ -3098,9 +3703,16 @@ get_from_clause(Query *query, deparse_context *context) ...@@ -3098,9 +3703,16 @@ get_from_clause(Query *query, deparse_context *context)
continue; continue;
} }
appendStringInfo(buf, sep); if (first)
{
appendContextKeyword(context, " FROM ",
-PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
first = false;
}
else
appendStringInfoString(buf, ", ");
get_from_clause_item(jtnode, query, context); get_from_clause_item(jtnode, query, context);
sep = ", ";
} }
} }
...@@ -3127,7 +3739,8 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) ...@@ -3127,7 +3739,8 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
case RTE_SUBQUERY: case RTE_SUBQUERY:
/* Subquery RTE */ /* Subquery RTE */
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_query_def(rte->subquery, buf, context->namespaces, NULL); get_query_def(rte->subquery, buf, context->namespaces, NULL,
context->prettyFlags, context->indentLevel);
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
break; break;
case RTE_FUNCTION: case RTE_FUNCTION:
...@@ -3149,7 +3762,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) ...@@ -3149,7 +3762,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
{ {
List *col; List *col;
appendStringInfo(buf, "("); appendStringInfoChar(buf, '(');
foreach(col, rte->alias->colnames) foreach(col, rte->alias->colnames)
{ {
if (col != rte->alias->colnames) if (col != rte->alias->colnames)
...@@ -3183,36 +3796,105 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) ...@@ -3183,36 +3796,105 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
else if (IsA(jtnode, JoinExpr)) else if (IsA(jtnode, JoinExpr))
{ {
JoinExpr *j = (JoinExpr *) jtnode; JoinExpr *j = (JoinExpr *) jtnode;
bool need_paren_on_right;
need_paren_on_right = PRETTY_PAREN(context) &&
!IsA(j->rarg, RangeTblRef);
if (!PRETTY_PAREN(context) || j->alias != NULL)
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
get_from_clause_item(j->larg, query, context); get_from_clause_item(j->larg, query, context);
if (j->isNatural) if (j->isNatural)
appendStringInfo(buf, " NATURAL"); {
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, "unrecognized join type: %d",
(int) j->jointype);
}
}
else
{
switch (j->jointype) switch (j->jointype)
{ {
case JOIN_INNER: case JOIN_INNER:
if (j->quals) if (j->quals)
appendStringInfo(buf, " JOIN "); appendContextKeyword(context, " JOIN ",
-PRETTYINDENT_JOIN,
PRETTYINDENT_JOIN, 2);
else else
appendStringInfo(buf, " CROSS JOIN "); appendContextKeyword(context, " CROSS JOIN ",
-PRETTYINDENT_JOIN,
PRETTYINDENT_JOIN, 1);
break; break;
case JOIN_LEFT: case JOIN_LEFT:
appendStringInfo(buf, " LEFT JOIN "); appendContextKeyword(context, " LEFT JOIN ",
-PRETTYINDENT_JOIN,
PRETTYINDENT_JOIN, 2);
break; break;
case JOIN_FULL: case JOIN_FULL:
appendStringInfo(buf, " FULL JOIN "); appendContextKeyword(context, " FULL JOIN ",
-PRETTYINDENT_JOIN,
PRETTYINDENT_JOIN, 2);
break; break;
case JOIN_RIGHT: case JOIN_RIGHT:
appendStringInfo(buf, " RIGHT JOIN "); appendContextKeyword(context, " RIGHT JOIN ",
-PRETTYINDENT_JOIN,
PRETTYINDENT_JOIN, 2);
break; break;
case JOIN_UNION: case JOIN_UNION:
appendStringInfo(buf, " UNION JOIN "); appendContextKeyword(context, " UNION JOIN ",
-PRETTYINDENT_JOIN,
PRETTYINDENT_JOIN, 2);
break; break;
default: default:
elog(ERROR, "unrecognized join type: %d", elog(ERROR, "unrecognized join type: %d",
(int) j->jointype); (int) j->jointype);
} }
}
if (need_paren_on_right)
appendStringInfoChar(buf, '(');
get_from_clause_item(j->rarg, query, context); 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->isNatural)
{ {
if (j->using) if (j->using)
...@@ -3231,12 +3913,17 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) ...@@ -3231,12 +3913,17 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
} }
else if (j->quals) else if (j->quals)
{ {
appendStringInfo(buf, " ON ("); appendStringInfo(buf, " ON ");
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '(');
get_rule_expr(j->quals, context, false); get_rule_expr(j->quals, context, false);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
} }
} }
if (!PRETTY_PAREN(context) || j->alias != NULL)
appendStringInfoChar(buf, ')'); appendStringInfoChar(buf, ')');
/* Yes, it's correct to put alias after the right paren ... */ /* Yes, it's correct to put alias after the right paren ... */
if (j->alias != NULL) if (j->alias != NULL)
{ {
...@@ -3246,7 +3933,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) ...@@ -3246,7 +3933,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
{ {
List *col; List *col;
appendStringInfo(buf, "("); appendStringInfoChar(buf, '(');
foreach(col, j->alias->colnames) foreach(col, j->alias->colnames)
{ {
if (col != j->alias->colnames) if (col != j->alias->colnames)
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catversion.h,v 1.203 2003/07/29 17:21:27 tgl Exp $ * $Id: catversion.h,v 1.204 2003/07/30 22:56:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200307291 #define CATALOG_VERSION_NO 200307301
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_proc.h,v 1.309 2003/07/01 00:04:38 tgl Exp $ * $Id: pg_proc.h,v 1.310 2003/07/30 22:56:24 tgl Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -3405,6 +3405,20 @@ DESCR("I/O"); ...@@ -3405,6 +3405,20 @@ DESCR("I/O");
DATA(insert OID = 2503 ( anyarray_send PGNSP PGUID 12 f f t f s 1 17 "2277" anyarray_send - _null_ )); DATA(insert OID = 2503 ( anyarray_send PGNSP PGUID 12 f f t f s 1 17 "2277" anyarray_send - _null_ ));
DESCR("I/O"); DESCR("I/O");
/* System-view support functions with pretty-print option */
DATA(insert OID = 2504 ( pg_get_ruledef PGNSP PGUID 12 f f t f s 2 25 "26 16" pg_get_ruledef_ext - _null_ ));
DESCR("source text of a rule with pretty-print option");
DATA(insert OID = 2505 ( pg_get_viewdef PGNSP PGUID 12 f f t f s 2 25 "25 16" pg_get_viewdef_name_ext - _null_ ));
DESCR("select statement of a view with pretty-print option");
DATA(insert OID = 2506 ( pg_get_viewdef PGNSP PGUID 12 f f t f s 2 25 "26 16" pg_get_viewdef_ext - _null_ ));
DESCR("select statement of a view with pretty-print option");
DATA(insert OID = 2507 ( pg_get_indexdef PGNSP PGUID 12 f f t f s 3 25 "26 23 16" pg_get_indexdef_ext - _null_ ));
DESCR("index description (full create statement or single expression) with pretty-print option");
DATA(insert OID = 2508 ( pg_get_constraintdef PGNSP PGUID 12 f f t f s 2 25 "26 16" pg_get_constraintdef_ext - _null_ ));
DESCR("constraint description with pretty-print option");
DATA(insert OID = 2509 ( pg_get_expr PGNSP PGUID 12 f f t f s 3 25 "25 26 16" pg_get_expr_ext - _null_ ));
DESCR("deparse an encoded expression with pretty-print option");
/* /*
* Symbolic values for provolatile column: these indicate whether the result * Symbolic values for provolatile column: these indicate whether the result
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: builtins.h,v 1.223 2003/06/27 00:33:26 tgl Exp $ * $Id: builtins.h,v 1.224 2003/07/30 22:56:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -441,13 +441,19 @@ extern char *format_operator(Oid operator_oid); ...@@ -441,13 +441,19 @@ extern char *format_operator(Oid operator_oid);
/* ruleutils.c */ /* ruleutils.c */
extern Datum pg_get_ruledef(PG_FUNCTION_ARGS); extern Datum pg_get_ruledef(PG_FUNCTION_ARGS);
extern Datum pg_get_ruledef_ext(PG_FUNCTION_ARGS);
extern Datum pg_get_viewdef(PG_FUNCTION_ARGS); extern Datum pg_get_viewdef(PG_FUNCTION_ARGS);
extern Datum pg_get_viewdef_ext(PG_FUNCTION_ARGS);
extern Datum pg_get_viewdef_name(PG_FUNCTION_ARGS); extern Datum pg_get_viewdef_name(PG_FUNCTION_ARGS);
extern Datum pg_get_viewdef_name_ext(PG_FUNCTION_ARGS);
extern Datum pg_get_indexdef(PG_FUNCTION_ARGS); extern Datum pg_get_indexdef(PG_FUNCTION_ARGS);
extern Datum pg_get_indexdef_ext(PG_FUNCTION_ARGS);
extern Datum pg_get_triggerdef(PG_FUNCTION_ARGS); extern Datum pg_get_triggerdef(PG_FUNCTION_ARGS);
extern Datum pg_get_constraintdef(PG_FUNCTION_ARGS); extern Datum pg_get_constraintdef(PG_FUNCTION_ARGS);
extern Datum pg_get_constraintdef_ext(PG_FUNCTION_ARGS);
extern Datum pg_get_userbyid(PG_FUNCTION_ARGS); extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
extern Datum pg_get_expr(PG_FUNCTION_ARGS); extern Datum pg_get_expr(PG_FUNCTION_ARGS);
extern Datum pg_get_expr_ext(PG_FUNCTION_ARGS);
extern char *deparse_expression(Node *expr, List *dpcontext, extern char *deparse_expression(Node *expr, List *dpcontext,
bool forceprefix, bool showimplicit); bool forceprefix, bool showimplicit);
extern List *deparse_context_for(const char *aliasname, Oid relid); extern List *deparse_context_for(const char *aliasname, Oid relid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment