]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/ruleutils.c
Support MergeAppend plans, to allow sorted output from append relations.
[postgresql] / src / backend / utils / adt / ruleutils.c
1 /*-------------------------------------------------------------------------
2  *
3  * ruleutils.c
4  *        Functions to convert stored expressions/querytrees back to
5  *        source text
6  *
7  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *        src/backend/utils/adt/ruleutils.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17
18 #include <unistd.h>
19 #include <fcntl.h>
20
21 #include "access/genam.h"
22 #include "access/sysattr.h"
23 #include "catalog/dependency.h"
24 #include "catalog/indexing.h"
25 #include "catalog/pg_authid.h"
26 #include "catalog/pg_constraint.h"
27 #include "catalog/pg_depend.h"
28 #include "catalog/pg_language.h"
29 #include "catalog/pg_opclass.h"
30 #include "catalog/pg_operator.h"
31 #include "catalog/pg_proc.h"
32 #include "catalog/pg_trigger.h"
33 #include "catalog/pg_type.h"
34 #include "commands/defrem.h"
35 #include "commands/tablespace.h"
36 #include "executor/spi.h"
37 #include "funcapi.h"
38 #include "nodes/makefuncs.h"
39 #include "nodes/nodeFuncs.h"
40 #include "optimizer/clauses.h"
41 #include "optimizer/tlist.h"
42 #include "parser/keywords.h"
43 #include "parser/parse_func.h"
44 #include "parser/parse_oper.h"
45 #include "parser/parser.h"
46 #include "parser/parsetree.h"
47 #include "rewrite/rewriteHandler.h"
48 #include "rewrite/rewriteManip.h"
49 #include "rewrite/rewriteSupport.h"
50 #include "utils/array.h"
51 #include "utils/builtins.h"
52 #include "utils/fmgroids.h"
53 #include "utils/lsyscache.h"
54 #include "utils/tqual.h"
55 #include "utils/syscache.h"
56 #include "utils/typcache.h"
57 #include "utils/xml.h"
58
59
60 /* ----------
61  * Pretty formatting constants
62  * ----------
63  */
64
65 /* Indent counts */
66 #define PRETTYINDENT_STD                8
67 #define PRETTYINDENT_JOIN          13
68 #define PRETTYINDENT_JOIN_ON    (PRETTYINDENT_JOIN-PRETTYINDENT_STD)
69 #define PRETTYINDENT_VAR                4
70
71 /* Pretty flags */
72 #define PRETTYFLAG_PAREN                1
73 #define PRETTYFLAG_INDENT               2
74
75 /* macro to test if pretty action needed */
76 #define PRETTY_PAREN(context)   ((context)->prettyFlags & PRETTYFLAG_PAREN)
77 #define PRETTY_INDENT(context)  ((context)->prettyFlags & PRETTYFLAG_INDENT)
78
79
80 /* ----------
81  * Local data types
82  * ----------
83  */
84
85 /* Context info needed for invoking a recursive querytree display routine */
86 typedef struct
87 {
88         StringInfo      buf;                    /* output buffer to append to */
89         List       *namespaces;         /* List of deparse_namespace nodes */
90         List       *windowClause;       /* Current query level's WINDOW clause */
91         List       *windowTList;        /* targetlist for resolving WINDOW clause */
92         int                     prettyFlags;    /* enabling of pretty-print functions */
93         int                     indentLevel;    /* current indent level for prettyprint */
94         bool            varprefix;              /* TRUE to print prefixes on Vars */
95 } deparse_context;
96
97 /*
98  * Each level of query context around a subtree needs a level of Var namespace.
99  * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
100  * the current context's namespaces list.
101  *
102  * The rangetable is the list of actual RTEs from the query tree, and the
103  * cte list is the list of actual CTEs.
104  *
105  * When deparsing plan trees, there is always just a single item in the
106  * deparse_namespace list (since a plan tree never contains Vars with
107  * varlevelsup > 0).  We store the PlanState node that is the immediate
108  * parent of the expression to be deparsed, as well as a list of that
109  * PlanState's ancestors.  In addition, we store the outer and inner
110  * subplan nodes, whose targetlists are used to resolve OUTER and INNER Vars.
111  * (Note: these could be derived on-the-fly from the planstate instead.)
112  */
113 typedef struct
114 {
115         List       *rtable;                     /* List of RangeTblEntry nodes */
116         List       *ctes;                       /* List of CommonTableExpr nodes */
117         /* Remaining fields are used only when deparsing a Plan tree: */
118         PlanState  *planstate;          /* immediate parent of current expression */
119         List       *ancestors;          /* ancestors of planstate */
120         PlanState  *outer_planstate;    /* OUTER subplan state, or NULL if none */
121         PlanState  *inner_planstate;    /* INNER subplan state, or NULL if none */
122         Plan       *outer_plan;         /* OUTER subplan, or NULL if none */
123         Plan       *inner_plan;         /* INNER subplan, or NULL if none */
124 } deparse_namespace;
125
126
127 /* ----------
128  * Global data
129  * ----------
130  */
131 static SPIPlanPtr plan_getrulebyoid = NULL;
132 static const char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
133 static SPIPlanPtr plan_getviewrule = NULL;
134 static const char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
135
136 /* GUC parameters */
137 bool            quote_all_identifiers = false;
138
139
140 /* ----------
141  * Local functions
142  *
143  * Most of these functions used to use fixed-size buffers to build their
144  * results.  Now, they take an (already initialized) StringInfo object
145  * as a parameter, and append their text output to its contents.
146  * ----------
147  */
148 static char *deparse_expression_pretty(Node *expr, List *dpcontext,
149                                                   bool forceprefix, bool showimplicit,
150                                                   int prettyFlags, int startIndent);
151 static char *pg_get_viewdef_worker(Oid viewoid, int prettyFlags);
152 static char *pg_get_triggerdef_worker(Oid trigid, bool pretty);
153 static void decompile_column_index_array(Datum column_index_array, Oid relId,
154                                                          StringInfo buf);
155 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
156 static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
157                                            const Oid *excludeOps,
158                                            bool attrsOnly, bool showTblSpc,
159                                            int prettyFlags);
160 static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
161                                                         int prettyFlags);
162 static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
163                                    int prettyFlags);
164 static int print_function_arguments(StringInfo buf, HeapTuple proctup,
165                                                  bool print_table_args, bool print_defaults);
166 static void print_function_rettype(StringInfo buf, HeapTuple proctup);
167 static void set_deparse_planstate(deparse_namespace *dpns, PlanState *ps);
168 static void push_child_plan(deparse_namespace *dpns, PlanState *ps,
169                                 deparse_namespace *save_dpns);
170 static void pop_child_plan(deparse_namespace *dpns,
171                                                    deparse_namespace *save_dpns);
172 static void push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
173                                    deparse_namespace *save_dpns);
174 static void pop_ancestor_plan(deparse_namespace *dpns,
175                                                           deparse_namespace *save_dpns);
176 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
177                          int prettyFlags);
178 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
179                          int prettyFlags);
180 static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
181                           TupleDesc resultDesc, int prettyFlags, int startIndent);
182 static void get_values_def(List *values_lists, deparse_context *context);
183 static void get_with_clause(Query *query, deparse_context *context);
184 static void get_select_query_def(Query *query, deparse_context *context,
185                                          TupleDesc resultDesc);
186 static void get_insert_query_def(Query *query, deparse_context *context);
187 static void get_update_query_def(Query *query, deparse_context *context);
188 static void get_delete_query_def(Query *query, deparse_context *context);
189 static void get_utility_query_def(Query *query, deparse_context *context);
190 static void get_basic_select_query(Query *query, deparse_context *context,
191                                            TupleDesc resultDesc);
192 static void get_target_list(List *targetList, deparse_context *context,
193                                 TupleDesc resultDesc);
194 static void get_setop_query(Node *setOp, Query *query,
195                                 deparse_context *context,
196                                 TupleDesc resultDesc);
197 static Node *get_rule_sortgroupclause(SortGroupClause *srt, List *tlist,
198                                                  bool force_colno,
199                                                  deparse_context *context);
200 static void get_rule_orderby(List *orderList, List *targetList,
201                                  bool force_colno, deparse_context *context);
202 static void get_rule_windowclause(Query *query, deparse_context *context);
203 static void get_rule_windowspec(WindowClause *wc, List *targetList,
204                                         deparse_context *context);
205 static char *get_variable(Var *var, int levelsup, bool showstar,
206                          deparse_context *context);
207 static RangeTblEntry *find_rte_by_refname(const char *refname,
208                                         deparse_context *context);
209 static void get_parameter(Param *param, deparse_context *context);
210 static void print_parameter_expr(Node *expr, ListCell *ancestor_cell,
211                                          deparse_namespace *dpns, deparse_context *context);
212 static const char *get_simple_binary_op_name(OpExpr *expr);
213 static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
214 static void appendContextKeyword(deparse_context *context, const char *str,
215                                          int indentBefore, int indentAfter, int indentPlus);
216 static void get_rule_expr(Node *node, deparse_context *context,
217                           bool showimplicit);
218 static void get_oper_expr(OpExpr *expr, deparse_context *context);
219 static void get_func_expr(FuncExpr *expr, deparse_context *context,
220                           bool showimplicit);
221 static void get_agg_expr(Aggref *aggref, deparse_context *context);
222 static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
223 static void get_coercion_expr(Node *arg, deparse_context *context,
224                                   Oid resulttype, int32 resulttypmod,
225                                   Node *parentNode);
226 static void get_const_expr(Const *constval, deparse_context *context,
227                            int showtype);
228 static void simple_quote_literal(StringInfo buf, const char *val);
229 static void get_sublink_expr(SubLink *sublink, deparse_context *context);
230 static void get_from_clause(Query *query, const char *prefix,
231                                 deparse_context *context);
232 static void get_from_clause_item(Node *jtnode, Query *query,
233                                          deparse_context *context);
234 static void get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
235                                           deparse_context *context);
236 static void get_from_clause_coldeflist(List *names, List *types, List *typmods,
237                                                    deparse_context *context);
238 static void get_opclass_name(Oid opclass, Oid actual_datatype,
239                                  StringInfo buf);
240 static Node *processIndirection(Node *node, deparse_context *context,
241                                    bool printit);
242 static void printSubscripts(ArrayRef *aref, deparse_context *context);
243 static char *generate_relation_name(Oid relid, List *namespaces);
244 static char *generate_function_name(Oid funcid, int nargs, List *argnames,
245                                            Oid *argtypes, bool *is_variadic);
246 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
247 static text *string_to_text(char *str);
248 static char *flatten_reloptions(Oid relid);
249
250 #define only_marker(rte)  ((rte)->inh ? "" : "ONLY ")
251
252
253 /* ----------
254  * get_ruledef                  - Do it all and return a text
255  *                                that could be used as a statement
256  *                                to recreate the rule
257  * ----------
258  */
259 Datum
260 pg_get_ruledef(PG_FUNCTION_ARGS)
261 {
262         Oid                     ruleoid = PG_GETARG_OID(0);
263
264         PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, 0)));
265 }
266
267
268 Datum
269 pg_get_ruledef_ext(PG_FUNCTION_ARGS)
270 {
271         Oid                     ruleoid = PG_GETARG_OID(0);
272         bool            pretty = PG_GETARG_BOOL(1);
273         int                     prettyFlags;
274
275         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
276         PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, prettyFlags)));
277 }
278
279
280 static char *
281 pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
282 {
283         Datum           args[1];
284         char            nulls[1];
285         int                     spirc;
286         HeapTuple       ruletup;
287         TupleDesc       rulettc;
288         StringInfoData buf;
289
290         /*
291          * Do this first so that string is alloc'd in outer context not SPI's.
292          */
293         initStringInfo(&buf);
294
295         /*
296          * Connect to SPI manager
297          */
298         if (SPI_connect() != SPI_OK_CONNECT)
299                 elog(ERROR, "SPI_connect failed");
300
301         /*
302          * On the first call prepare the plan to lookup pg_rewrite. We read
303          * pg_rewrite over the SPI manager instead of using the syscache to be
304          * checked for read access on pg_rewrite.
305          */
306         if (plan_getrulebyoid == NULL)
307         {
308                 Oid                     argtypes[1];
309                 SPIPlanPtr      plan;
310
311                 argtypes[0] = OIDOID;
312                 plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
313                 if (plan == NULL)
314                         elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
315                 plan_getrulebyoid = SPI_saveplan(plan);
316         }
317
318         /*
319          * Get the pg_rewrite tuple for this rule
320          */
321         args[0] = ObjectIdGetDatum(ruleoid);
322         nulls[0] = ' ';
323         spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 1);
324         if (spirc != SPI_OK_SELECT)
325                 elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
326         if (SPI_processed != 1)
327                 appendStringInfo(&buf, "-");
328         else
329         {
330                 /*
331                  * Get the rule's definition and put it into executor's memory
332                  */
333                 ruletup = SPI_tuptable->vals[0];
334                 rulettc = SPI_tuptable->tupdesc;
335                 make_ruledef(&buf, ruletup, rulettc, prettyFlags);
336         }
337
338         /*
339          * Disconnect from SPI manager
340          */
341         if (SPI_finish() != SPI_OK_FINISH)
342                 elog(ERROR, "SPI_finish failed");
343
344         return buf.data;
345 }
346
347
348 /* ----------
349  * get_viewdef                  - Mainly the same thing, but we
350  *                                only return the SELECT part of a view
351  * ----------
352  */
353 Datum
354 pg_get_viewdef(PG_FUNCTION_ARGS)
355 {
356         /* By OID */
357         Oid                     viewoid = PG_GETARG_OID(0);
358
359         PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, 0)));
360 }
361
362
363 Datum
364 pg_get_viewdef_ext(PG_FUNCTION_ARGS)
365 {
366         /* By OID */
367         Oid                     viewoid = PG_GETARG_OID(0);
368         bool            pretty = PG_GETARG_BOOL(1);
369         int                     prettyFlags;
370
371         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
372         PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags)));
373 }
374
375 Datum
376 pg_get_viewdef_name(PG_FUNCTION_ARGS)
377 {
378         /* By qualified name */
379         text       *viewname = PG_GETARG_TEXT_P(0);
380         RangeVar   *viewrel;
381         Oid                     viewoid;
382
383         viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
384         viewoid = RangeVarGetRelid(viewrel, false);
385
386         PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, 0)));
387 }
388
389
390 Datum
391 pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
392 {
393         /* By qualified name */
394         text       *viewname = PG_GETARG_TEXT_P(0);
395         bool            pretty = PG_GETARG_BOOL(1);
396         int                     prettyFlags;
397         RangeVar   *viewrel;
398         Oid                     viewoid;
399
400         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
401         viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
402         viewoid = RangeVarGetRelid(viewrel, false);
403
404         PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags)));
405 }
406
407 /*
408  * Common code for by-OID and by-name variants of pg_get_viewdef
409  */
410 static char *
411 pg_get_viewdef_worker(Oid viewoid, int prettyFlags)
412 {
413         Datum           args[2];
414         char            nulls[2];
415         int                     spirc;
416         HeapTuple       ruletup;
417         TupleDesc       rulettc;
418         StringInfoData buf;
419
420         /*
421          * Do this first so that string is alloc'd in outer context not SPI's.
422          */
423         initStringInfo(&buf);
424
425         /*
426          * Connect to SPI manager
427          */
428         if (SPI_connect() != SPI_OK_CONNECT)
429                 elog(ERROR, "SPI_connect failed");
430
431         /*
432          * On the first call prepare the plan to lookup pg_rewrite. We read
433          * pg_rewrite over the SPI manager instead of using the syscache to be
434          * checked for read access on pg_rewrite.
435          */
436         if (plan_getviewrule == NULL)
437         {
438                 Oid                     argtypes[2];
439                 SPIPlanPtr      plan;
440
441                 argtypes[0] = OIDOID;
442                 argtypes[1] = NAMEOID;
443                 plan = SPI_prepare(query_getviewrule, 2, argtypes);
444                 if (plan == NULL)
445                         elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
446                 plan_getviewrule = SPI_saveplan(plan);
447         }
448
449         /*
450          * Get the pg_rewrite tuple for the view's SELECT rule
451          */
452         args[0] = ObjectIdGetDatum(viewoid);
453         args[1] = PointerGetDatum(ViewSelectRuleName);
454         nulls[0] = ' ';
455         nulls[1] = ' ';
456         spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 2);
457         if (spirc != SPI_OK_SELECT)
458                 elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
459         if (SPI_processed != 1)
460                 appendStringInfo(&buf, "Not a view");
461         else
462         {
463                 /*
464                  * Get the rule's definition and put it into executor's memory
465                  */
466                 ruletup = SPI_tuptable->vals[0];
467                 rulettc = SPI_tuptable->tupdesc;
468                 make_viewdef(&buf, ruletup, rulettc, prettyFlags);
469         }
470
471         /*
472          * Disconnect from SPI manager
473          */
474         if (SPI_finish() != SPI_OK_FINISH)
475                 elog(ERROR, "SPI_finish failed");
476
477         return buf.data;
478 }
479
480 /* ----------
481  * get_triggerdef                       - Get the definition of a trigger
482  * ----------
483  */
484 Datum
485 pg_get_triggerdef(PG_FUNCTION_ARGS)
486 {
487         Oid                     trigid = PG_GETARG_OID(0);
488
489         PG_RETURN_TEXT_P(string_to_text(pg_get_triggerdef_worker(trigid, false)));
490 }
491
492 Datum
493 pg_get_triggerdef_ext(PG_FUNCTION_ARGS)
494 {
495         Oid                     trigid = PG_GETARG_OID(0);
496         bool            pretty = PG_GETARG_BOOL(1);
497
498         PG_RETURN_TEXT_P(string_to_text(pg_get_triggerdef_worker(trigid, pretty)));
499 }
500
501 static char *
502 pg_get_triggerdef_worker(Oid trigid, bool pretty)
503 {
504         HeapTuple       ht_trig;
505         Form_pg_trigger trigrec;
506         StringInfoData buf;
507         Relation        tgrel;
508         ScanKeyData skey[1];
509         SysScanDesc tgscan;
510         int                     findx = 0;
511         char       *tgname;
512         Datum           value;
513         bool            isnull;
514
515         /*
516          * Fetch the pg_trigger tuple by the Oid of the trigger
517          */
518         tgrel = heap_open(TriggerRelationId, AccessShareLock);
519
520         ScanKeyInit(&skey[0],
521                                 ObjectIdAttributeNumber,
522                                 BTEqualStrategyNumber, F_OIDEQ,
523                                 ObjectIdGetDatum(trigid));
524
525         tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
526                                                                 SnapshotNow, 1, skey);
527
528         ht_trig = systable_getnext(tgscan);
529
530         if (!HeapTupleIsValid(ht_trig))
531                 elog(ERROR, "could not find tuple for trigger %u", trigid);
532
533         trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
534
535         /*
536          * Start the trigger definition. Note that the trigger's name should never
537          * be schema-qualified, but the trigger rel's name may be.
538          */
539         initStringInfo(&buf);
540
541         tgname = NameStr(trigrec->tgname);
542         appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
543                                          OidIsValid(trigrec->tgconstraint) ? "CONSTRAINT " : "",
544                                          quote_identifier(tgname));
545
546         if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
547                 appendStringInfo(&buf, "BEFORE");
548         else if (TRIGGER_FOR_AFTER(trigrec->tgtype))
549                 appendStringInfo(&buf, "AFTER");
550         else if (TRIGGER_FOR_INSTEAD(trigrec->tgtype))
551                 appendStringInfo(&buf, "INSTEAD OF");
552         else
553                 elog(ERROR, "unexpected tgtype value: %d", trigrec->tgtype);
554
555         if (TRIGGER_FOR_INSERT(trigrec->tgtype))
556         {
557                 appendStringInfo(&buf, " INSERT");
558                 findx++;
559         }
560         if (TRIGGER_FOR_DELETE(trigrec->tgtype))
561         {
562                 if (findx > 0)
563                         appendStringInfo(&buf, " OR DELETE");
564                 else
565                         appendStringInfo(&buf, " DELETE");
566                 findx++;
567         }
568         if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
569         {
570                 if (findx > 0)
571                         appendStringInfo(&buf, " OR UPDATE");
572                 else
573                         appendStringInfo(&buf, " UPDATE");
574                 findx++;
575                 /* tgattr is first var-width field, so OK to access directly */
576                 if (trigrec->tgattr.dim1 > 0)
577                 {
578                         int                     i;
579
580                         appendStringInfoString(&buf, " OF ");
581                         for (i = 0; i < trigrec->tgattr.dim1; i++)
582                         {
583                                 char       *attname;
584
585                                 if (i > 0)
586                                         appendStringInfoString(&buf, ", ");
587                                 attname = get_relid_attribute_name(trigrec->tgrelid,
588                                                                                                    trigrec->tgattr.values[i]);
589                                 appendStringInfoString(&buf, quote_identifier(attname));
590                         }
591                 }
592         }
593         if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
594         {
595                 if (findx > 0)
596                         appendStringInfo(&buf, " OR TRUNCATE");
597                 else
598                         appendStringInfo(&buf, " TRUNCATE");
599                 findx++;
600         }
601         appendStringInfo(&buf, " ON %s ",
602                                          generate_relation_name(trigrec->tgrelid, NIL));
603
604         if (OidIsValid(trigrec->tgconstraint))
605         {
606                 if (OidIsValid(trigrec->tgconstrrelid))
607                         appendStringInfo(&buf, "FROM %s ",
608                                                 generate_relation_name(trigrec->tgconstrrelid, NIL));
609                 if (!trigrec->tgdeferrable)
610                         appendStringInfo(&buf, "NOT ");
611                 appendStringInfo(&buf, "DEFERRABLE INITIALLY ");
612                 if (trigrec->tginitdeferred)
613                         appendStringInfo(&buf, "DEFERRED ");
614                 else
615                         appendStringInfo(&buf, "IMMEDIATE ");
616         }
617
618         if (TRIGGER_FOR_ROW(trigrec->tgtype))
619                 appendStringInfo(&buf, "FOR EACH ROW ");
620         else
621                 appendStringInfo(&buf, "FOR EACH STATEMENT ");
622
623         /* If the trigger has a WHEN qualification, add that */
624         value = fastgetattr(ht_trig, Anum_pg_trigger_tgqual,
625                                                 tgrel->rd_att, &isnull);
626         if (!isnull)
627         {
628                 Node       *qual;
629                 deparse_context context;
630                 deparse_namespace dpns;
631                 RangeTblEntry *oldrte;
632                 RangeTblEntry *newrte;
633
634                 appendStringInfoString(&buf, "WHEN (");
635
636                 qual = stringToNode(TextDatumGetCString(value));
637
638                 /* Build minimal OLD and NEW RTEs for the rel */
639                 oldrte = makeNode(RangeTblEntry);
640                 oldrte->rtekind = RTE_RELATION;
641                 oldrte->relid = trigrec->tgrelid;
642                 oldrte->eref = makeAlias("old", NIL);
643                 oldrte->inh = false;
644                 oldrte->inFromCl = true;
645
646                 newrte = makeNode(RangeTblEntry);
647                 newrte->rtekind = RTE_RELATION;
648                 newrte->relid = trigrec->tgrelid;
649                 newrte->eref = makeAlias("new", NIL);
650                 newrte->inh = false;
651                 newrte->inFromCl = true;
652
653                 /* Build two-element rtable */
654                 memset(&dpns, 0, sizeof(dpns));
655                 dpns.rtable = list_make2(oldrte, newrte);
656                 dpns.ctes = NIL;
657
658                 /* Set up context with one-deep namespace stack */
659                 context.buf = &buf;
660                 context.namespaces = list_make1(&dpns);
661                 context.windowClause = NIL;
662                 context.windowTList = NIL;
663                 context.varprefix = true;
664                 context.prettyFlags = pretty ? PRETTYFLAG_PAREN : 0;
665                 context.indentLevel = PRETTYINDENT_STD;
666
667                 get_rule_expr(qual, &context, false);
668
669                 appendStringInfo(&buf, ") ");
670         }
671
672         appendStringInfo(&buf, "EXECUTE PROCEDURE %s(",
673                                          generate_function_name(trigrec->tgfoid, 0,
674                                                                                         NIL, NULL, NULL));
675
676         if (trigrec->tgnargs > 0)
677         {
678                 char       *p;
679                 int                     i;
680
681                 value = fastgetattr(ht_trig, Anum_pg_trigger_tgargs,
682                                                         tgrel->rd_att, &isnull);
683                 if (isnull)
684                         elog(ERROR, "tgargs is null for trigger %u", trigid);
685                 p = (char *) VARDATA(DatumGetByteaP(value));
686                 for (i = 0; i < trigrec->tgnargs; i++)
687                 {
688                         if (i > 0)
689                                 appendStringInfo(&buf, ", ");
690                         simple_quote_literal(&buf, p);
691                         /* advance p to next string embedded in tgargs */
692                         while (*p)
693                                 p++;
694                         p++;
695                 }
696         }
697
698         /* We deliberately do not put semi-colon at end */
699         appendStringInfo(&buf, ")");
700
701         /* Clean up */
702         systable_endscan(tgscan);
703
704         heap_close(tgrel, AccessShareLock);
705
706         return buf.data;
707 }
708
709 /* ----------
710  * get_indexdef                 - Get the definition of an index
711  *
712  * In the extended version, there is a colno argument as well as pretty bool.
713  *      if colno == 0, we want a complete index definition.
714  *      if colno > 0, we only want the Nth index key's variable or expression.
715  *
716  * Note that the SQL-function versions of this omit any info about the
717  * index tablespace; this is intentional because pg_dump wants it that way.
718  * However pg_get_indexdef_string() includes index tablespace if not default.
719  * ----------
720  */
721 Datum
722 pg_get_indexdef(PG_FUNCTION_ARGS)
723 {
724         Oid                     indexrelid = PG_GETARG_OID(0);
725
726         PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, 0,
727                                                                                                                    NULL,
728                                                                                                                    false, false, 0)));
729 }
730
731 Datum
732 pg_get_indexdef_ext(PG_FUNCTION_ARGS)
733 {
734         Oid                     indexrelid = PG_GETARG_OID(0);
735         int32           colno = PG_GETARG_INT32(1);
736         bool            pretty = PG_GETARG_BOOL(2);
737         int                     prettyFlags;
738
739         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
740         PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, colno,
741                                                                                                                    NULL,
742                                                                                                                    colno != 0,
743                                                                                                                    false,
744                                                                                                                    prettyFlags)));
745 }
746
747 /* Internal version that returns a palloc'd C string */
748 char *
749 pg_get_indexdef_string(Oid indexrelid)
750 {
751         return pg_get_indexdef_worker(indexrelid, 0, NULL, false, true, 0);
752 }
753
754 /* Internal version that just reports the column definitions */
755 char *
756 pg_get_indexdef_columns(Oid indexrelid, bool pretty)
757 {
758         int                     prettyFlags;
759
760         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
761         return pg_get_indexdef_worker(indexrelid, 0, NULL, true, false, prettyFlags);
762 }
763
764 /*
765  * Internal workhorse to decompile an index definition.
766  *
767  * This is now used for exclusion constraints as well: if excludeOps is not
768  * NULL then it points to an array of exclusion operator OIDs.
769  */
770 static char *
771 pg_get_indexdef_worker(Oid indexrelid, int colno,
772                                            const Oid *excludeOps,
773                                            bool attrsOnly, bool showTblSpc,
774                                            int prettyFlags)
775 {
776         /* might want a separate isConstraint parameter later */
777         bool            isConstraint = (excludeOps != NULL);
778         HeapTuple       ht_idx;
779         HeapTuple       ht_idxrel;
780         HeapTuple       ht_am;
781         Form_pg_index idxrec;
782         Form_pg_class idxrelrec;
783         Form_pg_am      amrec;
784         List       *indexprs;
785         ListCell   *indexpr_item;
786         List       *context;
787         Oid                     indrelid;
788         int                     keyno;
789         Oid                     keycoltype;
790         Datum           indclassDatum;
791         Datum           indoptionDatum;
792         bool            isnull;
793         oidvector  *indclass;
794         int2vector *indoption;
795         StringInfoData buf;
796         char       *str;
797         char       *sep;
798
799         /*
800          * Fetch the pg_index tuple by the Oid of the index
801          */
802         ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid));
803         if (!HeapTupleIsValid(ht_idx))
804                 elog(ERROR, "cache lookup failed for index %u", indexrelid);
805         idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
806
807         indrelid = idxrec->indrelid;
808         Assert(indexrelid == idxrec->indexrelid);
809
810         /* Must get indclass and indoption the hard way */
811         indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
812                                                                         Anum_pg_index_indclass, &isnull);
813         Assert(!isnull);
814         indclass = (oidvector *) DatumGetPointer(indclassDatum);
815         indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
816                                                                          Anum_pg_index_indoption, &isnull);
817         Assert(!isnull);
818         indoption = (int2vector *) DatumGetPointer(indoptionDatum);
819
820         /*
821          * Fetch the pg_class tuple of the index relation
822          */
823         ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid));
824         if (!HeapTupleIsValid(ht_idxrel))
825                 elog(ERROR, "cache lookup failed for relation %u", indexrelid);
826         idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
827
828         /*
829          * Fetch the pg_am tuple of the index' access method
830          */
831         ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
832         if (!HeapTupleIsValid(ht_am))
833                 elog(ERROR, "cache lookup failed for access method %u",
834                          idxrelrec->relam);
835         amrec = (Form_pg_am) GETSTRUCT(ht_am);
836
837         /*
838          * Get the index expressions, if any.  (NOTE: we do not use the relcache
839          * versions of the expressions and predicate, because we want to display
840          * non-const-folded expressions.)
841          */
842         if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
843         {
844                 Datum           exprsDatum;
845                 bool            isnull;
846                 char       *exprsString;
847
848                 exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
849                                                                          Anum_pg_index_indexprs, &isnull);
850                 Assert(!isnull);
851                 exprsString = TextDatumGetCString(exprsDatum);
852                 indexprs = (List *) stringToNode(exprsString);
853                 pfree(exprsString);
854         }
855         else
856                 indexprs = NIL;
857
858         indexpr_item = list_head(indexprs);
859
860         context = deparse_context_for(get_rel_name(indrelid), indrelid);
861
862         /*
863          * Start the index definition.  Note that the index's name should never be
864          * schema-qualified, but the indexed rel's name may be.
865          */
866         initStringInfo(&buf);
867
868         if (!attrsOnly)
869         {
870                 if (!isConstraint)
871                         appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
872                                                          idxrec->indisunique ? "UNIQUE " : "",
873                                                          quote_identifier(NameStr(idxrelrec->relname)),
874                                                          generate_relation_name(indrelid, NIL),
875                                                          quote_identifier(NameStr(amrec->amname)));
876                 else    /* currently, must be EXCLUDE constraint */
877                         appendStringInfo(&buf, "EXCLUDE USING %s (",
878                                                          quote_identifier(NameStr(amrec->amname)));
879         }
880
881         /*
882          * Report the indexed attributes
883          */
884         sep = "";
885         for (keyno = 0; keyno < idxrec->indnatts; keyno++)
886         {
887                 AttrNumber      attnum = idxrec->indkey.values[keyno];
888                 int16           opt = indoption->values[keyno];
889
890                 if (!colno)
891                         appendStringInfoString(&buf, sep);
892                 sep = ", ";
893
894                 if (attnum != 0)
895                 {
896                         /* Simple index column */
897                         char       *attname;
898
899                         attname = get_relid_attribute_name(indrelid, attnum);
900                         if (!colno || colno == keyno + 1)
901                                 appendStringInfoString(&buf, quote_identifier(attname));
902                         keycoltype = get_atttype(indrelid, attnum);
903                 }
904                 else
905                 {
906                         /* expressional index */
907                         Node       *indexkey;
908
909                         if (indexpr_item == NULL)
910                                 elog(ERROR, "too few entries in indexprs list");
911                         indexkey = (Node *) lfirst(indexpr_item);
912                         indexpr_item = lnext(indexpr_item);
913                         /* Deparse */
914                         str = deparse_expression_pretty(indexkey, context, false, false,
915                                                                                         prettyFlags, 0);
916                         if (!colno || colno == keyno + 1)
917                         {
918                                 /* Need parens if it's not a bare function call */
919                                 if (indexkey && IsA(indexkey, FuncExpr) &&
920                                  ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
921                                         appendStringInfoString(&buf, str);
922                                 else
923                                         appendStringInfo(&buf, "(%s)", str);
924                         }
925                         keycoltype = exprType(indexkey);
926                 }
927
928                 if (!attrsOnly && (!colno || colno == keyno + 1))
929                 {
930                         /* Add the operator class name, if not default */
931                         get_opclass_name(indclass->values[keyno], keycoltype, &buf);
932
933                         /* Add options if relevant */
934                         if (amrec->amcanorder)
935                         {
936                                 /* if it supports sort ordering, report DESC and NULLS opts */
937                                 if (opt & INDOPTION_DESC)
938                                 {
939                                         appendStringInfo(&buf, " DESC");
940                                         /* NULLS FIRST is the default in this case */
941                                         if (!(opt & INDOPTION_NULLS_FIRST))
942                                                 appendStringInfo(&buf, " NULLS LAST");
943                                 }
944                                 else
945                                 {
946                                         if (opt & INDOPTION_NULLS_FIRST)
947                                                 appendStringInfo(&buf, " NULLS FIRST");
948                                 }
949                         }
950
951                         /* Add the exclusion operator if relevant */
952                         if (excludeOps != NULL)
953                                 appendStringInfo(&buf, " WITH %s",
954                                                                  generate_operator_name(excludeOps[keyno],
955                                                                                                                 keycoltype,
956                                                                                                                 keycoltype));
957                 }
958         }
959
960         if (!attrsOnly)
961         {
962                 appendStringInfoChar(&buf, ')');
963
964                 /*
965                  * If it has options, append "WITH (options)"
966                  */
967                 str = flatten_reloptions(indexrelid);
968                 if (str)
969                 {
970                         appendStringInfo(&buf, " WITH (%s)", str);
971                         pfree(str);
972                 }
973
974                 /*
975                  * If it's in a nondefault tablespace, say so, but only if requested
976                  */
977                 if (showTblSpc)
978                 {
979                         Oid                     tblspc;
980
981                         tblspc = get_rel_tablespace(indexrelid);
982                         if (OidIsValid(tblspc))
983                         {
984                                 if (isConstraint)
985                                         appendStringInfoString(&buf, " USING INDEX");
986                                 appendStringInfo(&buf, " TABLESPACE %s",
987                                                           quote_identifier(get_tablespace_name(tblspc)));
988                         }
989                 }
990
991                 /*
992                  * If it's a partial index, decompile and append the predicate
993                  */
994                 if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
995                 {
996                         Node       *node;
997                         Datum           predDatum;
998                         bool            isnull;
999                         char       *predString;
1000
1001                         /* Convert text string to node tree */
1002                         predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
1003                                                                                 Anum_pg_index_indpred, &isnull);
1004                         Assert(!isnull);
1005                         predString = TextDatumGetCString(predDatum);
1006                         node = (Node *) stringToNode(predString);
1007                         pfree(predString);
1008
1009                         /* Deparse */
1010                         str = deparse_expression_pretty(node, context, false, false,
1011                                                                                         prettyFlags, 0);
1012                         if (isConstraint)
1013                                 appendStringInfo(&buf, " WHERE (%s)", str);
1014                         else
1015                                 appendStringInfo(&buf, " WHERE %s", str);
1016                 }
1017         }
1018
1019         /* Clean up */
1020         ReleaseSysCache(ht_idx);
1021         ReleaseSysCache(ht_idxrel);
1022         ReleaseSysCache(ht_am);
1023
1024         return buf.data;
1025 }
1026
1027
1028 /*
1029  * pg_get_constraintdef
1030  *
1031  * Returns the definition for the constraint, ie, everything that needs to
1032  * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
1033  */
1034 Datum
1035 pg_get_constraintdef(PG_FUNCTION_ARGS)
1036 {
1037         Oid                     constraintId = PG_GETARG_OID(0);
1038
1039         PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,
1040                                                                                                                                 false, 0)));
1041 }
1042
1043 Datum
1044 pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
1045 {
1046         Oid                     constraintId = PG_GETARG_OID(0);
1047         bool            pretty = PG_GETARG_BOOL(1);
1048         int                     prettyFlags;
1049
1050         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
1051         PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,
1052                                                                                                            false, prettyFlags)));
1053 }
1054
1055 /* Internal version that returns a palloc'd C string */
1056 char *
1057 pg_get_constraintdef_string(Oid constraintId)
1058 {
1059         return pg_get_constraintdef_worker(constraintId, true, 0);
1060 }
1061
1062 static char *
1063 pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
1064                                                         int prettyFlags)
1065 {
1066         HeapTuple       tup;
1067         Form_pg_constraint conForm;
1068         StringInfoData buf;
1069
1070         tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintId));
1071         if (!HeapTupleIsValid(tup)) /* should not happen */
1072                 elog(ERROR, "cache lookup failed for constraint %u", constraintId);
1073         conForm = (Form_pg_constraint) GETSTRUCT(tup);
1074
1075         initStringInfo(&buf);
1076
1077         if (fullCommand && OidIsValid(conForm->conrelid))
1078         {
1079                 appendStringInfo(&buf, "ALTER TABLE ONLY %s ADD CONSTRAINT %s ",
1080                                                  generate_relation_name(conForm->conrelid, NIL),
1081                                                  quote_identifier(NameStr(conForm->conname)));
1082         }
1083
1084         switch (conForm->contype)
1085         {
1086                 case CONSTRAINT_FOREIGN:
1087                         {
1088                                 Datum           val;
1089                                 bool            isnull;
1090                                 const char *string;
1091
1092                                 /* Start off the constraint definition */
1093                                 appendStringInfo(&buf, "FOREIGN KEY (");
1094
1095                                 /* Fetch and build referencing-column list */
1096                                 val = SysCacheGetAttr(CONSTROID, tup,
1097                                                                           Anum_pg_constraint_conkey, &isnull);
1098                                 if (isnull)
1099                                         elog(ERROR, "null conkey for constraint %u",
1100                                                  constraintId);
1101
1102                                 decompile_column_index_array(val, conForm->conrelid, &buf);
1103
1104                                 /* add foreign relation name */
1105                                 appendStringInfo(&buf, ") REFERENCES %s(",
1106                                                                  generate_relation_name(conForm->confrelid,
1107                                                                                                                 NIL));
1108
1109                                 /* Fetch and build referenced-column list */
1110                                 val = SysCacheGetAttr(CONSTROID, tup,
1111                                                                           Anum_pg_constraint_confkey, &isnull);
1112                                 if (isnull)
1113                                         elog(ERROR, "null confkey for constraint %u",
1114                                                  constraintId);
1115
1116                                 decompile_column_index_array(val, conForm->confrelid, &buf);
1117
1118                                 appendStringInfo(&buf, ")");
1119
1120                                 /* Add match type */
1121                                 switch (conForm->confmatchtype)
1122                                 {
1123                                         case FKCONSTR_MATCH_FULL:
1124                                                 string = " MATCH FULL";
1125                                                 break;
1126                                         case FKCONSTR_MATCH_PARTIAL:
1127                                                 string = " MATCH PARTIAL";
1128                                                 break;
1129                                         case FKCONSTR_MATCH_UNSPECIFIED:
1130                                                 string = "";
1131                                                 break;
1132                                         default:
1133                                                 elog(ERROR, "unrecognized confmatchtype: %d",
1134                                                          conForm->confmatchtype);
1135                                                 string = "";    /* keep compiler quiet */
1136                                                 break;
1137                                 }
1138                                 appendStringInfoString(&buf, string);
1139
1140                                 /* Add ON UPDATE and ON DELETE clauses, if needed */
1141                                 switch (conForm->confupdtype)
1142                                 {
1143                                         case FKCONSTR_ACTION_NOACTION:
1144                                                 string = NULL;  /* suppress default */
1145                                                 break;
1146                                         case FKCONSTR_ACTION_RESTRICT:
1147                                                 string = "RESTRICT";
1148                                                 break;
1149                                         case FKCONSTR_ACTION_CASCADE:
1150                                                 string = "CASCADE";
1151                                                 break;
1152                                         case FKCONSTR_ACTION_SETNULL:
1153                                                 string = "SET NULL";
1154                                                 break;
1155                                         case FKCONSTR_ACTION_SETDEFAULT:
1156                                                 string = "SET DEFAULT";
1157                                                 break;
1158                                         default:
1159                                                 elog(ERROR, "unrecognized confupdtype: %d",
1160                                                          conForm->confupdtype);
1161                                                 string = NULL;  /* keep compiler quiet */
1162                                                 break;
1163                                 }
1164                                 if (string)
1165                                         appendStringInfo(&buf, " ON UPDATE %s", string);
1166
1167                                 switch (conForm->confdeltype)
1168                                 {
1169                                         case FKCONSTR_ACTION_NOACTION:
1170                                                 string = NULL;  /* suppress default */
1171                                                 break;
1172                                         case FKCONSTR_ACTION_RESTRICT:
1173                                                 string = "RESTRICT";
1174                                                 break;
1175                                         case FKCONSTR_ACTION_CASCADE:
1176                                                 string = "CASCADE";
1177                                                 break;
1178                                         case FKCONSTR_ACTION_SETNULL:
1179                                                 string = "SET NULL";
1180                                                 break;
1181                                         case FKCONSTR_ACTION_SETDEFAULT:
1182                                                 string = "SET DEFAULT";
1183                                                 break;
1184                                         default:
1185                                                 elog(ERROR, "unrecognized confdeltype: %d",
1186                                                          conForm->confdeltype);
1187                                                 string = NULL;  /* keep compiler quiet */
1188                                                 break;
1189                                 }
1190                                 if (string)
1191                                         appendStringInfo(&buf, " ON DELETE %s", string);
1192
1193                                 break;
1194                         }
1195                 case CONSTRAINT_PRIMARY:
1196                 case CONSTRAINT_UNIQUE:
1197                         {
1198                                 Datum           val;
1199                                 bool            isnull;
1200                                 Oid                     indexId;
1201
1202                                 /* Start off the constraint definition */
1203                                 if (conForm->contype == CONSTRAINT_PRIMARY)
1204                                         appendStringInfo(&buf, "PRIMARY KEY (");
1205                                 else
1206                                         appendStringInfo(&buf, "UNIQUE (");
1207
1208                                 /* Fetch and build target column list */
1209                                 val = SysCacheGetAttr(CONSTROID, tup,
1210                                                                           Anum_pg_constraint_conkey, &isnull);
1211                                 if (isnull)
1212                                         elog(ERROR, "null conkey for constraint %u",
1213                                                  constraintId);
1214
1215                                 decompile_column_index_array(val, conForm->conrelid, &buf);
1216
1217                                 appendStringInfo(&buf, ")");
1218
1219                                 indexId = get_constraint_index(constraintId);
1220
1221                                 /* XXX why do we only print these bits if fullCommand? */
1222                                 if (fullCommand && OidIsValid(indexId))
1223                                 {
1224                                         char       *options = flatten_reloptions(indexId);
1225                                         Oid                     tblspc;
1226
1227                                         if (options)
1228                                         {
1229                                                 appendStringInfo(&buf, " WITH (%s)", options);
1230                                                 pfree(options);
1231                                         }
1232
1233                                         tblspc = get_rel_tablespace(indexId);
1234                                         if (OidIsValid(tblspc))
1235                                                 appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
1236                                                           quote_identifier(get_tablespace_name(tblspc)));
1237                                 }
1238
1239                                 break;
1240                         }
1241                 case CONSTRAINT_CHECK:
1242                         {
1243                                 Datum           val;
1244                                 bool            isnull;
1245                                 char       *conbin;
1246                                 char       *consrc;
1247                                 Node       *expr;
1248                                 List       *context;
1249
1250                                 /* Fetch constraint expression in parsetree form */
1251                                 val = SysCacheGetAttr(CONSTROID, tup,
1252                                                                           Anum_pg_constraint_conbin, &isnull);
1253                                 if (isnull)
1254                                         elog(ERROR, "null conbin for constraint %u",
1255                                                  constraintId);
1256
1257                                 conbin = TextDatumGetCString(val);
1258                                 expr = stringToNode(conbin);
1259
1260                                 /* Set up deparsing context for Var nodes in constraint */
1261                                 if (conForm->conrelid != InvalidOid)
1262                                 {
1263                                         /* relation constraint */
1264                                         context = deparse_context_for(get_rel_name(conForm->conrelid),
1265                                                                                                   conForm->conrelid);
1266                                 }
1267                                 else
1268                                 {
1269                                         /* domain constraint --- can't have Vars */
1270                                         context = NIL;
1271                                 }
1272
1273                                 consrc = deparse_expression_pretty(expr, context, false, false,
1274                                                                                                    prettyFlags, 0);
1275
1276                                 /*
1277                                  * Now emit the constraint definition.  There are cases where
1278                                  * the constraint expression will be fully parenthesized and
1279                                  * we don't need the outer parens ... but there are other
1280                                  * cases where we do need 'em.  Be conservative for now.
1281                                  *
1282                                  * Note that simply checking for leading '(' and trailing ')'
1283                                  * would NOT be good enough, consider "(x > 0) AND (y > 0)".
1284                                  */
1285                                 appendStringInfo(&buf, "CHECK (%s)", consrc);
1286
1287                                 break;
1288                         }
1289                 case CONSTRAINT_TRIGGER:
1290
1291                         /*
1292                          * There isn't an ALTER TABLE syntax for creating a user-defined
1293                          * constraint trigger, but it seems better to print something than
1294                          * throw an error; if we throw error then this function couldn't
1295                          * safely be applied to all rows of pg_constraint.
1296                          */
1297                         appendStringInfo(&buf, "TRIGGER");
1298                         break;
1299                 case CONSTRAINT_EXCLUSION:
1300                         {
1301                                 Oid                     indexOid = conForm->conindid;
1302                                 Datum           val;
1303                                 bool            isnull;
1304                                 Datum      *elems;
1305                                 int                     nElems;
1306                                 int                     i;
1307                                 Oid                *operators;
1308
1309                                 /* Extract operator OIDs from the pg_constraint tuple */
1310                                 val = SysCacheGetAttr(CONSTROID, tup,
1311                                                                           Anum_pg_constraint_conexclop,
1312                                                                           &isnull);
1313                                 if (isnull)
1314                                         elog(ERROR, "null conexclop for constraint %u",
1315                                                  constraintId);
1316
1317                                 deconstruct_array(DatumGetArrayTypeP(val),
1318                                                                   OIDOID, sizeof(Oid), true, 'i',
1319                                                                   &elems, NULL, &nElems);
1320
1321                                 operators = (Oid *) palloc(nElems * sizeof(Oid));
1322                                 for (i = 0; i < nElems; i++)
1323                                         operators[i] = DatumGetObjectId(elems[i]);
1324
1325                                 /* pg_get_indexdef_worker does the rest */
1326                                 /* suppress tablespace because pg_dump wants it that way */
1327                                 appendStringInfoString(&buf,
1328                                                                            pg_get_indexdef_worker(indexOid,
1329                                                                                                                           0,
1330                                                                                                                           operators,
1331                                                                                                                           false,
1332                                                                                                                           false,
1333                                                                                                                           prettyFlags));
1334                                 break;
1335                         }
1336                 default:
1337                         elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
1338                         break;
1339         }
1340
1341         if (conForm->condeferrable)
1342                 appendStringInfo(&buf, " DEFERRABLE");
1343         if (conForm->condeferred)
1344                 appendStringInfo(&buf, " INITIALLY DEFERRED");
1345
1346         /* Cleanup */
1347         ReleaseSysCache(tup);
1348
1349         return buf.data;
1350 }
1351
1352
1353 /*
1354  * Convert an int16[] Datum into a comma-separated list of column names
1355  * for the indicated relation; append the list to buf.
1356  */
1357 static void
1358 decompile_column_index_array(Datum column_index_array, Oid relId,
1359                                                          StringInfo buf)
1360 {
1361         Datum      *keys;
1362         int                     nKeys;
1363         int                     j;
1364
1365         /* Extract data from array of int16 */
1366         deconstruct_array(DatumGetArrayTypeP(column_index_array),
1367                                           INT2OID, 2, true, 's',
1368                                           &keys, NULL, &nKeys);
1369
1370         for (j = 0; j < nKeys; j++)
1371         {
1372                 char       *colName;
1373
1374                 colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j]));
1375
1376                 if (j == 0)
1377                         appendStringInfoString(buf, quote_identifier(colName));
1378                 else
1379                         appendStringInfo(buf, ", %s", quote_identifier(colName));
1380         }
1381 }
1382
1383
1384 /* ----------
1385  * get_expr                     - Decompile an expression tree
1386  *
1387  * Input: an expression tree in nodeToString form, and a relation OID
1388  *
1389  * Output: reverse-listed expression
1390  *
1391  * Currently, the expression can only refer to a single relation, namely
1392  * the one specified by the second parameter.  This is sufficient for
1393  * partial indexes, column default expressions, etc.  We also support
1394  * Var-free expressions, for which the OID can be InvalidOid.
1395  * ----------
1396  */
1397 Datum
1398 pg_get_expr(PG_FUNCTION_ARGS)
1399 {
1400         text       *expr = PG_GETARG_TEXT_P(0);
1401         Oid                     relid = PG_GETARG_OID(1);
1402         char       *relname;
1403
1404         if (OidIsValid(relid))
1405         {
1406                 /* Get the name for the relation */
1407                 relname = get_rel_name(relid);
1408
1409                 /*
1410                  * If the OID isn't actually valid, don't throw an error, just return
1411                  * NULL.  This is a bit questionable, but it's what we've done
1412                  * historically, and it can help avoid unwanted failures when
1413                  * examining catalog entries for just-deleted relations.
1414                  */
1415                 if (relname == NULL)
1416                         PG_RETURN_NULL();
1417         }
1418         else
1419                 relname = NULL;
1420
1421         PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, 0));
1422 }
1423
1424 Datum
1425 pg_get_expr_ext(PG_FUNCTION_ARGS)
1426 {
1427         text       *expr = PG_GETARG_TEXT_P(0);
1428         Oid                     relid = PG_GETARG_OID(1);
1429         bool            pretty = PG_GETARG_BOOL(2);
1430         int                     prettyFlags;
1431         char       *relname;
1432
1433         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
1434
1435         if (OidIsValid(relid))
1436         {
1437                 /* Get the name for the relation */
1438                 relname = get_rel_name(relid);
1439                 /* See notes above */
1440                 if (relname == NULL)
1441                         PG_RETURN_NULL();
1442         }
1443         else
1444                 relname = NULL;
1445
1446         PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
1447 }
1448
1449 static text *
1450 pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
1451 {
1452         Node       *node;
1453         List       *context;
1454         char       *exprstr;
1455         char       *str;
1456
1457         /* Convert input TEXT object to C string */
1458         exprstr = text_to_cstring(expr);
1459
1460         /* Convert expression to node tree */
1461         node = (Node *) stringToNode(exprstr);
1462
1463         pfree(exprstr);
1464
1465         /* Prepare deparse context if needed */
1466         if (OidIsValid(relid))
1467                 context = deparse_context_for(relname, relid);
1468         else
1469                 context = NIL;
1470
1471         /* Deparse */
1472         str = deparse_expression_pretty(node, context, false, false,
1473                                                                         prettyFlags, 0);
1474
1475         return string_to_text(str);
1476 }
1477
1478
1479 /* ----------
1480  * get_userbyid                 - Get a user name by roleid and
1481  *                                fallback to 'unknown (OID=n)'
1482  * ----------
1483  */
1484 Datum
1485 pg_get_userbyid(PG_FUNCTION_ARGS)
1486 {
1487         Oid                     roleid = PG_GETARG_OID(0);
1488         Name            result;
1489         HeapTuple       roletup;
1490         Form_pg_authid role_rec;
1491
1492         /*
1493          * Allocate space for the result
1494          */
1495         result = (Name) palloc(NAMEDATALEN);
1496         memset(NameStr(*result), 0, NAMEDATALEN);
1497
1498         /*
1499          * Get the pg_authid entry and print the result
1500          */
1501         roletup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
1502         if (HeapTupleIsValid(roletup))
1503         {
1504                 role_rec = (Form_pg_authid) GETSTRUCT(roletup);
1505                 StrNCpy(NameStr(*result), NameStr(role_rec->rolname), NAMEDATALEN);
1506                 ReleaseSysCache(roletup);
1507         }
1508         else
1509                 sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
1510
1511         PG_RETURN_NAME(result);
1512 }
1513
1514
1515 /*
1516  * pg_get_serial_sequence
1517  *              Get the name of the sequence used by a serial column,
1518  *              formatted suitably for passing to setval, nextval or currval.
1519  *              First parameter is not treated as double-quoted, second parameter
1520  *              is --- see documentation for reason.
1521  */
1522 Datum
1523 pg_get_serial_sequence(PG_FUNCTION_ARGS)
1524 {
1525         text       *tablename = PG_GETARG_TEXT_P(0);
1526         text       *columnname = PG_GETARG_TEXT_PP(1);
1527         RangeVar   *tablerv;
1528         Oid                     tableOid;
1529         char       *column;
1530         AttrNumber      attnum;
1531         Oid                     sequenceId = InvalidOid;
1532         Relation        depRel;
1533         ScanKeyData key[3];
1534         SysScanDesc scan;
1535         HeapTuple       tup;
1536
1537         /* Get the OID of the table */
1538         tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1539         tableOid = RangeVarGetRelid(tablerv, false);
1540
1541         /* Get the number of the column */
1542         column = text_to_cstring(columnname);
1543
1544         attnum = get_attnum(tableOid, column);
1545         if (attnum == InvalidAttrNumber)
1546                 ereport(ERROR,
1547                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
1548                                  errmsg("column \"%s\" of relation \"%s\" does not exist",
1549                                                 column, tablerv->relname)));
1550
1551         /* Search the dependency table for the dependent sequence */
1552         depRel = heap_open(DependRelationId, AccessShareLock);
1553
1554         ScanKeyInit(&key[0],
1555                                 Anum_pg_depend_refclassid,
1556                                 BTEqualStrategyNumber, F_OIDEQ,
1557                                 ObjectIdGetDatum(RelationRelationId));
1558         ScanKeyInit(&key[1],
1559                                 Anum_pg_depend_refobjid,
1560                                 BTEqualStrategyNumber, F_OIDEQ,
1561                                 ObjectIdGetDatum(tableOid));
1562         ScanKeyInit(&key[2],
1563                                 Anum_pg_depend_refobjsubid,
1564                                 BTEqualStrategyNumber, F_INT4EQ,
1565                                 Int32GetDatum(attnum));
1566
1567         scan = systable_beginscan(depRel, DependReferenceIndexId, true,
1568                                                           SnapshotNow, 3, key);
1569
1570         while (HeapTupleIsValid(tup = systable_getnext(scan)))
1571         {
1572                 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
1573
1574                 /*
1575                  * We assume any auto dependency of a sequence on a column must be
1576                  * what we are looking for.  (We need the relkind test because indexes
1577                  * can also have auto dependencies on columns.)
1578                  */
1579                 if (deprec->classid == RelationRelationId &&
1580                         deprec->objsubid == 0 &&
1581                         deprec->deptype == DEPENDENCY_AUTO &&
1582                         get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
1583                 {
1584                         sequenceId = deprec->objid;
1585                         break;
1586                 }
1587         }
1588
1589         systable_endscan(scan);
1590         heap_close(depRel, AccessShareLock);
1591
1592         if (OidIsValid(sequenceId))
1593         {
1594                 HeapTuple       classtup;
1595                 Form_pg_class classtuple;
1596                 char       *nspname;
1597                 char       *result;
1598
1599                 /* Get the sequence's pg_class entry */
1600                 classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(sequenceId));
1601                 if (!HeapTupleIsValid(classtup))
1602                         elog(ERROR, "cache lookup failed for relation %u", sequenceId);
1603                 classtuple = (Form_pg_class) GETSTRUCT(classtup);
1604
1605                 /* Get the namespace */
1606                 nspname = get_namespace_name(classtuple->relnamespace);
1607                 if (!nspname)
1608                         elog(ERROR, "cache lookup failed for namespace %u",
1609                                  classtuple->relnamespace);
1610
1611                 /* And construct the result string */
1612                 result = quote_qualified_identifier(nspname,
1613                                                                                         NameStr(classtuple->relname));
1614
1615                 ReleaseSysCache(classtup);
1616
1617                 PG_RETURN_TEXT_P(string_to_text(result));
1618         }
1619
1620         PG_RETURN_NULL();
1621 }
1622
1623
1624 /*
1625  * pg_get_functiondef
1626  *              Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
1627  *              the specified function.
1628  *
1629  * Note: if you change the output format of this function, be careful not
1630  * to break psql's rules (in \ef and \sf) for identifying the start of the
1631  * function body.  To wit: the function body starts on a line that begins
1632  * with "AS ", and no preceding line will look like that.
1633  */
1634 Datum
1635 pg_get_functiondef(PG_FUNCTION_ARGS)
1636 {
1637         Oid                     funcid = PG_GETARG_OID(0);
1638         StringInfoData buf;
1639         StringInfoData dq;
1640         HeapTuple       proctup;
1641         HeapTuple       langtup;
1642         Form_pg_proc proc;
1643         Form_pg_language lang;
1644         Datum           tmp;
1645         bool            isnull;
1646         const char *prosrc;
1647         const char *name;
1648         const char *nsp;
1649         float4          procost;
1650         int                     oldlen;
1651
1652         initStringInfo(&buf);
1653
1654         /* Look up the function */
1655         proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1656         if (!HeapTupleIsValid(proctup))
1657                 elog(ERROR, "cache lookup failed for function %u", funcid);
1658         proc = (Form_pg_proc) GETSTRUCT(proctup);
1659         name = NameStr(proc->proname);
1660
1661         if (proc->proisagg)
1662                 ereport(ERROR,
1663                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1664                                  errmsg("\"%s\" is an aggregate function", name)));
1665
1666         /* Need its pg_language tuple for the language name */
1667         langtup = SearchSysCache1(LANGOID, ObjectIdGetDatum(proc->prolang));
1668         if (!HeapTupleIsValid(langtup))
1669                 elog(ERROR, "cache lookup failed for language %u", proc->prolang);
1670         lang = (Form_pg_language) GETSTRUCT(langtup);
1671
1672         /*
1673          * We always qualify the function name, to ensure the right function gets
1674          * replaced.
1675          */
1676         nsp = get_namespace_name(proc->pronamespace);
1677         appendStringInfo(&buf, "CREATE OR REPLACE FUNCTION %s(",
1678                                          quote_qualified_identifier(nsp, name));
1679         (void) print_function_arguments(&buf, proctup, false, true);
1680         appendStringInfoString(&buf, ")\n RETURNS ");
1681         print_function_rettype(&buf, proctup);
1682         appendStringInfo(&buf, "\n LANGUAGE %s\n",
1683                                          quote_identifier(NameStr(lang->lanname)));
1684
1685         /* Emit some miscellaneous options on one line */
1686         oldlen = buf.len;
1687
1688         if (proc->proiswindow)
1689                 appendStringInfoString(&buf, " WINDOW");
1690         switch (proc->provolatile)
1691         {
1692                 case PROVOLATILE_IMMUTABLE:
1693                         appendStringInfoString(&buf, " IMMUTABLE");
1694                         break;
1695                 case PROVOLATILE_STABLE:
1696                         appendStringInfoString(&buf, " STABLE");
1697                         break;
1698                 case PROVOLATILE_VOLATILE:
1699                         break;
1700         }
1701         if (proc->proisstrict)
1702                 appendStringInfoString(&buf, " STRICT");
1703         if (proc->prosecdef)
1704                 appendStringInfoString(&buf, " SECURITY DEFINER");
1705
1706         /* This code for the default cost and rows should match functioncmds.c */
1707         if (proc->prolang == INTERNALlanguageId ||
1708                 proc->prolang == ClanguageId)
1709                 procost = 1;
1710         else
1711                 procost = 100;
1712         if (proc->procost != procost)
1713                 appendStringInfo(&buf, " COST %g", proc->procost);
1714
1715         if (proc->prorows > 0 && proc->prorows != 1000)
1716                 appendStringInfo(&buf, " ROWS %g", proc->prorows);
1717
1718         if (oldlen != buf.len)
1719                 appendStringInfoChar(&buf, '\n');
1720
1721         /* Emit any proconfig options, one per line */
1722         tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
1723         if (!isnull)
1724         {
1725                 ArrayType  *a = DatumGetArrayTypeP(tmp);
1726                 int                     i;
1727
1728                 Assert(ARR_ELEMTYPE(a) == TEXTOID);
1729                 Assert(ARR_NDIM(a) == 1);
1730                 Assert(ARR_LBOUND(a)[0] == 1);
1731
1732                 for (i = 1; i <= ARR_DIMS(a)[0]; i++)
1733                 {
1734                         Datum           d;
1735
1736                         d = array_ref(a, 1, &i,
1737                                                   -1 /* varlenarray */ ,
1738                                                   -1 /* TEXT's typlen */ ,
1739                                                   false /* TEXT's typbyval */ ,
1740                                                   'i' /* TEXT's typalign */ ,
1741                                                   &isnull);
1742                         if (!isnull)
1743                         {
1744                                 char       *configitem = TextDatumGetCString(d);
1745                                 char       *pos;
1746
1747                                 pos = strchr(configitem, '=');
1748                                 if (pos == NULL)
1749                                         continue;
1750                                 *pos++ = '\0';
1751
1752                                 appendStringInfo(&buf, " SET %s TO ",
1753                                                                  quote_identifier(configitem));
1754
1755                                 /*
1756                                  * Some GUC variable names are 'LIST' type and hence must not
1757                                  * be quoted.
1758                                  */
1759                                 if (pg_strcasecmp(configitem, "DateStyle") == 0
1760                                         || pg_strcasecmp(configitem, "search_path") == 0)
1761                                         appendStringInfoString(&buf, pos);
1762                                 else
1763                                         simple_quote_literal(&buf, pos);
1764                                 appendStringInfoChar(&buf, '\n');
1765                         }
1766                 }
1767         }
1768
1769         /* And finally the function definition ... */
1770         appendStringInfoString(&buf, "AS ");
1771
1772         tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
1773         if (!isnull)
1774         {
1775                 simple_quote_literal(&buf, TextDatumGetCString(tmp));
1776                 appendStringInfoString(&buf, ", ");             /* assume prosrc isn't null */
1777         }
1778
1779         tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosrc, &isnull);
1780         if (isnull)
1781                 elog(ERROR, "null prosrc");
1782         prosrc = TextDatumGetCString(tmp);
1783
1784         /*
1785          * We always use dollar quoting.  Figure out a suitable delimiter.
1786          *
1787          * Since the user is likely to be editing the function body string, we
1788          * shouldn't use a short delimiter that he might easily create a conflict
1789          * with.  Hence prefer "$function$", but extend if needed.
1790          */
1791         initStringInfo(&dq);
1792         appendStringInfoString(&dq, "$function");
1793         while (strstr(prosrc, dq.data) != NULL)
1794                 appendStringInfoChar(&dq, 'x');
1795         appendStringInfoChar(&dq, '$');
1796
1797         appendStringInfoString(&buf, dq.data);
1798         appendStringInfoString(&buf, prosrc);
1799         appendStringInfoString(&buf, dq.data);
1800
1801         appendStringInfoString(&buf, "\n");
1802
1803         ReleaseSysCache(langtup);
1804         ReleaseSysCache(proctup);
1805
1806         PG_RETURN_TEXT_P(string_to_text(buf.data));
1807 }
1808
1809 /*
1810  * pg_get_function_arguments
1811  *              Get a nicely-formatted list of arguments for a function.
1812  *              This is everything that would go between the parentheses in
1813  *              CREATE FUNCTION.
1814  */
1815 Datum
1816 pg_get_function_arguments(PG_FUNCTION_ARGS)
1817 {
1818         Oid                     funcid = PG_GETARG_OID(0);
1819         StringInfoData buf;
1820         HeapTuple       proctup;
1821
1822         initStringInfo(&buf);
1823
1824         proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1825         if (!HeapTupleIsValid(proctup))
1826                 elog(ERROR, "cache lookup failed for function %u", funcid);
1827
1828         (void) print_function_arguments(&buf, proctup, false, true);
1829
1830         ReleaseSysCache(proctup);
1831
1832         PG_RETURN_TEXT_P(string_to_text(buf.data));
1833 }
1834
1835 /*
1836  * pg_get_function_identity_arguments
1837  *              Get a formatted list of arguments for a function.
1838  *              This is everything that would go between the parentheses in
1839  *              ALTER FUNCTION, etc.  In particular, don't print defaults.
1840  */
1841 Datum
1842 pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
1843 {
1844         Oid                     funcid = PG_GETARG_OID(0);
1845         StringInfoData buf;
1846         HeapTuple       proctup;
1847
1848         initStringInfo(&buf);
1849
1850         proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1851         if (!HeapTupleIsValid(proctup))
1852                 elog(ERROR, "cache lookup failed for function %u", funcid);
1853
1854         (void) print_function_arguments(&buf, proctup, false, false);
1855
1856         ReleaseSysCache(proctup);
1857
1858         PG_RETURN_TEXT_P(string_to_text(buf.data));
1859 }
1860
1861 /*
1862  * pg_get_function_result
1863  *              Get a nicely-formatted version of the result type of a function.
1864  *              This is what would appear after RETURNS in CREATE FUNCTION.
1865  */
1866 Datum
1867 pg_get_function_result(PG_FUNCTION_ARGS)
1868 {
1869         Oid                     funcid = PG_GETARG_OID(0);
1870         StringInfoData buf;
1871         HeapTuple       proctup;
1872
1873         initStringInfo(&buf);
1874
1875         proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1876         if (!HeapTupleIsValid(proctup))
1877                 elog(ERROR, "cache lookup failed for function %u", funcid);
1878
1879         print_function_rettype(&buf, proctup);
1880
1881         ReleaseSysCache(proctup);
1882
1883         PG_RETURN_TEXT_P(string_to_text(buf.data));
1884 }
1885
1886 /*
1887  * Guts of pg_get_function_result: append the function's return type
1888  * to the specified buffer.
1889  */
1890 static void
1891 print_function_rettype(StringInfo buf, HeapTuple proctup)
1892 {
1893         Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
1894         int                     ntabargs = 0;
1895         StringInfoData rbuf;
1896
1897         initStringInfo(&rbuf);
1898
1899         if (proc->proretset)
1900         {
1901                 /* It might be a table function; try to print the arguments */
1902                 appendStringInfoString(&rbuf, "TABLE(");
1903                 ntabargs = print_function_arguments(&rbuf, proctup, true, false);
1904                 if (ntabargs > 0)
1905                         appendStringInfoString(&rbuf, ")");
1906                 else
1907                         resetStringInfo(&rbuf);
1908         }
1909
1910         if (ntabargs == 0)
1911         {
1912                 /* Not a table function, so do the normal thing */
1913                 if (proc->proretset)
1914                         appendStringInfoString(&rbuf, "SETOF ");
1915                 appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
1916         }
1917
1918         appendStringInfoString(buf, rbuf.data);
1919 }
1920
1921 /*
1922  * Common code for pg_get_function_arguments and pg_get_function_result:
1923  * append the desired subset of arguments to buf.  We print only TABLE
1924  * arguments when print_table_args is true, and all the others when it's false.
1925  * We print argument defaults only if print_defaults is true.
1926  * Function return value is the number of arguments printed.
1927  */
1928 static int
1929 print_function_arguments(StringInfo buf, HeapTuple proctup,
1930                                                  bool print_table_args, bool print_defaults)
1931 {
1932         Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
1933         int                     numargs;
1934         Oid                *argtypes;
1935         char      **argnames;
1936         char       *argmodes;
1937         int                     argsprinted;
1938         int                     inputargno;
1939         int                     nlackdefaults;
1940         ListCell   *nextargdefault = NULL;
1941         int                     i;
1942
1943         numargs = get_func_arg_info(proctup,
1944                                                                 &argtypes, &argnames, &argmodes);
1945
1946         nlackdefaults = numargs;
1947         if (print_defaults && proc->pronargdefaults > 0)
1948         {
1949                 Datum           proargdefaults;
1950                 bool            isnull;
1951
1952                 proargdefaults = SysCacheGetAttr(PROCOID, proctup,
1953                                                                                  Anum_pg_proc_proargdefaults,
1954                                                                                  &isnull);
1955                 if (!isnull)
1956                 {
1957                         char       *str;
1958                         List       *argdefaults;
1959
1960                         str = TextDatumGetCString(proargdefaults);
1961                         argdefaults = (List *) stringToNode(str);
1962                         Assert(IsA(argdefaults, List));
1963                         pfree(str);
1964                         nextargdefault = list_head(argdefaults);
1965                         /* nlackdefaults counts only *input* arguments lacking defaults */
1966                         nlackdefaults = proc->pronargs - list_length(argdefaults);
1967                 }
1968         }
1969
1970         argsprinted = 0;
1971         inputargno = 0;
1972         for (i = 0; i < numargs; i++)
1973         {
1974                 Oid                     argtype = argtypes[i];
1975                 char       *argname = argnames ? argnames[i] : NULL;
1976                 char            argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
1977                 const char *modename;
1978                 bool            isinput;
1979
1980                 switch (argmode)
1981                 {
1982                         case PROARGMODE_IN:
1983                                 modename = "";
1984                                 isinput = true;
1985                                 break;
1986                         case PROARGMODE_INOUT:
1987                                 modename = "INOUT ";
1988                                 isinput = true;
1989                                 break;
1990                         case PROARGMODE_OUT:
1991                                 modename = "OUT ";
1992                                 isinput = false;
1993                                 break;
1994                         case PROARGMODE_VARIADIC:
1995                                 modename = "VARIADIC ";
1996                                 isinput = true;
1997                                 break;
1998                         case PROARGMODE_TABLE:
1999                                 modename = "";
2000                                 isinput = false;
2001                                 break;
2002                         default:
2003                                 elog(ERROR, "invalid parameter mode '%c'", argmode);
2004                                 modename = NULL;        /* keep compiler quiet */
2005                                 isinput = false;
2006                                 break;
2007                 }
2008                 if (isinput)
2009                         inputargno++;           /* this is a 1-based counter */
2010
2011                 if (print_table_args != (argmode == PROARGMODE_TABLE))
2012                         continue;
2013
2014                 if (argsprinted)
2015                         appendStringInfoString(buf, ", ");
2016                 appendStringInfoString(buf, modename);
2017                 if (argname && argname[0])
2018                         appendStringInfo(buf, "%s ", quote_identifier(argname));
2019                 appendStringInfoString(buf, format_type_be(argtype));
2020                 if (print_defaults && isinput && inputargno > nlackdefaults)
2021                 {
2022                         Node       *expr;
2023
2024                         Assert(nextargdefault != NULL);
2025                         expr = (Node *) lfirst(nextargdefault);
2026                         nextargdefault = lnext(nextargdefault);
2027
2028                         appendStringInfo(buf, " DEFAULT %s",
2029                                                          deparse_expression(expr, NIL, false, false));
2030                 }
2031                 argsprinted++;
2032         }
2033
2034         return argsprinted;
2035 }
2036
2037
2038 /*
2039  * deparse_expression                   - General utility for deparsing expressions
2040  *
2041  * calls deparse_expression_pretty with all prettyPrinting disabled
2042  */
2043 char *
2044 deparse_expression(Node *expr, List *dpcontext,
2045                                    bool forceprefix, bool showimplicit)
2046 {
2047         return deparse_expression_pretty(expr, dpcontext, forceprefix,
2048                                                                          showimplicit, 0, 0);
2049 }
2050
2051 /* ----------
2052  * deparse_expression_pretty    - General utility for deparsing expressions
2053  *
2054  * expr is the node tree to be deparsed.  It must be a transformed expression
2055  * tree (ie, not the raw output of gram.y).
2056  *
2057  * dpcontext is a list of deparse_namespace nodes representing the context
2058  * for interpreting Vars in the node tree.
2059  *
2060  * forceprefix is TRUE to force all Vars to be prefixed with their table names.
2061  *
2062  * showimplicit is TRUE to force all implicit casts to be shown explicitly.
2063  *
2064  * tries to pretty up the output according to prettyFlags and startIndent.
2065  *
2066  * The result is a palloc'd string.
2067  * ----------
2068  */
2069 static char *
2070 deparse_expression_pretty(Node *expr, List *dpcontext,
2071                                                   bool forceprefix, bool showimplicit,
2072                                                   int prettyFlags, int startIndent)
2073 {
2074         StringInfoData buf;
2075         deparse_context context;
2076
2077         initStringInfo(&buf);
2078         context.buf = &buf;
2079         context.namespaces = dpcontext;
2080         context.windowClause = NIL;
2081         context.windowTList = NIL;
2082         context.varprefix = forceprefix;
2083         context.prettyFlags = prettyFlags;
2084         context.indentLevel = startIndent;
2085
2086         get_rule_expr(expr, &context, showimplicit);
2087
2088         return buf.data;
2089 }
2090
2091 /* ----------
2092  * deparse_context_for                  - Build deparse context for a single relation
2093  *
2094  * Given the reference name (alias) and OID of a relation, build deparsing
2095  * context for an expression referencing only that relation (as varno 1,
2096  * varlevelsup 0).      This is sufficient for many uses of deparse_expression.
2097  * ----------
2098  */
2099 List *
2100 deparse_context_for(const char *aliasname, Oid relid)
2101 {
2102         deparse_namespace *dpns;
2103         RangeTblEntry *rte;
2104
2105         dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
2106
2107         /* Build a minimal RTE for the rel */
2108         rte = makeNode(RangeTblEntry);
2109         rte->rtekind = RTE_RELATION;
2110         rte->relid = relid;
2111         rte->eref = makeAlias(aliasname, NIL);
2112         rte->inh = false;
2113         rte->inFromCl = true;
2114
2115         /* Build one-element rtable */
2116         dpns->rtable = list_make1(rte);
2117         dpns->ctes = NIL;
2118
2119         /* Return a one-deep namespace stack */
2120         return list_make1(dpns);
2121 }
2122
2123 /*
2124  * deparse_context_for_planstate        - Build deparse context for a plan
2125  *
2126  * When deparsing an expression in a Plan tree, we might have to resolve
2127  * OUTER or INNER references.  To do this, the caller must provide the
2128  * parent PlanState node.  Then OUTER and INNER references can be resolved
2129  * by drilling down into the left and right child plans.
2130  *
2131  * Note: planstate really ought to be declared as "PlanState *", but we use
2132  * "Node *" to avoid having to include execnodes.h in builtins.h.
2133  *
2134  * The ancestors list is a list of the PlanState's parent PlanStates, the
2135  * most-closely-nested first.  This is needed to resolve PARAM_EXEC Params.
2136  * Note we assume that all the PlanStates share the same rtable.
2137  *
2138  * The plan's rangetable list must also be passed.  We actually prefer to use
2139  * the rangetable to resolve simple Vars, but the plan inputs are necessary
2140  * for Vars that reference expressions computed in subplan target lists.
2141  */
2142 List *
2143 deparse_context_for_planstate(Node *planstate, List *ancestors,
2144                                                           List *rtable)
2145 {
2146         deparse_namespace *dpns;
2147
2148         dpns = (deparse_namespace *) palloc0(sizeof(deparse_namespace));
2149
2150         /* Initialize fields that stay the same across the whole plan tree */
2151         dpns->rtable = rtable;
2152         dpns->ctes = NIL;
2153
2154         /* Set our attention on the specific plan node passed in */
2155         set_deparse_planstate(dpns, (PlanState *) planstate);
2156         dpns->ancestors = ancestors;
2157
2158         /* Return a one-deep namespace stack */
2159         return list_make1(dpns);
2160 }
2161
2162 /*
2163  * set_deparse_planstate: set up deparse_namespace to parse subexpressions
2164  * of a given PlanState node
2165  *
2166  * This sets the planstate, outer_planstate, inner_planstate, outer_plan, and
2167  * inner_plan fields.  Caller is responsible for adjusting the ancestors list
2168  * if necessary.  Note that the rtable and ctes fields do not need to change
2169  * when shifting attention to different plan nodes in a single plan tree.
2170  */
2171 static void
2172 set_deparse_planstate(deparse_namespace *dpns, PlanState *ps)
2173 {
2174         dpns->planstate = ps;
2175
2176         /*
2177          * We special-case Append and MergeAppend to pretend that the first child
2178          * plan is the OUTER referent; we have to interpret OUTER Vars in their
2179          * tlists according to one of the children, and the first one is the most
2180          * natural choice.  Likewise special-case ModifyTable to pretend that the
2181          * first child plan is the OUTER referent; this is to support RETURNING
2182          * lists containing references to non-target relations.
2183          */
2184         if (IsA(ps, AppendState))
2185                 dpns->outer_planstate = ((AppendState *) ps)->appendplans[0];
2186         else if (IsA(ps, MergeAppendState))
2187                 dpns->outer_planstate = ((MergeAppendState *) ps)->mergeplans[0];
2188         else if (IsA(ps, ModifyTableState))
2189                 dpns->outer_planstate = ((ModifyTableState *) ps)->mt_plans[0];
2190         else
2191                 dpns->outer_planstate = outerPlanState(ps);
2192
2193         if (dpns->outer_planstate)
2194                 dpns->outer_plan = dpns->outer_planstate->plan;
2195         else
2196                 dpns->outer_plan = NULL;
2197
2198         /*
2199          * For a SubqueryScan, pretend the subplan is INNER referent.  (We don't
2200          * use OUTER because that could someday conflict with the normal meaning.)
2201          * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
2202          */
2203         if (IsA(ps, SubqueryScanState))
2204                 dpns->inner_planstate = ((SubqueryScanState *) ps)->subplan;
2205         else if (IsA(ps, CteScanState))
2206                 dpns->inner_planstate = ((CteScanState *) ps)->cteplanstate;
2207         else
2208                 dpns->inner_planstate = innerPlanState(ps);
2209
2210         if (dpns->inner_planstate)
2211                 dpns->inner_plan = dpns->inner_planstate->plan;
2212         else
2213                 dpns->inner_plan = NULL;
2214 }
2215
2216 /*
2217  * push_child_plan: temporarily transfer deparsing attention to a child plan
2218  *
2219  * When expanding an OUTER or INNER reference, we must adjust the deparse
2220  * context in case the referenced expression itself uses OUTER/INNER.   We
2221  * modify the top stack entry in-place to avoid affecting levelsup issues
2222  * (although in a Plan tree there really shouldn't be any).
2223  *
2224  * Caller must provide a local deparse_namespace variable to save the
2225  * previous state for pop_child_plan.
2226  */
2227 static void
2228 push_child_plan(deparse_namespace *dpns, PlanState *ps,
2229                                 deparse_namespace *save_dpns)
2230 {
2231         /* Save state for restoration later */
2232         *save_dpns = *dpns;
2233
2234         /*
2235          * Currently we don't bother to adjust the ancestors list, because an
2236          * OUTER or INNER reference really shouldn't contain any Params that
2237          * would be set by the parent node itself.  If we did want to adjust it,
2238          * lcons'ing dpns->planstate onto dpns->ancestors would be the appropriate
2239          * thing --- and pop_child_plan would need to undo the change to the list.
2240          */
2241
2242         /* Set attention on selected child */
2243         set_deparse_planstate(dpns, ps);
2244 }
2245
2246 /*
2247  * pop_child_plan: undo the effects of push_child_plan
2248  */
2249 static void
2250 pop_child_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
2251 {
2252         /* Restore fields changed by push_child_plan */
2253         *dpns = *save_dpns;
2254 }
2255
2256 /*
2257  * push_ancestor_plan: temporarily transfer deparsing attention to an
2258  * ancestor plan
2259  *
2260  * When expanding a Param reference, we must adjust the deparse context
2261  * to match the plan node that contains the expression being printed;
2262  * otherwise we'd fail if that expression itself contains a Param or
2263  * OUTER/INNER variables.
2264  *
2265  * The target ancestor is conveniently identified by the ListCell holding it
2266  * in dpns->ancestors.
2267  *
2268  * Caller must provide a local deparse_namespace variable to save the
2269  * previous state for pop_ancestor_plan.
2270  */
2271 static void
2272 push_ancestor_plan(deparse_namespace *dpns, ListCell *ancestor_cell,
2273                                    deparse_namespace *save_dpns)
2274 {
2275         PlanState  *ps = (PlanState *) lfirst(ancestor_cell);
2276         List       *ancestors;
2277
2278         /* Save state for restoration later */
2279         *save_dpns = *dpns;
2280
2281         /* Build a new ancestor list with just this node's ancestors */
2282         ancestors = NIL;
2283         while ((ancestor_cell = lnext(ancestor_cell)) != NULL)
2284                 ancestors = lappend(ancestors, lfirst(ancestor_cell));
2285         dpns->ancestors = ancestors;
2286
2287         /* Set attention on selected ancestor */
2288         set_deparse_planstate(dpns, ps);
2289 }
2290
2291 /*
2292  * pop_ancestor_plan: undo the effects of push_ancestor_plan
2293  */
2294 static void
2295 pop_ancestor_plan(deparse_namespace *dpns, deparse_namespace *save_dpns)
2296 {
2297         /* Free the ancestor list made in push_ancestor_plan */
2298         list_free(dpns->ancestors);
2299
2300         /* Restore fields changed by push_ancestor_plan */
2301         *dpns = *save_dpns;
2302 }
2303
2304
2305 /* ----------
2306  * make_ruledef                 - reconstruct the CREATE RULE command
2307  *                                for a given pg_rewrite tuple
2308  * ----------
2309  */
2310 static void
2311 make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
2312                          int prettyFlags)
2313 {
2314         char       *rulename;
2315         char            ev_type;
2316         Oid                     ev_class;
2317         int2            ev_attr;
2318         bool            is_instead;
2319         char       *ev_qual;
2320         char       *ev_action;
2321         List       *actions = NIL;
2322         int                     fno;
2323         Datum           dat;
2324         bool            isnull;
2325
2326         /*
2327          * Get the attribute values from the rules tuple
2328          */
2329         fno = SPI_fnumber(rulettc, "rulename");
2330         dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2331         Assert(!isnull);
2332         rulename = NameStr(*(DatumGetName(dat)));
2333
2334         fno = SPI_fnumber(rulettc, "ev_type");
2335         dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2336         Assert(!isnull);
2337         ev_type = DatumGetChar(dat);
2338
2339         fno = SPI_fnumber(rulettc, "ev_class");
2340         dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2341         Assert(!isnull);
2342         ev_class = DatumGetObjectId(dat);
2343
2344         fno = SPI_fnumber(rulettc, "ev_attr");
2345         dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2346         Assert(!isnull);
2347         ev_attr = DatumGetInt16(dat);
2348
2349         fno = SPI_fnumber(rulettc, "is_instead");
2350         dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2351         Assert(!isnull);
2352         is_instead = DatumGetBool(dat);
2353
2354         /* these could be nulls */
2355         fno = SPI_fnumber(rulettc, "ev_qual");
2356         ev_qual = SPI_getvalue(ruletup, rulettc, fno);
2357
2358         fno = SPI_fnumber(rulettc, "ev_action");
2359         ev_action = SPI_getvalue(ruletup, rulettc, fno);
2360         if (ev_action != NULL)
2361                 actions = (List *) stringToNode(ev_action);
2362
2363         /*
2364          * Build the rules definition text
2365          */
2366         appendStringInfo(buf, "CREATE RULE %s AS",
2367                                          quote_identifier(rulename));
2368
2369         if (prettyFlags & PRETTYFLAG_INDENT)
2370                 appendStringInfoString(buf, "\n    ON ");
2371         else
2372                 appendStringInfoString(buf, " ON ");
2373
2374         /* The event the rule is fired for */
2375         switch (ev_type)
2376         {
2377                 case '1':
2378                         appendStringInfo(buf, "SELECT");
2379                         break;
2380
2381                 case '2':
2382                         appendStringInfo(buf, "UPDATE");
2383                         break;
2384
2385                 case '3':
2386                         appendStringInfo(buf, "INSERT");
2387                         break;
2388
2389                 case '4':
2390                         appendStringInfo(buf, "DELETE");
2391                         break;
2392
2393                 default:
2394                         ereport(ERROR,
2395                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2396                                          errmsg("rule \"%s\" has unsupported event type %d",
2397                                                         rulename, ev_type)));
2398                         break;
2399         }
2400
2401         /* The relation the rule is fired on */
2402         appendStringInfo(buf, " TO %s", generate_relation_name(ev_class, NIL));
2403         if (ev_attr > 0)
2404                 appendStringInfo(buf, ".%s",
2405                                                  quote_identifier(get_relid_attribute_name(ev_class,
2406                                                                                                                                    ev_attr)));
2407
2408         /* If the rule has an event qualification, add it */
2409         if (ev_qual == NULL)
2410                 ev_qual = "";
2411         if (strlen(ev_qual) > 0 && strcmp(ev_qual, "<>") != 0)
2412         {
2413                 Node       *qual;
2414                 Query      *query;
2415                 deparse_context context;
2416                 deparse_namespace dpns;
2417
2418                 if (prettyFlags & PRETTYFLAG_INDENT)
2419                         appendStringInfoString(buf, "\n  ");
2420                 appendStringInfo(buf, " WHERE ");
2421
2422                 qual = stringToNode(ev_qual);
2423
2424                 /*
2425                  * We need to make a context for recognizing any Vars in the qual
2426                  * (which can only be references to OLD and NEW).  Use the rtable of
2427                  * the first query in the action list for this purpose.
2428                  */
2429                 query = (Query *) linitial(actions);
2430
2431                 /*
2432                  * If the action is INSERT...SELECT, OLD/NEW have been pushed down
2433                  * into the SELECT, and that's what we need to look at. (Ugly kluge
2434                  * ... try to fix this when we redesign querytrees.)
2435                  */
2436                 query = getInsertSelectQuery(query, NULL);
2437
2438                 /* Must acquire locks right away; see notes in get_query_def() */
2439                 AcquireRewriteLocks(query, false);
2440
2441                 context.buf = buf;
2442                 context.namespaces = list_make1(&dpns);
2443                 context.windowClause = NIL;
2444                 context.windowTList = NIL;
2445                 context.varprefix = (list_length(query->rtable) != 1);
2446                 context.prettyFlags = prettyFlags;
2447                 context.indentLevel = PRETTYINDENT_STD;
2448
2449                 memset(&dpns, 0, sizeof(dpns));
2450                 dpns.rtable = query->rtable;
2451                 dpns.ctes = query->cteList;
2452
2453                 get_rule_expr(qual, &context, false);
2454         }
2455
2456         appendStringInfo(buf, " DO ");
2457
2458         /* The INSTEAD keyword (if so) */
2459         if (is_instead)
2460                 appendStringInfo(buf, "INSTEAD ");
2461
2462         /* Finally the rules actions */
2463         if (list_length(actions) > 1)
2464         {
2465                 ListCell   *action;
2466                 Query      *query;
2467
2468                 appendStringInfo(buf, "(");
2469                 foreach(action, actions)
2470                 {
2471                         query = (Query *) lfirst(action);
2472                         get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
2473                         if (prettyFlags)
2474                                 appendStringInfo(buf, ";\n");
2475                         else
2476                                 appendStringInfo(buf, "; ");
2477                 }
2478                 appendStringInfo(buf, ");");
2479         }
2480         else if (list_length(actions) == 0)
2481         {
2482                 appendStringInfo(buf, "NOTHING;");
2483         }
2484         else
2485         {
2486                 Query      *query;
2487
2488                 query = (Query *) linitial(actions);
2489                 get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
2490                 appendStringInfo(buf, ";");
2491         }
2492 }
2493
2494
2495 /* ----------
2496  * make_viewdef                 - reconstruct the SELECT part of a
2497  *                                view rewrite rule
2498  * ----------
2499  */
2500 static void
2501 make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
2502                          int prettyFlags)
2503 {
2504         Query      *query;
2505         char            ev_type;
2506         Oid                     ev_class;
2507         int2            ev_attr;
2508         bool            is_instead;
2509         char       *ev_qual;
2510         char       *ev_action;
2511         List       *actions = NIL;
2512         Relation        ev_relation;
2513         int                     fno;
2514         bool            isnull;
2515
2516         /*
2517          * Get the attribute values from the rules tuple
2518          */
2519         fno = SPI_fnumber(rulettc, "ev_type");
2520         ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2521
2522         fno = SPI_fnumber(rulettc, "ev_class");
2523         ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2524
2525         fno = SPI_fnumber(rulettc, "ev_attr");
2526         ev_attr = (int2) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2527
2528         fno = SPI_fnumber(rulettc, "is_instead");
2529         is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2530
2531         fno = SPI_fnumber(rulettc, "ev_qual");
2532         ev_qual = SPI_getvalue(ruletup, rulettc, fno);
2533
2534         fno = SPI_fnumber(rulettc, "ev_action");
2535         ev_action = SPI_getvalue(ruletup, rulettc, fno);
2536         if (ev_action != NULL)
2537                 actions = (List *) stringToNode(ev_action);
2538
2539         if (list_length(actions) != 1)
2540         {
2541                 appendStringInfo(buf, "Not a view");
2542                 return;
2543         }
2544
2545         query = (Query *) linitial(actions);
2546
2547         if (ev_type != '1' || ev_attr >= 0 || !is_instead ||
2548                 strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
2549         {
2550                 appendStringInfo(buf, "Not a view");
2551                 return;
2552         }
2553
2554         ev_relation = heap_open(ev_class, AccessShareLock);
2555
2556         get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),
2557                                   prettyFlags, 0);
2558         appendStringInfo(buf, ";");
2559
2560         heap_close(ev_relation, AccessShareLock);
2561 }
2562
2563
2564 /* ----------
2565  * get_query_def                        - Parse back one query parsetree
2566  *
2567  * If resultDesc is not NULL, then it is the output tuple descriptor for
2568  * the view represented by a SELECT query.
2569  * ----------
2570  */
2571 static void
2572 get_query_def(Query *query, StringInfo buf, List *parentnamespace,
2573                           TupleDesc resultDesc, int prettyFlags, int startIndent)
2574 {
2575         deparse_context context;
2576         deparse_namespace dpns;
2577
2578         /*
2579          * Before we begin to examine the query, acquire locks on referenced
2580          * relations, and fix up deleted columns in JOIN RTEs.  This ensures
2581          * consistent results.  Note we assume it's OK to scribble on the passed
2582          * querytree!
2583          */
2584         AcquireRewriteLocks(query, false);
2585
2586         context.buf = buf;
2587         context.namespaces = lcons(&dpns, list_copy(parentnamespace));
2588         context.windowClause = NIL;
2589         context.windowTList = NIL;
2590         context.varprefix = (parentnamespace != NIL ||
2591                                                  list_length(query->rtable) != 1);
2592         context.prettyFlags = prettyFlags;
2593         context.indentLevel = startIndent;
2594
2595         memset(&dpns, 0, sizeof(dpns));
2596         dpns.rtable = query->rtable;
2597         dpns.ctes = query->cteList;
2598
2599         switch (query->commandType)
2600         {
2601                 case CMD_SELECT:
2602                         get_select_query_def(query, &context, resultDesc);
2603                         break;
2604
2605                 case CMD_UPDATE:
2606                         get_update_query_def(query, &context);
2607                         break;
2608
2609                 case CMD_INSERT:
2610                         get_insert_query_def(query, &context);
2611                         break;
2612
2613                 case CMD_DELETE:
2614                         get_delete_query_def(query, &context);
2615                         break;
2616
2617                 case CMD_NOTHING:
2618                         appendStringInfo(buf, "NOTHING");
2619                         break;
2620
2621                 case CMD_UTILITY:
2622                         get_utility_query_def(query, &context);
2623                         break;
2624
2625                 default:
2626                         elog(ERROR, "unrecognized query command type: %d",
2627                                  query->commandType);
2628                         break;
2629         }
2630 }
2631
2632 /* ----------
2633  * get_values_def                       - Parse back a VALUES list
2634  * ----------
2635  */
2636 static void
2637 get_values_def(List *values_lists, deparse_context *context)
2638 {
2639         StringInfo      buf = context->buf;
2640         bool            first_list = true;
2641         ListCell   *vtl;
2642
2643         appendStringInfoString(buf, "VALUES ");
2644
2645         foreach(vtl, values_lists)
2646         {
2647                 List       *sublist = (List *) lfirst(vtl);
2648                 bool            first_col = true;
2649                 ListCell   *lc;
2650
2651                 if (first_list)
2652                         first_list = false;
2653                 else
2654                         appendStringInfoString(buf, ", ");
2655
2656                 appendStringInfoChar(buf, '(');
2657                 foreach(lc, sublist)
2658                 {
2659                         Node       *col = (Node *) lfirst(lc);
2660
2661                         if (first_col)
2662                                 first_col = false;
2663                         else
2664                                 appendStringInfoChar(buf, ',');
2665
2666                         /*
2667                          * Strip any top-level nodes representing indirection assignments,
2668                          * then print the result.
2669                          */
2670                         get_rule_expr(processIndirection(col, context, false),
2671                                                   context, false);
2672                 }
2673                 appendStringInfoChar(buf, ')');
2674         }
2675 }
2676
2677 /* ----------
2678  * get_with_clause                      - Parse back a WITH clause
2679  * ----------
2680  */
2681 static void
2682 get_with_clause(Query *query, deparse_context *context)
2683 {
2684         StringInfo      buf = context->buf;
2685         const char *sep;
2686         ListCell   *l;
2687
2688         if (query->cteList == NIL)
2689                 return;
2690
2691         if (PRETTY_INDENT(context))
2692         {
2693                 context->indentLevel += PRETTYINDENT_STD;
2694                 appendStringInfoChar(buf, ' ');
2695         }
2696
2697         if (query->hasRecursive)
2698                 sep = "WITH RECURSIVE ";
2699         else
2700                 sep = "WITH ";
2701         foreach(l, query->cteList)
2702         {
2703                 CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
2704
2705                 appendStringInfoString(buf, sep);
2706                 appendStringInfoString(buf, quote_identifier(cte->ctename));
2707                 if (cte->aliascolnames)
2708                 {
2709                         bool            first = true;
2710                         ListCell   *col;
2711
2712                         appendStringInfoChar(buf, '(');
2713                         foreach(col, cte->aliascolnames)
2714                         {
2715                                 if (first)
2716                                         first = false;
2717                                 else
2718                                         appendStringInfoString(buf, ", ");
2719                                 appendStringInfoString(buf,
2720                                                                            quote_identifier(strVal(lfirst(col))));
2721                         }
2722                         appendStringInfoChar(buf, ')');
2723                 }
2724                 appendStringInfoString(buf, " AS (");
2725                 if (PRETTY_INDENT(context))
2726                         appendContextKeyword(context, "", 0, 0, 0);
2727                 get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
2728                                           context->prettyFlags, context->indentLevel);
2729                 if (PRETTY_INDENT(context))
2730                         appendContextKeyword(context, "", 0, 0, 0);
2731                 appendStringInfoChar(buf, ')');
2732                 sep = ", ";
2733         }
2734
2735         if (PRETTY_INDENT(context))
2736         {
2737                 context->indentLevel -= PRETTYINDENT_STD;
2738                 appendContextKeyword(context, "", 0, 0, 0);
2739         }
2740         else
2741                 appendStringInfoChar(buf, ' ');
2742 }
2743
2744 /* ----------
2745  * get_select_query_def                 - Parse back a SELECT parsetree
2746  * ----------
2747  */
2748 static void
2749 get_select_query_def(Query *query, deparse_context *context,
2750                                          TupleDesc resultDesc)
2751 {
2752         StringInfo      buf = context->buf;
2753         List       *save_windowclause;
2754         List       *save_windowtlist;
2755         bool            force_colno;
2756         ListCell   *l;
2757
2758         /* Insert the WITH clause if given */
2759         get_with_clause(query, context);
2760
2761         /* Set up context for possible window functions */
2762         save_windowclause = context->windowClause;
2763         context->windowClause = query->windowClause;
2764         save_windowtlist = context->windowTList;
2765         context->windowTList = query->targetList;
2766
2767         /*
2768          * If the Query node has a setOperations tree, then it's the top level of
2769          * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
2770          * fields are interesting in the top query itself.
2771          */
2772         if (query->setOperations)
2773         {
2774                 get_setop_query(query->setOperations, query, context, resultDesc);
2775                 /* ORDER BY clauses must be simple in this case */
2776                 force_colno = true;
2777         }
2778         else
2779         {
2780                 get_basic_select_query(query, context, resultDesc);
2781                 force_colno = false;
2782         }
2783
2784         /* Add the ORDER BY clause if given */
2785         if (query->sortClause != NIL)
2786         {
2787                 appendContextKeyword(context, " ORDER BY ",
2788                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2789                 get_rule_orderby(query->sortClause, query->targetList,
2790                                                  force_colno, context);
2791         }
2792
2793         /* Add the LIMIT clause if given */
2794         if (query->limitOffset != NULL)
2795         {
2796                 appendContextKeyword(context, " OFFSET ",
2797                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2798                 get_rule_expr(query->limitOffset, context, false);
2799         }
2800         if (query->limitCount != NULL)
2801         {
2802                 appendContextKeyword(context, " LIMIT ",
2803                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2804                 if (IsA(query->limitCount, Const) &&
2805                         ((Const *) query->limitCount)->constisnull)
2806                         appendStringInfo(buf, "ALL");
2807                 else
2808                         get_rule_expr(query->limitCount, context, false);
2809         }
2810
2811         /* Add FOR UPDATE/SHARE clauses if present */
2812         if (query->hasForUpdate)
2813         {
2814                 foreach(l, query->rowMarks)
2815                 {
2816                         RowMarkClause *rc = (RowMarkClause *) lfirst(l);
2817                         RangeTblEntry *rte = rt_fetch(rc->rti, query->rtable);
2818
2819                         /* don't print implicit clauses */
2820                         if (rc->pushedDown)
2821                                 continue;
2822
2823                         if (rc->forUpdate)
2824                                 appendContextKeyword(context, " FOR UPDATE",
2825                                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2826                         else
2827                                 appendContextKeyword(context, " FOR SHARE",
2828                                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2829                         appendStringInfo(buf, " OF %s",
2830                                                          quote_identifier(rte->eref->aliasname));
2831                         if (rc->noWait)
2832                                 appendStringInfo(buf, " NOWAIT");
2833                 }
2834         }
2835
2836         context->windowClause = save_windowclause;
2837         context->windowTList = save_windowtlist;
2838 }
2839
2840 static void
2841 get_basic_select_query(Query *query, deparse_context *context,
2842                                            TupleDesc resultDesc)
2843 {
2844         StringInfo      buf = context->buf;
2845         char       *sep;
2846         ListCell   *l;
2847
2848         if (PRETTY_INDENT(context))
2849         {
2850                 context->indentLevel += PRETTYINDENT_STD;
2851                 appendStringInfoChar(buf, ' ');
2852         }
2853
2854         /*
2855          * If the query looks like SELECT * FROM (VALUES ...), then print just the
2856          * VALUES part.  This reverses what transformValuesClause() did at parse
2857          * time.  If the jointree contains just a single VALUES RTE, we assume
2858          * this case applies (without looking at the targetlist...)
2859          */
2860         if (list_length(query->jointree->fromlist) == 1)
2861         {
2862                 RangeTblRef *rtr = (RangeTblRef *) linitial(query->jointree->fromlist);
2863
2864                 if (IsA(rtr, RangeTblRef))
2865                 {
2866                         RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
2867
2868                         if (rte->rtekind == RTE_VALUES)
2869                         {
2870                                 get_values_def(rte->values_lists, context);
2871                                 return;
2872                         }
2873                 }
2874         }
2875
2876         /*
2877          * Build up the query string - first we say SELECT
2878          */
2879         appendStringInfo(buf, "SELECT");
2880
2881         /* Add the DISTINCT clause if given */
2882         if (query->distinctClause != NIL)
2883         {
2884                 if (query->hasDistinctOn)
2885                 {
2886                         appendStringInfo(buf, " DISTINCT ON (");
2887                         sep = "";
2888                         foreach(l, query->distinctClause)
2889                         {
2890                                 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
2891
2892                                 appendStringInfoString(buf, sep);
2893                                 get_rule_sortgroupclause(srt, query->targetList,
2894                                                                                  false, context);
2895                                 sep = ", ";
2896                         }
2897                         appendStringInfo(buf, ")");
2898                 }
2899                 else
2900                         appendStringInfo(buf, " DISTINCT");
2901         }
2902
2903         /* Then we tell what to select (the targetlist) */
2904         get_target_list(query->targetList, context, resultDesc);
2905
2906         /* Add the FROM clause if needed */
2907         get_from_clause(query, " FROM ", context);
2908
2909         /* Add the WHERE clause if given */
2910         if (query->jointree->quals != NULL)
2911         {
2912                 appendContextKeyword(context, " WHERE ",
2913                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2914                 get_rule_expr(query->jointree->quals, context, false);
2915         }
2916
2917         /* Add the GROUP BY clause if given */
2918         if (query->groupClause != NULL)
2919         {
2920                 appendContextKeyword(context, " GROUP BY ",
2921                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2922                 sep = "";
2923                 foreach(l, query->groupClause)
2924                 {
2925                         SortGroupClause *grp = (SortGroupClause *) lfirst(l);
2926
2927                         appendStringInfoString(buf, sep);
2928                         get_rule_sortgroupclause(grp, query->targetList,
2929                                                                          false, context);
2930                         sep = ", ";
2931                 }
2932         }
2933
2934         /* Add the HAVING clause if given */
2935         if (query->havingQual != NULL)
2936         {
2937                 appendContextKeyword(context, " HAVING ",
2938                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2939                 get_rule_expr(query->havingQual, context, false);
2940         }
2941
2942         /* Add the WINDOW clause if needed */
2943         if (query->windowClause != NIL)
2944                 get_rule_windowclause(query, context);
2945 }
2946
2947 /* ----------
2948  * get_target_list                      - Parse back a SELECT target list
2949  *
2950  * This is also used for RETURNING lists in INSERT/UPDATE/DELETE.
2951  * ----------
2952  */
2953 static void
2954 get_target_list(List *targetList, deparse_context *context,
2955                                 TupleDesc resultDesc)
2956 {
2957         StringInfo      buf = context->buf;
2958         char       *sep;
2959         int                     colno;
2960         ListCell   *l;
2961
2962         sep = " ";
2963         colno = 0;
2964         foreach(l, targetList)
2965         {
2966                 TargetEntry *tle = (TargetEntry *) lfirst(l);
2967                 char       *colname;
2968                 char       *attname;
2969
2970                 if (tle->resjunk)
2971                         continue;                       /* ignore junk entries */
2972
2973                 appendStringInfoString(buf, sep);
2974                 sep = ", ";
2975                 colno++;
2976
2977                 /*
2978                  * We special-case Var nodes rather than using get_rule_expr. This is
2979                  * needed because get_rule_expr will display a whole-row Var as
2980                  * "foo.*", which is the preferred notation in most contexts, but at
2981                  * the top level of a SELECT list it's not right (the parser will
2982                  * expand that notation into multiple columns, yielding behavior
2983                  * different from a whole-row Var).  We want just "foo", instead.
2984                  */
2985                 if (tle->expr && IsA(tle->expr, Var))
2986                 {
2987                         attname = get_variable((Var *) tle->expr, 0, false, context);
2988                 }
2989                 else
2990                 {
2991                         get_rule_expr((Node *) tle->expr, context, true);
2992                         /* We'll show the AS name unless it's this: */
2993                         attname = "?column?";
2994                 }
2995
2996                 /*
2997                  * Figure out what the result column should be called.  In the context
2998                  * of a view, use the view's tuple descriptor (so as to pick up the
2999                  * effects of any column RENAME that's been done on the view).
3000                  * Otherwise, just use what we can find in the TLE.
3001                  */
3002                 if (resultDesc && colno <= resultDesc->natts)
3003                         colname = NameStr(resultDesc->attrs[colno - 1]->attname);
3004                 else
3005                         colname = tle->resname;
3006
3007                 /* Show AS unless the column's name is correct as-is */
3008                 if (colname)                    /* resname could be NULL */
3009                 {
3010                         if (attname == NULL || strcmp(attname, colname) != 0)
3011                                 appendStringInfo(buf, " AS %s", quote_identifier(colname));
3012                 }
3013         }
3014 }
3015
3016 static void
3017 get_setop_query(Node *setOp, Query *query, deparse_context *context,
3018                                 TupleDesc resultDesc)
3019 {
3020         StringInfo      buf = context->buf;
3021         bool            need_paren;
3022
3023         if (IsA(setOp, RangeTblRef))
3024         {
3025                 RangeTblRef *rtr = (RangeTblRef *) setOp;
3026                 RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
3027                 Query      *subquery = rte->subquery;
3028
3029                 Assert(subquery != NULL);
3030                 Assert(subquery->setOperations == NULL);
3031                 /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
3032                 need_paren = (subquery->cteList ||
3033                                           subquery->sortClause ||
3034                                           subquery->rowMarks ||
3035                                           subquery->limitOffset ||
3036                                           subquery->limitCount);
3037                 if (need_paren)
3038                         appendStringInfoChar(buf, '(');
3039                 get_query_def(subquery, buf, context->namespaces, resultDesc,
3040                                           context->prettyFlags, context->indentLevel);
3041                 if (need_paren)
3042                         appendStringInfoChar(buf, ')');
3043         }
3044         else if (IsA(setOp, SetOperationStmt))
3045         {
3046                 SetOperationStmt *op = (SetOperationStmt *) setOp;
3047
3048                 if (PRETTY_INDENT(context))
3049                 {
3050                         context->indentLevel += PRETTYINDENT_STD;
3051                         appendStringInfoSpaces(buf, PRETTYINDENT_STD);
3052                 }
3053
3054                 /*
3055                  * We force parens whenever nesting two SetOperationStmts. There are
3056                  * some cases in which parens are needed around a leaf query too, but
3057                  * those are more easily handled at the next level down (see code
3058                  * above).
3059                  */
3060                 need_paren = !IsA(op->larg, RangeTblRef);
3061
3062                 if (need_paren)
3063                         appendStringInfoChar(buf, '(');
3064                 get_setop_query(op->larg, query, context, resultDesc);
3065                 if (need_paren)
3066                         appendStringInfoChar(buf, ')');
3067
3068                 if (!PRETTY_INDENT(context))
3069                         appendStringInfoChar(buf, ' ');
3070                 switch (op->op)
3071                 {
3072                         case SETOP_UNION:
3073                                 appendContextKeyword(context, "UNION ",
3074                                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
3075                                 break;
3076                         case SETOP_INTERSECT:
3077                                 appendContextKeyword(context, "INTERSECT ",
3078                                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
3079                                 break;
3080                         case SETOP_EXCEPT:
3081                                 appendContextKeyword(context, "EXCEPT ",
3082                                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
3083                                 break;
3084                         default:
3085                                 elog(ERROR, "unrecognized set op: %d",
3086                                          (int) op->op);
3087                 }
3088                 if (op->all)
3089                         appendStringInfo(buf, "ALL ");
3090
3091                 if (PRETTY_INDENT(context))
3092                         appendContextKeyword(context, "", 0, 0, 0);
3093
3094                 need_paren = !IsA(op->rarg, RangeTblRef);
3095
3096                 if (need_paren)
3097                         appendStringInfoChar(buf, '(');
3098                 get_setop_query(op->rarg, query, context, resultDesc);
3099                 if (need_paren)
3100                         appendStringInfoChar(buf, ')');
3101
3102                 if (PRETTY_INDENT(context))
3103                         context->indentLevel -= PRETTYINDENT_STD;
3104         }
3105         else
3106         {
3107                 elog(ERROR, "unrecognized node type: %d",
3108                          (int) nodeTag(setOp));
3109         }
3110 }
3111
3112 /*
3113  * Display a sort/group clause.
3114  *
3115  * Also returns the expression tree, so caller need not find it again.
3116  */
3117 static Node *
3118 get_rule_sortgroupclause(SortGroupClause *srt, List *tlist, bool force_colno,
3119                                                  deparse_context *context)
3120 {
3121         StringInfo      buf = context->buf;
3122         TargetEntry *tle;
3123         Node       *expr;
3124
3125         tle = get_sortgroupclause_tle(srt, tlist);
3126         expr = (Node *) tle->expr;
3127
3128         /*
3129          * Use column-number form if requested by caller.  Otherwise, if
3130          * expression is a constant, force it to be dumped with an explicit cast
3131          * as decoration --- this is because a simple integer constant is
3132          * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we
3133          * dump it without any decoration.      Otherwise, just dump the expression
3134          * normally.
3135          */
3136         if (force_colno)
3137         {
3138                 Assert(!tle->resjunk);
3139                 appendStringInfo(buf, "%d", tle->resno);
3140         }
3141         else if (expr && IsA(expr, Const))
3142                 get_const_expr((Const *) expr, context, 1);
3143         else
3144                 get_rule_expr(expr, context, true);
3145
3146         return expr;
3147 }
3148
3149 /*
3150  * Display an ORDER BY list.
3151  */
3152 static void
3153 get_rule_orderby(List *orderList, List *targetList,
3154                                  bool force_colno, deparse_context *context)
3155 {
3156         StringInfo      buf = context->buf;
3157         const char *sep;
3158         ListCell   *l;
3159
3160         sep = "";
3161         foreach(l, orderList)
3162         {
3163                 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
3164                 Node       *sortexpr;
3165                 Oid                     sortcoltype;
3166                 TypeCacheEntry *typentry;
3167
3168                 appendStringInfoString(buf, sep);
3169                 sortexpr = get_rule_sortgroupclause(srt, targetList,
3170                                                                                         force_colno, context);
3171                 sortcoltype = exprType(sortexpr);
3172                 /* See whether operator is default < or > for datatype */
3173                 typentry = lookup_type_cache(sortcoltype,
3174                                                                          TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
3175                 if (srt->sortop == typentry->lt_opr)
3176                 {
3177                         /* ASC is default, so emit nothing for it */
3178                         if (srt->nulls_first)
3179                                 appendStringInfo(buf, " NULLS FIRST");
3180                 }
3181                 else if (srt->sortop == typentry->gt_opr)
3182                 {
3183                         appendStringInfo(buf, " DESC");
3184                         /* DESC defaults to NULLS FIRST */
3185                         if (!srt->nulls_first)
3186                                 appendStringInfo(buf, " NULLS LAST");
3187                 }
3188                 else
3189                 {
3190                         appendStringInfo(buf, " USING %s",
3191                                                          generate_operator_name(srt->sortop,
3192                                                                                                         sortcoltype,
3193                                                                                                         sortcoltype));
3194                         /* be specific to eliminate ambiguity */
3195                         if (srt->nulls_first)
3196                                 appendStringInfo(buf, " NULLS FIRST");
3197                         else
3198                                 appendStringInfo(buf, " NULLS LAST");
3199                 }
3200                 sep = ", ";
3201         }
3202 }
3203
3204 /*
3205  * Display a WINDOW clause.
3206  *
3207  * Note that the windowClause list might contain only anonymous window
3208  * specifications, in which case we should print nothing here.
3209  */
3210 static void
3211 get_rule_windowclause(Query *query, deparse_context *context)
3212 {
3213         StringInfo      buf = context->buf;
3214         const char *sep;
3215         ListCell   *l;
3216
3217         sep = NULL;
3218         foreach(l, query->windowClause)
3219         {
3220                 WindowClause *wc = (WindowClause *) lfirst(l);
3221
3222                 if (wc->name == NULL)
3223                         continue;                       /* ignore anonymous windows */
3224
3225                 if (sep == NULL)
3226                         appendContextKeyword(context, " WINDOW ",
3227                                                                  -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3228                 else
3229                         appendStringInfoString(buf, sep);
3230
3231                 appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
3232
3233                 get_rule_windowspec(wc, query->targetList, context);
3234
3235                 sep = ", ";
3236         }
3237 }
3238
3239 /*
3240  * Display a window definition
3241  */
3242 static void
3243 get_rule_windowspec(WindowClause *wc, List *targetList,
3244                                         deparse_context *context)
3245 {
3246         StringInfo      buf = context->buf;
3247         bool            needspace = false;
3248         const char *sep;
3249         ListCell   *l;
3250
3251         appendStringInfoChar(buf, '(');
3252         if (wc->refname)
3253         {
3254                 appendStringInfoString(buf, quote_identifier(wc->refname));
3255                 needspace = true;
3256         }
3257         /* partition clauses are always inherited, so only print if no refname */
3258         if (wc->partitionClause && !wc->refname)
3259         {
3260                 if (needspace)
3261                         appendStringInfoChar(buf, ' ');
3262                 appendStringInfoString(buf, "PARTITION BY ");
3263                 sep = "";
3264                 foreach(l, wc->partitionClause)
3265                 {
3266                         SortGroupClause *grp = (SortGroupClause *) lfirst(l);
3267
3268                         appendStringInfoString(buf, sep);
3269                         get_rule_sortgroupclause(grp, targetList,
3270                                                                          false, context);
3271                         sep = ", ";
3272                 }
3273                 needspace = true;
3274         }
3275         /* print ordering clause only if not inherited */
3276         if (wc->orderClause && !wc->copiedOrder)
3277         {
3278                 if (needspace)
3279                         appendStringInfoChar(buf, ' ');
3280                 appendStringInfoString(buf, "ORDER BY ");
3281                 get_rule_orderby(wc->orderClause, targetList, false, context);
3282                 needspace = true;
3283         }
3284         /* framing clause is never inherited, so print unless it's default */
3285         if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
3286         {
3287                 if (needspace)
3288                         appendStringInfoChar(buf, ' ');
3289                 if (wc->frameOptions & FRAMEOPTION_RANGE)
3290                         appendStringInfoString(buf, "RANGE ");
3291                 else if (wc->frameOptions & FRAMEOPTION_ROWS)
3292                         appendStringInfoString(buf, "ROWS ");
3293                 else
3294                         Assert(false);
3295                 if (wc->frameOptions & FRAMEOPTION_BETWEEN)
3296                         appendStringInfoString(buf, "BETWEEN ");
3297                 if (wc->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
3298                         appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
3299                 else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW)
3300                         appendStringInfoString(buf, "CURRENT ROW ");
3301                 else if (wc->frameOptions & FRAMEOPTION_START_VALUE)
3302                 {
3303                         get_rule_expr(wc->startOffset, context, false);
3304                         if (wc->frameOptions & FRAMEOPTION_START_VALUE_PRECEDING)
3305                                 appendStringInfoString(buf, " PRECEDING ");
3306                         else if (wc->frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING)
3307                                 appendStringInfoString(buf, " FOLLOWING ");
3308                         else
3309                                 Assert(false);
3310                 }
3311                 else
3312                         Assert(false);
3313                 if (wc->frameOptions & FRAMEOPTION_BETWEEN)
3314                 {
3315                         appendStringInfoString(buf, "AND ");
3316                         if (wc->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
3317                                 appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
3318                         else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
3319                                 appendStringInfoString(buf, "CURRENT ROW ");
3320                         else if (wc->frameOptions & FRAMEOPTION_END_VALUE)
3321                         {
3322                                 get_rule_expr(wc->endOffset, context, false);
3323                                 if (wc->frameOptions & FRAMEOPTION_END_VALUE_PRECEDING)
3324                                         appendStringInfoString(buf, " PRECEDING ");
3325                                 else if (wc->frameOptions & FRAMEOPTION_END_VALUE_FOLLOWING)
3326                                         appendStringInfoString(buf, " FOLLOWING ");
3327                                 else
3328                                         Assert(false);
3329                         }
3330                         else
3331                                 Assert(false);
3332                 }
3333                 /* we will now have a trailing space; remove it */
3334                 buf->len--;
3335         }
3336         appendStringInfoChar(buf, ')');
3337 }
3338
3339 /* ----------
3340  * get_insert_query_def                 - Parse back an INSERT parsetree
3341  * ----------
3342  */
3343 static void
3344 get_insert_query_def(Query *query, deparse_context *context)
3345 {
3346         StringInfo      buf = context->buf;
3347         RangeTblEntry *select_rte = NULL;
3348         RangeTblEntry *values_rte = NULL;
3349         RangeTblEntry *rte;
3350         char       *sep;
3351         ListCell   *values_cell;
3352         ListCell   *l;
3353         List       *strippedexprs;
3354
3355         /*
3356          * If it's an INSERT ... SELECT or VALUES (...), (...), ... there will be
3357          * a single RTE for the SELECT or VALUES.
3358          */
3359         foreach(l, query->rtable)
3360         {
3361                 rte = (RangeTblEntry *) lfirst(l);
3362
3363                 if (rte->rtekind == RTE_SUBQUERY)
3364                 {
3365                         if (select_rte)
3366                                 elog(ERROR, "too many subquery RTEs in INSERT");
3367                         select_rte = rte;
3368                 }
3369
3370                 if (rte->rtekind == RTE_VALUES)
3371                 {
3372                         if (values_rte)
3373                                 elog(ERROR, "too many values RTEs in INSERT");
3374                         values_rte = rte;
3375                 }
3376         }
3377         if (select_rte && values_rte)
3378                 elog(ERROR, "both subquery and values RTEs in INSERT");
3379
3380         /*
3381          * Start the query with INSERT INTO relname
3382          */
3383         rte = rt_fetch(query->resultRelation, query->rtable);
3384         Assert(rte->rtekind == RTE_RELATION);
3385
3386         if (PRETTY_INDENT(context))
3387         {
3388                 context->indentLevel += PRETTYINDENT_STD;
3389                 appendStringInfoChar(buf, ' ');
3390         }
3391         appendStringInfo(buf, "INSERT INTO %s (",
3392                                          generate_relation_name(rte->relid, NIL));
3393
3394         /*
3395          * Add the insert-column-names list.  To handle indirection properly, we
3396          * need to look for indirection nodes in the top targetlist (if it's
3397          * INSERT ... SELECT or INSERT ... single VALUES), or in the first
3398          * expression list of the VALUES RTE (if it's INSERT ... multi VALUES). We
3399          * assume that all the expression lists will have similar indirection in
3400          * the latter case.
3401          */
3402         if (values_rte)
3403                 values_cell = list_head((List *) linitial(values_rte->values_lists));
3404         else
3405                 values_cell = NULL;
3406         strippedexprs = NIL;
3407         sep = "";
3408         foreach(l, query->targetList)
3409         {
3410                 TargetEntry *tle = (TargetEntry *) lfirst(l);
3411
3412                 if (tle->resjunk)
3413                         continue;                       /* ignore junk entries */
3414
3415                 appendStringInfoString(buf, sep);
3416                 sep = ", ";
3417
3418                 /*
3419                  * Put out name of target column; look in the catalogs, not at
3420                  * tle->resname, since resname will fail to track RENAME.
3421                  */
3422                 appendStringInfoString(buf,
3423                                                 quote_identifier(get_relid_attribute_name(rte->relid,
3424                                                                                                                            tle->resno)));
3425
3426                 /*
3427                  * Print any indirection needed (subfields or subscripts), and strip
3428                  * off the top-level nodes representing the indirection assignments.
3429                  */
3430                 if (values_cell)
3431                 {
3432                         /* we discard the stripped expression in this case */
3433                         processIndirection((Node *) lfirst(values_cell), context, true);
3434                         values_cell = lnext(values_cell);
3435                 }
3436                 else
3437                 {
3438                         /* we keep a list of the stripped expressions in this case */
3439                         strippedexprs = lappend(strippedexprs,
3440                                                                         processIndirection((Node *) tle->expr,
3441                                                                                                            context, true));
3442                 }
3443         }
3444         appendStringInfo(buf, ") ");
3445
3446         if (select_rte)
3447         {
3448                 /* Add the SELECT */
3449                 get_query_def(select_rte->subquery, buf, NIL, NULL,
3450                                           context->prettyFlags, context->indentLevel);
3451         }
3452         else if (values_rte)
3453         {
3454                 /* A WITH clause is possible here */
3455                 get_with_clause(query, context);
3456                 /* Add the multi-VALUES expression lists */
3457                 get_values_def(values_rte->values_lists, context);
3458         }
3459         else
3460         {
3461                 /* A WITH clause is possible here */
3462                 get_with_clause(query, context);
3463                 /* Add the single-VALUES expression list */
3464                 appendContextKeyword(context, "VALUES (",
3465                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
3466                 get_rule_expr((Node *) strippedexprs, context, false);
3467                 appendStringInfoChar(buf, ')');
3468         }
3469
3470         /* Add RETURNING if present */
3471         if (query->returningList)
3472         {
3473                 appendContextKeyword(context, " RETURNING",
3474                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3475                 get_target_list(query->returningList, context, NULL);
3476         }
3477 }
3478
3479
3480 /* ----------
3481  * get_update_query_def                 - Parse back an UPDATE parsetree
3482  * ----------
3483  */
3484 static void
3485 get_update_query_def(Query *query, deparse_context *context)
3486 {
3487         StringInfo      buf = context->buf;
3488         char       *sep;
3489         RangeTblEntry *rte;
3490         ListCell   *l;
3491
3492         /*
3493          * Start the query with UPDATE relname SET
3494          */
3495         rte = rt_fetch(query->resultRelation, query->rtable);
3496         Assert(rte->rtekind == RTE_RELATION);
3497         if (PRETTY_INDENT(context))
3498         {
3499                 appendStringInfoChar(buf, ' ');
3500                 context->indentLevel += PRETTYINDENT_STD;
3501         }
3502         appendStringInfo(buf, "UPDATE %s%s",
3503                                          only_marker(rte),
3504                                          generate_relation_name(rte->relid, NIL));
3505         if (rte->alias != NULL)
3506                 appendStringInfo(buf, " %s",
3507                                                  quote_identifier(rte->alias->aliasname));
3508         appendStringInfoString(buf, " SET ");
3509
3510         /* Add the comma separated list of 'attname = value' */
3511         sep = "";
3512         foreach(l, query->targetList)
3513         {
3514                 TargetEntry *tle = (TargetEntry *) lfirst(l);
3515                 Node       *expr;
3516
3517                 if (tle->resjunk)
3518                         continue;                       /* ignore junk entries */
3519
3520                 appendStringInfoString(buf, sep);
3521                 sep = ", ";
3522
3523                 /*
3524                  * Put out name of target column; look in the catalogs, not at
3525                  * tle->resname, since resname will fail to track RENAME.
3526                  */
3527                 appendStringInfoString(buf,
3528                                                 quote_identifier(get_relid_attribute_name(rte->relid,
3529                                                                                                                            tle->resno)));
3530
3531                 /*
3532                  * Print any indirection needed (subfields or subscripts), and strip
3533                  * off the top-level nodes representing the indirection assignments.
3534                  */
3535                 expr = processIndirection((Node *) tle->expr, context, true);
3536
3537                 appendStringInfo(buf, " = ");
3538
3539                 get_rule_expr(expr, context, false);
3540         }
3541
3542         /* Add the FROM clause if needed */
3543         get_from_clause(query, " FROM ", context);
3544
3545         /* Add a WHERE clause if given */
3546         if (query->jointree->quals != NULL)
3547         {
3548                 appendContextKeyword(context, " WHERE ",
3549                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3550                 get_rule_expr(query->jointree->quals, context, false);
3551         }
3552
3553         /* Add RETURNING if present */
3554         if (query->returningList)
3555         {
3556                 appendContextKeyword(context, " RETURNING",
3557                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3558                 get_target_list(query->returningList, context, NULL);
3559         }
3560 }
3561
3562
3563 /* ----------
3564  * get_delete_query_def                 - Parse back a DELETE parsetree
3565  * ----------
3566  */
3567 static void
3568 get_delete_query_def(Query *query, deparse_context *context)
3569 {
3570         StringInfo      buf = context->buf;
3571         RangeTblEntry *rte;
3572
3573         /*
3574          * Start the query with DELETE FROM relname
3575          */
3576         rte = rt_fetch(query->resultRelation, query->rtable);
3577         Assert(rte->rtekind == RTE_RELATION);
3578         if (PRETTY_INDENT(context))
3579         {
3580                 appendStringInfoChar(buf, ' ');
3581                 context->indentLevel += PRETTYINDENT_STD;
3582         }
3583         appendStringInfo(buf, "DELETE FROM %s%s",
3584                                          only_marker(rte),
3585                                          generate_relation_name(rte->relid, NIL));
3586         if (rte->alias != NULL)
3587                 appendStringInfo(buf, " %s",
3588                                                  quote_identifier(rte->alias->aliasname));
3589
3590         /* Add the USING clause if given */
3591         get_from_clause(query, " USING ", context);
3592
3593         /* Add a WHERE clause if given */
3594         if (query->jointree->quals != NULL)
3595         {
3596                 appendContextKeyword(context, " WHERE ",
3597                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3598                 get_rule_expr(query->jointree->quals, context, false);
3599         }
3600
3601         /* Add RETURNING if present */
3602         if (query->returningList)
3603         {
3604                 appendContextKeyword(context, " RETURNING",
3605                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3606                 get_target_list(query->returningList, context, NULL);
3607         }
3608 }
3609
3610
3611 /* ----------
3612  * get_utility_query_def                        - Parse back a UTILITY parsetree
3613  * ----------
3614  */
3615 static void
3616 get_utility_query_def(Query *query, deparse_context *context)
3617 {
3618         StringInfo      buf = context->buf;
3619
3620         if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
3621         {
3622                 NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
3623
3624                 appendContextKeyword(context, "",
3625                                                          0, PRETTYINDENT_STD, 1);
3626                 appendStringInfo(buf, "NOTIFY %s",
3627                                                  quote_identifier(stmt->conditionname));
3628                 if (stmt->payload)
3629                 {
3630                         appendStringInfoString(buf, ", ");
3631                         simple_quote_literal(buf, stmt->payload);
3632                 }
3633         }
3634         else
3635         {
3636                 /* Currently only NOTIFY utility commands can appear in rules */
3637                 elog(ERROR, "unexpected utility statement type");
3638         }
3639 }
3640
3641
3642 /*
3643  * Display a Var appropriately.
3644  *
3645  * In some cases (currently only when recursing into an unnamed join)
3646  * the Var's varlevelsup has to be interpreted with respect to a context
3647  * above the current one; levelsup indicates the offset.
3648  *
3649  * If showstar is TRUE, whole-row Vars are displayed as "foo.*";
3650  * if FALSE, merely as "foo".
3651  *
3652  * Returns the attname of the Var, or NULL if not determinable.
3653  */
3654 static char *
3655 get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
3656 {
3657         StringInfo      buf = context->buf;
3658         RangeTblEntry *rte;
3659         AttrNumber      attnum;
3660         int                     netlevelsup;
3661         deparse_namespace *dpns;
3662         char       *schemaname;
3663         char       *refname;
3664         char       *attname;
3665
3666         /* Find appropriate nesting depth */
3667         netlevelsup = var->varlevelsup + levelsup;
3668         if (netlevelsup >= list_length(context->namespaces))
3669                 elog(ERROR, "bogus varlevelsup: %d offset %d",
3670                          var->varlevelsup, levelsup);
3671         dpns = (deparse_namespace *) list_nth(context->namespaces,
3672                                                                                   netlevelsup);
3673
3674         /*
3675          * Try to find the relevant RTE in this rtable.  In a plan tree, it's
3676          * likely that varno is OUTER or INNER, in which case we must dig down
3677          * into the subplans.
3678          */
3679         if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
3680         {
3681                 rte = rt_fetch(var->varno, dpns->rtable);
3682                 attnum = var->varattno;
3683         }
3684         else if (var->varno == OUTER && dpns->outer_plan)
3685         {
3686                 TargetEntry *tle;
3687                 deparse_namespace save_dpns;
3688
3689                 tle = get_tle_by_resno(dpns->outer_plan->targetlist, var->varattno);
3690                 if (!tle)
3691                         elog(ERROR, "bogus varattno for OUTER var: %d", var->varattno);
3692
3693                 Assert(netlevelsup == 0);
3694                 push_child_plan(dpns, dpns->outer_planstate, &save_dpns);
3695
3696                 /*
3697                  * Force parentheses because our caller probably assumed a Var is a
3698                  * simple expression.
3699                  */
3700                 if (!IsA(tle->expr, Var))
3701                         appendStringInfoChar(buf, '(');
3702                 get_rule_expr((Node *) tle->expr, context, true);
3703                 if (!IsA(tle->expr, Var))
3704                         appendStringInfoChar(buf, ')');
3705
3706                 pop_child_plan(dpns, &save_dpns);
3707                 return NULL;
3708         }
3709         else if (var->varno == INNER && dpns->inner_plan)
3710         {
3711                 TargetEntry *tle;
3712                 deparse_namespace save_dpns;
3713
3714                 tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno);
3715                 if (!tle)
3716                         elog(ERROR, "bogus varattno for INNER var: %d", var->varattno);
3717
3718                 Assert(netlevelsup == 0);
3719                 push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
3720
3721                 /*
3722                  * Force parentheses because our caller probably assumed a Var is a
3723                  * simple expression.
3724                  */
3725                 if (!IsA(tle->expr, Var))
3726                         appendStringInfoChar(buf, '(');
3727                 get_rule_expr((Node *) tle->expr, context, true);
3728                 if (!IsA(tle->expr, Var))
3729                         appendStringInfoChar(buf, ')');
3730
3731                 pop_child_plan(dpns, &save_dpns);
3732                 return NULL;
3733         }
3734         else
3735         {
3736                 elog(ERROR, "bogus varno: %d", var->varno);
3737                 return NULL;                    /* keep compiler quiet */
3738         }
3739
3740         /*
3741          * The planner will sometimes emit Vars referencing resjunk elements of a
3742          * subquery's target list (this is currently only possible if it chooses
3743          * to generate a "physical tlist" for a SubqueryScan or CteScan node).
3744          * Although we prefer to print subquery-referencing Vars using the
3745          * subquery's alias, that's not possible for resjunk items since they have
3746          * no alias.  So in that case, drill down to the subplan and print the
3747          * contents of the referenced tlist item.  This works because in a plan
3748          * tree, such Vars can only occur in a SubqueryScan or CteScan node,
3749          * and we'll have set dpns->inner_plan to reference the child plan node.
3750          */
3751         if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
3752                 attnum > list_length(rte->eref->colnames) &&
3753                 dpns->inner_plan)
3754         {
3755                 TargetEntry *tle;
3756                 deparse_namespace save_dpns;
3757
3758                 tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno);
3759                 if (!tle)
3760                         elog(ERROR, "bogus varattno for subquery var: %d", var->varattno);
3761
3762                 Assert(netlevelsup == 0);
3763                 push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
3764
3765                 /*
3766                  * Force parentheses because our caller probably assumed a Var is a
3767                  * simple expression.
3768                  */
3769                 if (!IsA(tle->expr, Var))
3770                         appendStringInfoChar(buf, '(');
3771                 get_rule_expr((Node *) tle->expr, context, true);
3772                 if (!IsA(tle->expr, Var))
3773                         appendStringInfoChar(buf, ')');
3774
3775                 pop_child_plan(dpns, &save_dpns);
3776                 return NULL;
3777         }
3778
3779         /* Identify names to use */
3780         schemaname = NULL;                      /* default assumptions */
3781         refname = rte->eref->aliasname;
3782
3783         /* Exceptions occur only if the RTE is alias-less */
3784         if (rte->alias == NULL)
3785         {
3786                 if (rte->rtekind == RTE_RELATION)
3787                 {
3788                         /*
3789                          * It's possible that use of the bare refname would find another
3790                          * more-closely-nested RTE, or be ambiguous, in which case we need
3791                          * to specify the schemaname to avoid these errors.
3792                          */
3793                         if (find_rte_by_refname(rte->eref->aliasname, context) != rte)
3794                                 schemaname = get_namespace_name(get_rel_namespace(rte->relid));
3795                 }
3796                 else if (rte->rtekind == RTE_JOIN)
3797                 {
3798                         /*
3799                          * If it's an unnamed join, look at the expansion of the alias
3800                          * variable.  If it's a simple reference to one of the input vars
3801                          * then recursively print the name of that var, instead. (This
3802                          * allows correct decompiling of cases where there are identically
3803                          * named columns on both sides of the join.) When it's not a
3804                          * simple reference, we have to just print the unqualified
3805                          * variable name (this can only happen with columns that were
3806                          * merged by USING or NATURAL clauses).
3807                          *
3808                          * This wouldn't work in decompiling plan trees, because we don't
3809                          * store joinaliasvars lists after planning; but a plan tree
3810                          * should never contain a join alias variable.
3811                          */
3812                         if (rte->joinaliasvars == NIL)
3813                                 elog(ERROR, "cannot decompile join alias var in plan tree");
3814                         if (attnum > 0)
3815                         {
3816                                 Var                *aliasvar;
3817
3818                                 aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
3819                                 if (IsA(aliasvar, Var))
3820                                 {
3821                                         return get_variable(aliasvar, var->varlevelsup + levelsup,
3822                                                                                 showstar, context);
3823                                 }
3824                         }
3825                         /* Unnamed join has neither schemaname nor refname */
3826                         refname = NULL;
3827                 }
3828         }
3829
3830         if (attnum == InvalidAttrNumber)
3831                 attname = NULL;
3832         else
3833                 attname = get_rte_attribute_name(rte, attnum);
3834
3835         if (refname && (context->varprefix || attname == NULL))
3836         {
3837                 if (schemaname)
3838                         appendStringInfo(buf, "%s.",
3839                                                          quote_identifier(schemaname));
3840                 appendStringInfoString(buf, quote_identifier(refname));
3841                 if (attname || showstar)
3842                         appendStringInfoChar(buf, '.');
3843         }
3844         if (attname)
3845                 appendStringInfoString(buf, quote_identifier(attname));
3846         else if (showstar)
3847                 appendStringInfoChar(buf, '*');
3848
3849         return attname;
3850 }
3851
3852
3853 /*
3854  * Get the name of a field of an expression of composite type.
3855  *
3856  * This is fairly straightforward except for the case of a Var of type RECORD.
3857  * Since no actual table or view column is allowed to have type RECORD, such
3858  * a Var must refer to a JOIN or FUNCTION RTE or to a subquery output.  We
3859  * drill down to find the ultimate defining expression and attempt to infer
3860  * the field name from it.      We ereport if we can't determine the name.
3861  *
3862  * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
3863  */
3864 static const char *
3865 get_name_for_var_field(Var *var, int fieldno,
3866                                            int levelsup, deparse_context *context)
3867 {
3868         RangeTblEntry *rte;
3869         AttrNumber      attnum;
3870         int                     netlevelsup;
3871         deparse_namespace *dpns;
3872         TupleDesc       tupleDesc;
3873         Node       *expr;
3874
3875         /*
3876          * If it's a RowExpr that was expanded from a whole-row Var, use the
3877          * column names attached to it.
3878          */
3879         if (IsA(var, RowExpr))
3880         {
3881                 RowExpr    *r = (RowExpr *) var;
3882
3883                 if (fieldno > 0 && fieldno <= list_length(r->colnames))
3884                         return strVal(list_nth(r->colnames, fieldno - 1));
3885         }
3886
3887         /*
3888          * If it's a Var of type RECORD, we have to find what the Var refers to;
3889          * if not, we can use get_expr_result_type. If that fails, we try
3890          * lookup_rowtype_tupdesc, which will probably fail too, but will ereport
3891          * an acceptable message.
3892          */
3893         if (!IsA(var, Var) ||
3894                 var->vartype != RECORDOID)
3895         {
3896                 if (get_expr_result_type((Node *) var, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
3897                         tupleDesc = lookup_rowtype_tupdesc_copy(exprType((Node *) var),
3898                                                                                                         exprTypmod((Node *) var));
3899                 Assert(tupleDesc);
3900                 /* Got the tupdesc, so we can extract the field name */
3901                 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
3902                 return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
3903         }
3904
3905         /* Find appropriate nesting depth */
3906         netlevelsup = var->varlevelsup + levelsup;
3907         if (netlevelsup >= list_length(context->namespaces))
3908                 elog(ERROR, "bogus varlevelsup: %d offset %d",
3909                          var->varlevelsup, levelsup);
3910         dpns = (deparse_namespace *) list_nth(context->namespaces,
3911                                                                                   netlevelsup);
3912
3913         /*
3914          * Try to find the relevant RTE in this rtable.  In a plan tree, it's
3915          * likely that varno is OUTER or INNER, in which case we must dig down
3916          * into the subplans.
3917          */
3918         if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
3919         {
3920                 rte = rt_fetch(var->varno, dpns->rtable);
3921                 attnum = var->varattno;
3922         }
3923         else if (var->varno == OUTER && dpns->outer_plan)
3924         {
3925                 TargetEntry *tle;
3926                 deparse_namespace save_dpns;
3927                 const char *result;
3928
3929                 tle = get_tle_by_resno(dpns->outer_plan->targetlist, var->varattno);
3930                 if (!tle)
3931                         elog(ERROR, "bogus varattno for OUTER var: %d", var->varattno);
3932
3933                 Assert(netlevelsup == 0);
3934                 push_child_plan(dpns, dpns->outer_planstate, &save_dpns);
3935
3936                 result = get_name_for_var_field((Var *) tle->expr, fieldno,
3937                                                                                 levelsup, context);
3938
3939                 pop_child_plan(dpns, &save_dpns);
3940                 return result;
3941         }
3942         else if (var->varno == INNER && dpns->inner_plan)
3943         {
3944                 TargetEntry *tle;
3945                 deparse_namespace save_dpns;
3946                 const char *result;
3947
3948                 tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno);
3949                 if (!tle)
3950                         elog(ERROR, "bogus varattno for INNER var: %d", var->varattno);
3951
3952                 Assert(netlevelsup == 0);
3953                 push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
3954
3955                 result = get_name_for_var_field((Var *) tle->expr, fieldno,
3956                                                                                 levelsup, context);
3957
3958                 pop_child_plan(dpns, &save_dpns);
3959                 return result;
3960         }
3961         else
3962         {
3963                 elog(ERROR, "bogus varno: %d", var->varno);
3964                 return NULL;                    /* keep compiler quiet */
3965         }
3966
3967         if (attnum == InvalidAttrNumber)
3968         {
3969                 /* Var is whole-row reference to RTE, so select the right field */
3970                 return get_rte_attribute_name(rte, fieldno);
3971         }
3972
3973         /*
3974          * This part has essentially the same logic as the parser's
3975          * expandRecordVariable() function, but we are dealing with a different
3976          * representation of the input context, and we only need one field name
3977          * not a TupleDesc.  Also, we need special cases for finding subquery and
3978          * CTE subplans when deparsing Plan trees.
3979          */
3980         expr = (Node *) var;            /* default if we can't drill down */
3981
3982         switch (rte->rtekind)
3983         {
3984                 case RTE_RELATION:
3985                 case RTE_SPECIAL:
3986                 case RTE_VALUES:
3987
3988                         /*
3989                          * This case should not occur: a column of a table or values list
3990                          * shouldn't have type RECORD.  Fall through and fail (most
3991                          * likely) at the bottom.
3992                          */
3993                         break;
3994                 case RTE_SUBQUERY:
3995                         /* Subselect-in-FROM: examine sub-select's output expr */
3996                         {
3997                                 if (rte->subquery)
3998                                 {
3999                                         TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
4000                                                                                                                 attnum);
4001
4002                                         if (ste == NULL || ste->resjunk)
4003                                                 elog(ERROR, "subquery %s does not have attribute %d",
4004                                                          rte->eref->aliasname, attnum);
4005                                         expr = (Node *) ste->expr;
4006                                         if (IsA(expr, Var))
4007                                         {
4008                                                 /*
4009                                                  * Recurse into the sub-select to see what its Var
4010                                                  * refers to. We have to build an additional level of
4011                                                  * namespace to keep in step with varlevelsup in the
4012                                                  * subselect.
4013                                                  */
4014                                                 deparse_namespace mydpns;
4015                                                 const char *result;
4016
4017                                                 memset(&mydpns, 0, sizeof(mydpns));
4018                                                 mydpns.rtable = rte->subquery->rtable;
4019                                                 mydpns.ctes = rte->subquery->cteList;
4020
4021                                                 context->namespaces = lcons(&mydpns,
4022                                                                                                         context->namespaces);
4023
4024                                                 result = get_name_for_var_field((Var *) expr, fieldno,
4025                                                                                                                 0, context);
4026
4027                                                 context->namespaces =
4028                                                         list_delete_first(context->namespaces);
4029
4030                                                 return result;
4031                                         }
4032                                         /* else fall through to inspect the expression */
4033                                 }
4034                                 else
4035                                 {
4036                                         /*
4037                                          * We're deparsing a Plan tree so we don't have complete
4038                                          * RTE entries (in particular, rte->subquery is NULL). But
4039                                          * the only place we'd see a Var directly referencing a
4040                                          * SUBQUERY RTE is in a SubqueryScan plan node, and we can
4041                                          * look into the child plan's tlist instead.
4042                                          */
4043                                         TargetEntry *tle;
4044                                         deparse_namespace save_dpns;
4045                                         const char *result;
4046
4047                                         if (!dpns->inner_plan)
4048                                                 elog(ERROR, "failed to find plan for subquery %s",
4049                                                          rte->eref->aliasname);
4050                                         tle = get_tle_by_resno(dpns->inner_plan->targetlist,
4051                                                                                    attnum);
4052                                         if (!tle)
4053                                                 elog(ERROR, "bogus varattno for subquery var: %d",
4054                                                          attnum);
4055                                         Assert(netlevelsup == 0);
4056                                         push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
4057
4058                                         result = get_name_for_var_field((Var *) tle->expr, fieldno,
4059                                                                                                         levelsup, context);
4060
4061                                         pop_child_plan(dpns, &save_dpns);
4062                                         return result;
4063                                 }
4064                         }
4065                         break;
4066                 case RTE_JOIN:
4067                         /* Join RTE --- recursively inspect the alias variable */
4068                         if (rte->joinaliasvars == NIL)
4069                                 elog(ERROR, "cannot decompile join alias var in plan tree");
4070                         Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
4071                         expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
4072                         if (IsA(expr, Var))
4073                                 return get_name_for_var_field((Var *) expr, fieldno,
4074                                                                                           var->varlevelsup + levelsup,
4075                                                                                           context);
4076                         /* else fall through to inspect the expression */
4077                         break;
4078                 case RTE_FUNCTION:
4079
4080                         /*
4081                          * We couldn't get here unless a function is declared with one of
4082                          * its result columns as RECORD, which is not allowed.
4083                          */
4084                         break;
4085                 case RTE_CTE:
4086                         /* CTE reference: examine subquery's output expr */
4087                         {
4088                                 CommonTableExpr *cte = NULL;
4089                                 Index           ctelevelsup;
4090                                 ListCell   *lc;
4091
4092                                 /*
4093                                  * Try to find the referenced CTE using the namespace stack.
4094                                  */
4095                                 ctelevelsup = rte->ctelevelsup + netlevelsup;
4096                                 if (ctelevelsup >= list_length(context->namespaces))
4097                                         lc = NULL;
4098                                 else
4099                                 {
4100                                         deparse_namespace *ctedpns;
4101
4102                                         ctedpns = (deparse_namespace *)
4103                                                 list_nth(context->namespaces, ctelevelsup);
4104                                         foreach(lc, ctedpns->ctes)
4105                                         {
4106                                                 cte = (CommonTableExpr *) lfirst(lc);
4107                                                 if (strcmp(cte->ctename, rte->ctename) == 0)
4108                                                         break;
4109                                         }
4110                                 }
4111                                 if (lc != NULL)
4112                                 {
4113                                         Query      *ctequery = (Query *) cte->ctequery;
4114                                         TargetEntry *ste = get_tle_by_resno(ctequery->targetList,
4115                                                                                                                 attnum);
4116
4117                                         if (ste == NULL || ste->resjunk)
4118                                                 elog(ERROR, "subquery %s does not have attribute %d",
4119                                                          rte->eref->aliasname, attnum);
4120                                         expr = (Node *) ste->expr;
4121                                         if (IsA(expr, Var))
4122                                         {
4123                                                 /*
4124                                                  * Recurse into the CTE to see what its Var refers to.
4125                                                  * We have to build an additional level of namespace
4126                                                  * to keep in step with varlevelsup in the CTE.
4127                                                  * Furthermore it could be an outer CTE, so we may
4128                                                  * have to delete some levels of namespace.
4129                                                  */
4130                                                 List       *save_nslist = context->namespaces;
4131                                                 List       *new_nslist;
4132                                                 deparse_namespace mydpns;
4133                                                 const char *result;
4134
4135                                                 memset(&mydpns, 0, sizeof(mydpns));
4136                                                 mydpns.rtable = ctequery->rtable;
4137                                                 mydpns.ctes = ctequery->cteList;
4138
4139                                                 new_nslist = list_copy_tail(context->namespaces,
4140                                                                                                         ctelevelsup);
4141                                                 context->namespaces = lcons(&mydpns, new_nslist);
4142
4143                                                 result = get_name_for_var_field((Var *) expr, fieldno,
4144                                                                                                                 0, context);
4145
4146                                                 context->namespaces = save_nslist;
4147
4148                                                 return result;
4149                                         }
4150                                         /* else fall through to inspect the expression */
4151                                 }
4152                                 else
4153                                 {
4154                                         /*
4155                                          * We're deparsing a Plan tree so we don't have a CTE
4156                                          * list.  But the only place we'd see a Var directly
4157                                          * referencing a CTE RTE is in a CteScan plan node, and we
4158                                          * can look into the subplan's tlist instead.
4159                                          */
4160                                         TargetEntry *tle;
4161                                         deparse_namespace save_dpns;
4162                                         const char *result;
4163
4164                                         if (!dpns->inner_plan)
4165                                                 elog(ERROR, "failed to find plan for CTE %s",
4166                                                          rte->eref->aliasname);
4167                                         tle = get_tle_by_resno(dpns->inner_plan->targetlist,
4168                                                                                    attnum);
4169                                         if (!tle)
4170                                                 elog(ERROR, "bogus varattno for subquery var: %d",
4171                                                          attnum);
4172                                         Assert(netlevelsup == 0);
4173                                         push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
4174
4175                                         result = get_name_for_var_field((Var *) tle->expr, fieldno,
4176                                                                                                         levelsup, context);
4177
4178                                         pop_child_plan(dpns, &save_dpns);
4179                                         return result;
4180                                 }
4181                         }
4182                         break;
4183         }
4184
4185         /*
4186          * We now have an expression we can't expand any more, so see if
4187          * get_expr_result_type() can do anything with it.      If not, pass to
4188          * lookup_rowtype_tupdesc() which will probably fail, but will give an
4189          * appropriate error message while failing.
4190          */
4191         if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
4192                 tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr),
4193                                                                                                 exprTypmod(expr));
4194         Assert(tupleDesc);
4195         /* Got the tupdesc, so we can extract the field name */
4196         Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
4197         return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
4198 }
4199
4200
4201 /*
4202  * find_rte_by_refname          - look up an RTE by refname in a deparse context
4203  *
4204  * Returns NULL if there is no matching RTE or the refname is ambiguous.
4205  *
4206  * NOTE: this code is not really correct since it does not take account of
4207  * the fact that not all the RTEs in a rangetable may be visible from the
4208  * point where a Var reference appears.  For the purposes we need, however,
4209  * the only consequence of a false match is that we might stick a schema
4210  * qualifier on a Var that doesn't really need it.  So it seems close
4211  * enough.
4212  */
4213 static RangeTblEntry *
4214 find_rte_by_refname(const char *refname, deparse_context *context)
4215 {
4216         RangeTblEntry *result = NULL;
4217         ListCell   *nslist;
4218
4219         foreach(nslist, context->namespaces)
4220         {
4221                 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
4222                 ListCell   *rtlist;
4223
4224                 foreach(rtlist, dpns->rtable)
4225                 {
4226                         RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtlist);
4227
4228                         if (strcmp(rte->eref->aliasname, refname) == 0)
4229                         {
4230                                 if (result)
4231                                         return NULL;    /* it's ambiguous */
4232                                 result = rte;
4233                         }
4234                 }
4235                 if (result)
4236                         break;
4237         }
4238         return result;
4239 }
4240
4241 /*
4242  * Display a Param appropriately.
4243  */
4244 static void
4245 get_parameter(Param *param, deparse_context *context)
4246 {
4247         /*
4248          * If it's a PARAM_EXEC parameter, try to locate the expression from
4249          * which the parameter was computed.  This will necessarily be in some
4250          * ancestor of the current expression's PlanState.  Note that failing
4251          * to find a referent isn't an error, since the Param might well be a
4252          * subplan output rather than an input.
4253          */
4254         if (param->paramkind == PARAM_EXEC)
4255         {
4256                 deparse_namespace *dpns;
4257                 PlanState  *child_ps;
4258                 bool            in_same_plan_level;
4259                 ListCell   *lc;
4260
4261                 dpns = (deparse_namespace *) linitial(context->namespaces);
4262                 child_ps = dpns->planstate;
4263                 in_same_plan_level = true;
4264
4265                 foreach(lc, dpns->ancestors)
4266                 {
4267                         PlanState  *ps = (PlanState *) lfirst(lc);
4268                         ListCell   *lc2;
4269
4270                         /*
4271                          * NestLoops transmit params to their inner child only; also,
4272                          * once we've crawled up out of a subplan, this couldn't
4273                          * possibly be the right match.
4274                          */
4275                         if (IsA(ps, NestLoopState) &&
4276                                 child_ps == innerPlanState(ps) &&
4277                                 in_same_plan_level)
4278                         {
4279                                 NestLoop   *nl = (NestLoop *) ps->plan;
4280
4281                                 foreach(lc2, nl->nestParams)
4282                                 {
4283                                         NestLoopParam  *nlp = (NestLoopParam *) lfirst(lc2);
4284
4285                                         if (nlp->paramno == param->paramid)
4286                                         {
4287                                                 /* Found a match, so print it */
4288                                                 print_parameter_expr((Node *) nlp->paramval, lc,
4289                                                                                          dpns, context);
4290                                                 return;
4291                                         }
4292                                 }
4293                         }
4294
4295                         /*
4296                          * Check to see if we're crawling up from a subplan.
4297                          */
4298                         foreach(lc2, ps->subPlan)
4299                         {
4300                                 SubPlanState *sstate = (SubPlanState *) lfirst(lc2);
4301                                 SubPlan    *subplan = (SubPlan *) sstate->xprstate.expr;
4302                                 ListCell   *lc3;
4303                                 ListCell   *lc4;
4304
4305                                 if (child_ps != sstate->planstate)
4306                                         continue;
4307
4308                                 /* Matched subplan, so check its arguments */
4309                                 forboth(lc3, subplan->parParam, lc4, subplan->args)
4310                                 {
4311                                         int             paramid = lfirst_int(lc3);
4312                                         Node   *arg = (Node *) lfirst(lc4);
4313
4314                                         if (paramid == param->paramid)
4315                                         {
4316                                                 /* Found a match, so print it */
4317                                                 print_parameter_expr(arg, lc, dpns, context);
4318                                                 return;
4319                                         }
4320                                 }
4321
4322                                 /* Keep looking, but we are emerging from a subplan. */
4323                                 in_same_plan_level = false;
4324                                 break;
4325                         }
4326
4327                         /*
4328                          * Likewise check to see if we're emerging from an initplan.
4329                          * Initplans never have any parParams, so no need to search that
4330                          * list, but we need to know if we should reset
4331                          * in_same_plan_level.
4332                          */
4333                         foreach(lc2, ps->initPlan)
4334                         {
4335                                 SubPlanState *sstate = (SubPlanState *) lfirst(lc2);
4336
4337                                 if (child_ps != sstate->planstate)
4338                                         continue;
4339
4340                                 /* No parameters to be had here. */
4341                                 Assert(((SubPlan *) sstate->xprstate.expr)->parParam == NIL);
4342
4343                                 /* Keep looking, but we are emerging from an initplan. */
4344                                 in_same_plan_level = false;
4345                                 break;
4346                         }
4347
4348                         /* No luck, crawl up to next ancestor */
4349                         child_ps = ps;
4350                 }
4351         }
4352
4353         /*
4354          * Not PARAM_EXEC, or couldn't find referent: just print $N.
4355          */
4356         appendStringInfo(context->buf, "$%d", param->paramid);
4357 }
4358
4359 /* Print a parameter reference expression found by get_parameter */
4360 static void
4361 print_parameter_expr(Node *expr, ListCell *ancestor_cell,
4362                                          deparse_namespace *dpns, deparse_context *context)
4363 {
4364         deparse_namespace save_dpns;
4365         bool            save_varprefix;
4366
4367         /* Switch attention to the ancestor plan node */
4368         push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
4369
4370         /*
4371          * Force prefixing of Vars, since they won't belong to the relation being
4372          * scanned in the original plan node.
4373          */
4374         save_varprefix = context->varprefix;
4375         context->varprefix = true;
4376
4377         /*
4378          * We don't need to add parentheses because a Param's expansion is
4379          * (currently) always a Var or Aggref.
4380          */
4381         Assert(IsA(expr, Var) || IsA(expr, Aggref));
4382
4383         get_rule_expr(expr, context, false);
4384
4385         context->varprefix = save_varprefix;
4386
4387         pop_ancestor_plan(dpns, &save_dpns);
4388 }
4389
4390 /*
4391  * get_simple_binary_op_name
4392  *
4393  * helper function for isSimpleNode
4394  * will return single char binary operator name, or NULL if it's not
4395  */
4396 static const char *
4397 get_simple_binary_op_name(OpExpr *expr)
4398 {
4399         List       *args = expr->args;
4400
4401         if (list_length(args) == 2)
4402         {
4403                 /* binary operator */
4404                 Node       *arg1 = (Node *) linitial(args);
4405                 Node       *arg2 = (Node *) lsecond(args);
4406                 const char *op;
4407
4408                 op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
4409                 if (strlen(op) == 1)
4410                         return op;
4411         }
4412         return NULL;
4413 }
4414
4415
4416 /*
4417  * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
4418  *
4419  *      true   : simple in the context of parent node's type
4420  *      false  : not simple
4421  */
4422 static bool
4423 isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
4424 {
4425         if (!node)
4426                 return false;
4427
4428         switch (nodeTag(node))
4429         {
4430                 case T_Var:
4431                 case T_Const:
4432                 case T_Param:
4433                 case T_CoerceToDomainValue:
4434                 case T_SetToDefault:
4435                 case T_CurrentOfExpr:
4436                         /* single words: always simple */
4437                         return true;
4438
4439                 case T_ArrayRef:
4440                 case T_ArrayExpr:
4441                 case T_RowExpr:
4442                 case T_CoalesceExpr:
4443                 case T_MinMaxExpr:
4444                 case T_XmlExpr:
4445                 case T_NullIfExpr:
4446                 case T_Aggref:
4447                 case T_WindowFunc:
4448                 case T_FuncExpr:
4449                         /* function-like: name(..) or name[..] */
4450                         return true;
4451
4452                         /* CASE keywords act as parentheses */
4453                 case T_CaseExpr:
4454                         return true;
4455
4456                 case T_FieldSelect:
4457
4458                         /*
4459                          * appears simple since . has top precedence, unless parent is
4460                          * T_FieldSelect itself!
4461                          */
4462                         return (IsA(parentNode, FieldSelect) ? false : true);
4463
4464                 case T_FieldStore:
4465
4466                         /*
4467                          * treat like FieldSelect (probably doesn't matter)
4468                          */
4469                         return (IsA(parentNode, FieldStore) ? false : true);
4470
4471                 case T_CoerceToDomain:
4472                         /* maybe simple, check args */
4473                         return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
4474                                                                 node, prettyFlags);
4475                 case T_RelabelType:
4476                         return isSimpleNode((Node *) ((RelabelType *) node)->arg,
4477                                                                 node, prettyFlags);
4478                 case T_CoerceViaIO:
4479                         return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
4480                                                                 node, prettyFlags);
4481                 case T_ArrayCoerceExpr:
4482                         return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
4483                                                                 node, prettyFlags);
4484                 case T_ConvertRowtypeExpr:
4485                         return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
4486                                                                 node, prettyFlags);
4487
4488                 case T_OpExpr:
4489                         {
4490                                 /* depends on parent node type; needs further checking */
4491                                 if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
4492                                 {
4493                                         const char *op;
4494                                         const char *parentOp;
4495                                         bool            is_lopriop;
4496                                         bool            is_hipriop;
4497                                         bool            is_lopriparent;
4498                                         bool            is_hipriparent;
4499
4500                                         op = get_simple_binary_op_name((OpExpr *) node);
4501                                         if (!op)
4502                                                 return false;
4503
4504                                         /* We know only the basic operators + - and * / % */
4505                                         is_lopriop = (strchr("+-", *op) != NULL);
4506                                         is_hipriop = (strchr("*/%", *op) != NULL);
4507                                         if (!(is_lopriop || is_hipriop))
4508                                                 return false;
4509
4510                                         parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
4511                                         if (!parentOp)
4512                                                 return false;
4513
4514                                         is_lopriparent = (strchr("+-", *parentOp) != NULL);
4515                                         is_hipriparent = (strchr("*/%", *parentOp) != NULL);
4516                                         if (!(is_lopriparent || is_hipriparent))
4517                                                 return false;
4518
4519                                         if (is_hipriop && is_lopriparent)
4520                                                 return true;    /* op binds tighter than parent */
4521
4522                                         if (is_lopriop && is_hipriparent)
4523                                                 return false;
4524
4525                                         /*
4526                                          * Operators are same priority --- can skip parens only if
4527                                          * we have (a - b) - c, not a - (b - c).
4528                                          */
4529                                         if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
4530                                                 return true;
4531
4532                                         return false;
4533                                 }
4534                                 /* else do the same stuff as for T_SubLink et al. */
4535                                 /* FALL THROUGH */
4536                         }
4537
4538                 case T_SubLink:
4539                 case T_NullTest:
4540                 case T_BooleanTest:
4541                 case T_DistinctExpr:
4542                         switch (nodeTag(parentNode))
4543                         {
4544                                 case T_FuncExpr:
4545                                         {
4546                                                 /* special handling for casts */
4547                                                 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
4548
4549                                                 if (type == COERCE_EXPLICIT_CAST ||
4550                                                         type == COERCE_IMPLICIT_CAST)
4551                                                         return false;
4552                                                 return true;    /* own parentheses */
4553                                         }
4554                                 case T_BoolExpr:                /* lower precedence */
4555                                 case T_ArrayRef:                /* other separators */
4556                                 case T_ArrayExpr:               /* other separators */
4557                                 case T_RowExpr: /* other separators */
4558                                 case T_CoalesceExpr:    /* own parentheses */
4559                                 case T_MinMaxExpr:              /* own parentheses */
4560                                 case T_XmlExpr: /* own parentheses */
4561                                 case T_NullIfExpr:              /* other separators */
4562                                 case T_Aggref:  /* own parentheses */
4563                                 case T_WindowFunc:              /* own parentheses */
4564                                 case T_CaseExpr:                /* other separators */
4565                                         return true;
4566                                 default:
4567                                         return false;
4568                         }
4569
4570                 case T_BoolExpr:
4571                         switch (nodeTag(parentNode))
4572                         {
4573                                 case T_BoolExpr:
4574                                         if (prettyFlags & PRETTYFLAG_PAREN)
4575                                         {
4576                                                 BoolExprType type;
4577                                                 BoolExprType parentType;
4578
4579                                                 type = ((BoolExpr *) node)->boolop;
4580                                                 parentType = ((BoolExpr *) parentNode)->boolop;
4581                                                 switch (type)
4582                                                 {
4583                                                         case NOT_EXPR:
4584                                                         case AND_EXPR:
4585                                                                 if (parentType == AND_EXPR || parentType == OR_EXPR)
4586                                                                         return true;
4587                                                                 break;
4588                                                         case OR_EXPR:
4589                                                                 if (parentType == OR_EXPR)
4590                                                                         return true;
4591                                                                 break;
4592                                                 }
4593                                         }
4594                                         return false;
4595                                 case T_FuncExpr:
4596                                         {
4597                                                 /* special handling for casts */
4598                                                 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
4599
4600                                                 if (type == COERCE_EXPLICIT_CAST ||
4601                                                         type == COERCE_IMPLICIT_CAST)
4602                                                         return false;
4603                                                 return true;    /* own parentheses */
4604                                         }
4605                                 case T_ArrayRef:                /* other separators */
4606                                 case T_ArrayExpr:               /* other separators */
4607                                 case T_RowExpr: /* other separators */
4608                                 case T_CoalesceExpr:    /* own parentheses */
4609                                 case T_MinMaxExpr:              /* own parentheses */
4610                                 case T_XmlExpr: /* own parentheses */
4611                                 case T_NullIfExpr:              /* other separators */
4612                                 case T_Aggref:  /* own parentheses */
4613                                 case T_WindowFunc:              /* own parentheses */
4614                                 case T_CaseExpr:                /* other separators */
4615                                         return true;
4616                                 default:
4617                                         return false;
4618                         }
4619
4620                 default:
4621                         break;
4622         }
4623         /* those we don't know: in dubio complexo */
4624         return false;
4625 }
4626
4627
4628 /*
4629  * appendContextKeyword - append a keyword to buffer
4630  *
4631  * If prettyPrint is enabled, perform a line break, and adjust indentation.
4632  * Otherwise, just append the keyword.
4633  */
4634 static void
4635 appendContextKeyword(deparse_context *context, const char *str,
4636                                          int indentBefore, int indentAfter, int indentPlus)
4637 {
4638         if (PRETTY_INDENT(context))
4639         {
4640                 context->indentLevel += indentBefore;
4641
4642                 appendStringInfoChar(context->buf, '\n');
4643                 appendStringInfoSpaces(context->buf,
4644                                                            Max(context->indentLevel, 0) + indentPlus);
4645                 appendStringInfoString(context->buf, str);
4646
4647                 context->indentLevel += indentAfter;
4648                 if (context->indentLevel < 0)
4649                         context->indentLevel = 0;
4650         }
4651         else
4652                 appendStringInfoString(context->buf, str);
4653 }
4654
4655 /*
4656  * get_rule_expr_paren  - deparse expr using get_rule_expr,
4657  * embracing the string with parentheses if necessary for prettyPrint.
4658  *
4659  * Never embrace if prettyFlags=0, because it's done in the calling node.
4660  *
4661  * Any node that does *not* embrace its argument node by sql syntax (with
4662  * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
4663  * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
4664  * added.
4665  */
4666 static void
4667 get_rule_expr_paren(Node *node, deparse_context *context,
4668                                         bool showimplicit, Node *parentNode)
4669 {
4670         bool            need_paren;
4671
4672         need_paren = PRETTY_PAREN(context) &&
4673                 !isSimpleNode(node, parentNode, context->prettyFlags);
4674
4675         if (need_paren)
4676                 appendStringInfoChar(context->buf, '(');
4677
4678         get_rule_expr(node, context, showimplicit);
4679
4680         if (need_paren)
4681                 appendStringInfoChar(context->buf, ')');
4682 }
4683
4684
4685 /* ----------
4686  * get_rule_expr                        - Parse back an expression
4687  *
4688  * Note: showimplicit determines whether we display any implicit cast that
4689  * is present at the top of the expression tree.  It is a passed argument,
4690  * not a field of the context struct, because we change the value as we
4691  * recurse down into the expression.  In general we suppress implicit casts
4692  * when the result type is known with certainty (eg, the arguments of an
4693  * OR must be boolean).  We display implicit casts for arguments of functions
4694  * and operators, since this is needed to be certain that the same function
4695  * or operator will be chosen when the expression is re-parsed.
4696  * ----------
4697  */
4698 static void
4699 get_rule_expr(Node *node, deparse_context *context,
4700                           bool showimplicit)
4701 {
4702         StringInfo      buf = context->buf;
4703
4704         if (node == NULL)
4705                 return;
4706
4707         /*
4708          * Each level of get_rule_expr must emit an indivisible term
4709          * (parenthesized if necessary) to ensure result is reparsed into the same
4710          * expression tree.  The only exception is that when the input is a List,
4711          * we emit the component items comma-separated with no surrounding
4712          * decoration; this is convenient for most callers.
4713          */
4714         switch (nodeTag(node))
4715         {
4716                 case T_Var:
4717                         (void) get_variable((Var *) node, 0, true, context);
4718                         break;
4719
4720                 case T_Const:
4721                         get_const_expr((Const *) node, context, 0);
4722                         break;
4723
4724                 case T_Param:
4725                         get_parameter((Param *) node, context);
4726                         break;
4727
4728                 case T_Aggref:
4729                         get_agg_expr((Aggref *) node, context);
4730                         break;
4731
4732                 case T_WindowFunc:
4733                         get_windowfunc_expr((WindowFunc *) node, context);
4734                         break;
4735
4736                 case T_ArrayRef:
4737                         {
4738                                 ArrayRef   *aref = (ArrayRef *) node;
4739                                 bool            need_parens;
4740
4741                                 /*
4742                                  * If the argument is a CaseTestExpr, we must be inside a
4743                                  * FieldStore, ie, we are assigning to an element of an array
4744                                  * within a composite column.  Since we already punted on
4745                                  * displaying the FieldStore's target information, just punt
4746                                  * here too, and display only the assignment source
4747                                  * expression.
4748                                  */
4749                                 if (IsA(aref->refexpr, CaseTestExpr))
4750                                 {
4751                                         Assert(aref->refassgnexpr);
4752                                         get_rule_expr((Node *) aref->refassgnexpr,
4753                                                                   context, showimplicit);
4754                                         break;
4755                                 }
4756
4757                                 /*
4758                                  * Parenthesize the argument unless it's a simple Var or a
4759                                  * FieldSelect.  (In particular, if it's another ArrayRef, we
4760                                  * *must* parenthesize to avoid confusion.)
4761                                  */
4762                                 need_parens = !IsA(aref->refexpr, Var) &&
4763                                         !IsA(aref->refexpr, FieldSelect);
4764                                 if (need_parens)
4765                                         appendStringInfoChar(buf, '(');
4766                                 get_rule_expr((Node *) aref->refexpr, context, showimplicit);
4767                                 if (need_parens)
4768                                         appendStringInfoChar(buf, ')');
4769
4770                                 /*
4771                                  * If there's a refassgnexpr, we want to print the node in the
4772                                  * format "array[subscripts] := refassgnexpr".  This is not
4773                                  * legal SQL, so decompilation of INSERT or UPDATE statements
4774                                  * should always use processIndirection as part of the
4775                                  * statement-level syntax.      We should only see this when
4776                                  * EXPLAIN tries to print the targetlist of a plan resulting
4777                                  * from such a statement.
4778                                  */
4779                                 if (aref->refassgnexpr)
4780                                 {
4781                                         Node       *refassgnexpr;
4782
4783                                         /*
4784                                          * Use processIndirection to print this node's subscripts
4785                                          * as well as any additional field selections or
4786                                          * subscripting in immediate descendants.  It returns the
4787                                          * RHS expr that is actually being "assigned".
4788                                          */
4789                                         refassgnexpr = processIndirection(node, context, true);
4790                                         appendStringInfoString(buf, " := ");
4791                                         get_rule_expr(refassgnexpr, context, showimplicit);
4792                                 }
4793                                 else
4794                                 {
4795                                         /* Just an ordinary array fetch, so print subscripts */
4796                                         printSubscripts(aref, context);
4797                                 }
4798                         }
4799                         break;
4800
4801                 case T_FuncExpr:
4802                         get_func_expr((FuncExpr *) node, context, showimplicit);
4803                         break;
4804
4805                 case T_NamedArgExpr:
4806                         {
4807                                 NamedArgExpr *na = (NamedArgExpr *) node;
4808
4809                                 appendStringInfo(buf, "%s := ", quote_identifier(na->name));
4810                                 get_rule_expr((Node *) na->arg, context, showimplicit);
4811                         }
4812                         break;
4813
4814                 case T_OpExpr:
4815                         get_oper_expr((OpExpr *) node, context);
4816                         break;
4817
4818                 case T_DistinctExpr:
4819                         {
4820                                 DistinctExpr *expr = (DistinctExpr *) node;
4821                                 List       *args = expr->args;
4822                                 Node       *arg1 = (Node *) linitial(args);
4823                                 Node       *arg2 = (Node *) lsecond(args);
4824
4825                                 if (!PRETTY_PAREN(context))
4826                                         appendStringInfoChar(buf, '(');
4827                                 get_rule_expr_paren(arg1, context, true, node);
4828                                 appendStringInfo(buf, " IS DISTINCT FROM ");
4829                                 get_rule_expr_paren(arg2, context, true, node);
4830                                 if (!PRETTY_PAREN(context))
4831                                         appendStringInfoChar(buf, ')');
4832                         }
4833                         break;
4834
4835                 case T_ScalarArrayOpExpr:
4836                         {
4837                                 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
4838                                 List       *args = expr->args;
4839                                 Node       *arg1 = (Node *) linitial(args);
4840                                 Node       *arg2 = (Node *) lsecond(args);
4841
4842                                 if (!PRETTY_PAREN(context))
4843                                         appendStringInfoChar(buf, '(');
4844                                 get_rule_expr_paren(arg1, context, true, node);
4845                                 appendStringInfo(buf, " %s %s (",
4846                                                                  generate_operator_name(expr->opno,
4847                                                                                                                 exprType(arg1),
4848                                                                                    get_element_type(exprType(arg2))),
4849                                                                  expr->useOr ? "ANY" : "ALL");
4850                                 get_rule_expr_paren(arg2, context, true, node);
4851                                 appendStringInfoChar(buf, ')');
4852                                 if (!PRETTY_PAREN(context))
4853                                         appendStringInfoChar(buf, ')');
4854                         }
4855                         break;
4856
4857                 case T_BoolExpr:
4858                         {
4859                                 BoolExpr   *expr = (BoolExpr *) node;
4860                                 Node       *first_arg = linitial(expr->args);
4861                                 ListCell   *arg = lnext(list_head(expr->args));
4862
4863                                 switch (expr->boolop)
4864                                 {
4865                                         case AND_EXPR:
4866                                                 if (!PRETTY_PAREN(context))
4867                                                         appendStringInfoChar(buf, '(');
4868                                                 get_rule_expr_paren(first_arg, context,
4869                                                                                         false, node);
4870                                                 while (arg)
4871                                                 {
4872                                                         appendStringInfo(buf, " AND ");
4873                                                         get_rule_expr_paren((Node *) lfirst(arg), context,
4874                                                                                                 false, node);
4875                                                         arg = lnext(arg);
4876                                                 }
4877                                                 if (!PRETTY_PAREN(context))
4878                                                         appendStringInfoChar(buf, ')');
4879                                                 break;
4880
4881                                         case OR_EXPR:
4882                                                 if (!PRETTY_PAREN(context))
4883                                                         appendStringInfoChar(buf, '(');
4884                                                 get_rule_expr_paren(first_arg, context,
4885                                                                                         false, node);
4886                                                 while (arg)
4887                                                 {
4888                                                         appendStringInfo(buf, " OR ");
4889                                                         get_rule_expr_paren((Node *) lfirst(arg), context,
4890                                                                                                 false, node);
4891                                                         arg = lnext(arg);
4892                                                 }
4893                                                 if (!PRETTY_PAREN(context))
4894                                                         appendStringInfoChar(buf, ')');
4895                                                 break;
4896
4897                                         case NOT_EXPR:
4898                                                 if (!PRETTY_PAREN(context))
4899                                                         appendStringInfoChar(buf, '(');
4900                                                 appendStringInfo(buf, "NOT ");
4901                                                 get_rule_expr_paren(first_arg, context,
4902                                                                                         false, node);
4903                                                 if (!PRETTY_PAREN(context))
4904                                                         appendStringInfoChar(buf, ')');
4905                                                 break;
4906
4907                                         default:
4908                                                 elog(ERROR, "unrecognized boolop: %d",
4909                                                          (int) expr->boolop);
4910                                 }
4911                         }
4912                         break;
4913
4914                 case T_SubLink:
4915                         get_sublink_expr((SubLink *) node, context);
4916                         break;
4917
4918                 case T_SubPlan:
4919                         {
4920                                 SubPlan    *subplan = (SubPlan *) node;
4921
4922                                 /*
4923                                  * We cannot see an already-planned subplan in rule deparsing,
4924                                  * only while EXPLAINing a query plan.  We don't try to
4925                                  * reconstruct the original SQL, just reference the subplan
4926                                  * that appears elsewhere in EXPLAIN's result.
4927                                  */
4928                                 if (subplan->useHashTable)
4929                                         appendStringInfo(buf, "(hashed %s)", subplan->plan_name);
4930                                 else
4931                                         appendStringInfo(buf, "(%s)", subplan->plan_name);
4932                         }
4933                         break;
4934
4935                 case T_AlternativeSubPlan:
4936                         {
4937                                 AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
4938                                 ListCell   *lc;
4939
4940                                 /* As above, this can only happen during EXPLAIN */
4941                                 appendStringInfo(buf, "(alternatives: ");
4942                                 foreach(lc, asplan->subplans)
4943                                 {
4944                                         SubPlan    *splan = (SubPlan *) lfirst(lc);
4945
4946                                         Assert(IsA(splan, SubPlan));
4947                                         if (splan->useHashTable)
4948                                                 appendStringInfo(buf, "hashed %s", splan->plan_name);
4949                                         else
4950                                                 appendStringInfo(buf, "%s", splan->plan_name);
4951                                         if (lnext(lc))
4952                                                 appendStringInfo(buf, " or ");
4953                                 }
4954                                 appendStringInfo(buf, ")");
4955                         }
4956                         break;
4957
4958                 case T_FieldSelect:
4959                         {
4960                                 FieldSelect *fselect = (FieldSelect *) node;
4961                                 Node       *arg = (Node *) fselect->arg;
4962                                 int                     fno = fselect->fieldnum;
4963                                 const char *fieldname;
4964                                 bool            need_parens;
4965
4966                                 /*
4967                                  * Parenthesize the argument unless it's an ArrayRef or
4968                                  * another FieldSelect.  Note in particular that it would be
4969                                  * WRONG to not parenthesize a Var argument; simplicity is not
4970                                  * the issue here, having the right number of names is.
4971                                  */
4972                                 need_parens = !IsA(arg, ArrayRef) &&!IsA(arg, FieldSelect);
4973                                 if (need_parens)
4974                                         appendStringInfoChar(buf, '(');
4975                                 get_rule_expr(arg, context, true);
4976                                 if (need_parens)
4977                                         appendStringInfoChar(buf, ')');
4978
4979                                 /*
4980                                  * Get and print the field name.
4981                                  */
4982                                 fieldname = get_name_for_var_field((Var *) arg, fno,
4983                                                                                                    0, context);
4984                                 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
4985                         }
4986                         break;
4987
4988                 case T_FieldStore:
4989                         {
4990                                 FieldStore *fstore = (FieldStore *) node;
4991                                 bool            need_parens;
4992
4993                                 /*
4994                                  * There is no good way to represent a FieldStore as real SQL,
4995                                  * so decompilation of INSERT or UPDATE statements should
4996                                  * always use processIndirection as part of the
4997                                  * statement-level syntax.      We should only get here when
4998                                  * EXPLAIN tries to print the targetlist of a plan resulting
4999                                  * from such a statement.  The plan case is even harder than
5000                                  * ordinary rules would be, because the planner tries to
5001                                  * collapse multiple assignments to the same field or subfield
5002                                  * into one FieldStore; so we can see a list of target fields
5003                                  * not just one, and the arguments could be FieldStores
5004                                  * themselves.  We don't bother to try to print the target
5005                                  * field names; we just print the source arguments, with a
5006                                  * ROW() around them if there's more than one.  This isn't
5007                                  * terribly complete, but it's probably good enough for
5008                                  * EXPLAIN's purposes; especially since anything more would be
5009                                  * either hopelessly confusing or an even poorer
5010                                  * representation of what the plan is actually doing.
5011                                  */
5012                                 need_parens = (list_length(fstore->newvals) != 1);
5013                                 if (need_parens)
5014                                         appendStringInfoString(buf, "ROW(");
5015                                 get_rule_expr((Node *) fstore->newvals, context, showimplicit);
5016                                 if (need_parens)
5017                                         appendStringInfoChar(buf, ')');
5018                         }
5019                         break;
5020
5021                 case T_RelabelType:
5022                         {
5023                                 RelabelType *relabel = (RelabelType *) node;
5024                                 Node       *arg = (Node *) relabel->arg;
5025
5026                                 if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
5027                                         !showimplicit)
5028                                 {
5029                                         /* don't show the implicit cast */
5030                                         get_rule_expr_paren(arg, context, false, node);
5031                                 }
5032                                 else
5033                                 {
5034                                         get_coercion_expr(arg, context,
5035                                                                           relabel->resulttype,
5036                                                                           relabel->resulttypmod,
5037                                                                           node);
5038                                 }
5039                         }
5040                         break;
5041
5042                 case T_CoerceViaIO:
5043                         {
5044                                 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
5045                                 Node       *arg = (Node *) iocoerce->arg;
5046
5047                                 if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
5048                                         !showimplicit)
5049                                 {
5050                                         /* don't show the implicit cast */
5051                                         get_rule_expr_paren(arg, context, false, node);
5052                                 }
5053                                 else
5054                                 {
5055                                         get_coercion_expr(arg, context,
5056                                                                           iocoerce->resulttype,
5057                                                                           -1,
5058                                                                           node);
5059                                 }
5060                         }
5061                         break;
5062
5063                 case T_ArrayCoerceExpr:
5064                         {
5065                                 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
5066                                 Node       *arg = (Node *) acoerce->arg;
5067
5068                                 if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
5069                                         !showimplicit)
5070                                 {
5071                                         /* don't show the implicit cast */
5072                                         get_rule_expr_paren(arg, context, false, node);
5073                                 }
5074                                 else
5075                                 {
5076                                         get_coercion_expr(arg, context,
5077                                                                           acoerce->resulttype,
5078                                                                           acoerce->resulttypmod,
5079                                                                           node);
5080                                 }
5081                         }
5082                         break;
5083
5084                 case T_ConvertRowtypeExpr:
5085                         {
5086                                 ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
5087                                 Node       *arg = (Node *) convert->arg;
5088
5089                                 if (convert->convertformat == COERCE_IMPLICIT_CAST &&
5090                                         !showimplicit)
5091                                 {
5092                                         /* don't show the implicit cast */
5093                                         get_rule_expr_paren(arg, context, false, node);
5094                                 }
5095                                 else
5096                                 {
5097                                         get_coercion_expr(arg, context,
5098                                                                           convert->resulttype, -1,
5099                                                                           node);
5100                                 }
5101                         }
5102                         break;
5103
5104                 case T_CaseExpr:
5105                         {
5106                                 CaseExpr   *caseexpr = (CaseExpr *) node;
5107                                 ListCell   *temp;
5108
5109                                 appendContextKeyword(context, "CASE",
5110                                                                          0, PRETTYINDENT_VAR, 0);
5111                                 if (caseexpr->arg)
5112                                 {
5113                                         appendStringInfoChar(buf, ' ');
5114                                         get_rule_expr((Node *) caseexpr->arg, context, true);
5115                                 }
5116                                 foreach(temp, caseexpr->args)
5117                                 {
5118                                         CaseWhen   *when = (CaseWhen *) lfirst(temp);
5119                                         Node       *w = (Node *) when->expr;
5120
5121                                         if (!PRETTY_INDENT(context))
5122                                                 appendStringInfoChar(buf, ' ');
5123                                         appendContextKeyword(context, "WHEN ",
5124                                                                                  0, 0, 0);
5125                                         if (caseexpr->arg)
5126                                         {
5127                                                 /*
5128                                                  * The parser should have produced WHEN clauses of the
5129                                                  * form "CaseTestExpr = RHS"; we want to show just the
5130                                                  * RHS.  If the user wrote something silly like "CASE
5131                                                  * boolexpr WHEN TRUE THEN ...", then the optimizer's
5132                                                  * simplify_boolean_equality() may have reduced this
5133                                                  * to just "CaseTestExpr" or "NOT CaseTestExpr", for
5134                                                  * which we have to show "TRUE" or "FALSE".  Also,
5135                                                  * depending on context the original CaseTestExpr
5136                                                  * might have been reduced to a Const (but we won't
5137                                                  * see "WHEN Const").  We have also to consider the
5138                                                  * possibility that an implicit coercion was inserted
5139                                                  * between the CaseTestExpr and the operator.
5140                                                  */
5141                                                 if (IsA(w, OpExpr))
5142                                                 {
5143                                                         List       *args = ((OpExpr *) w)->args;
5144                                                         Node       *lhs;
5145                                                         Node       *rhs;
5146
5147                                                         Assert(list_length(args) == 2);
5148                                                         lhs = strip_implicit_coercions(linitial(args));
5149                                                         Assert(IsA(lhs, CaseTestExpr) ||
5150                                                                    IsA(lhs, Const));
5151                                                         rhs = (Node *) lsecond(args);
5152                                                         get_rule_expr(rhs, context, false);
5153                                                 }
5154                                                 else if (IsA(strip_implicit_coercions(w),
5155                                                                          CaseTestExpr))
5156                                                         appendStringInfo(buf, "TRUE");
5157                                                 else if (not_clause(w))
5158                                                 {
5159                                                         Assert(IsA(strip_implicit_coercions((Node *) get_notclausearg((Expr *) w)),
5160                                                                            CaseTestExpr));
5161                                                         appendStringInfo(buf, "FALSE");
5162                                                 }
5163                                                 else
5164                                                         elog(ERROR, "unexpected CASE WHEN clause: %d",
5165                                                                  (int) nodeTag(w));
5166                                         }
5167                                         else
5168                                                 get_rule_expr(w, context, false);
5169                                         appendStringInfo(buf, " THEN ");
5170                                         get_rule_expr((Node *) when->result, context, true);
5171                                 }
5172                                 if (!PRETTY_INDENT(context))
5173                                         appendStringInfoChar(buf, ' ');
5174                                 appendContextKeyword(context, "ELSE ",
5175                                                                          0, 0, 0);
5176                                 get_rule_expr((Node *) caseexpr->defresult, context, true);
5177                                 if (!PRETTY_INDENT(context))
5178                                         appendStringInfoChar(buf, ' ');
5179                                 appendContextKeyword(context, "END",
5180                                                                          -PRETTYINDENT_VAR, 0, 0);
5181                         }
5182                         break;
5183
5184                 case T_ArrayExpr:
5185                         {
5186                                 ArrayExpr  *arrayexpr = (ArrayExpr *) node;
5187
5188                                 appendStringInfo(buf, "ARRAY[");
5189                                 get_rule_expr((Node *) arrayexpr->elements, context, true);
5190                                 appendStringInfoChar(buf, ']');
5191
5192                                 /*
5193                                  * If the array isn't empty, we assume its elements are
5194                                  * coerced to the desired type.  If it's empty, though, we
5195                                  * need an explicit coercion to the array type.
5196                                  */
5197                                 if (arrayexpr->elements == NIL)
5198                                         appendStringInfo(buf, "::%s",
5199                                           format_type_with_typemod(arrayexpr->array_typeid, -1));
5200                         }
5201                         break;
5202
5203                 case T_RowExpr:
5204                         {
5205                                 RowExpr    *rowexpr = (RowExpr *) node;
5206                                 TupleDesc       tupdesc = NULL;
5207                                 ListCell   *arg;
5208                                 int                     i;
5209                                 char       *sep;
5210
5211                                 /*
5212                                  * If it's a named type and not RECORD, we may have to skip
5213                                  * dropped columns and/or claim there are NULLs for added
5214                                  * columns.
5215                                  */
5216                                 if (rowexpr->row_typeid != RECORDOID)
5217                                 {
5218                                         tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
5219                                         Assert(list_length(rowexpr->args) <= tupdesc->natts);
5220                                 }
5221
5222                                 /*
5223                                  * SQL99 allows "ROW" to be omitted when there is more than
5224                                  * one column, but for simplicity we always print it.
5225                                  */
5226                                 appendStringInfo(buf, "ROW(");
5227                                 sep = "";
5228                                 i = 0;
5229                                 foreach(arg, rowexpr->args)
5230                                 {
5231                                         Node       *e = (Node *) lfirst(arg);
5232
5233                                         if (tupdesc == NULL ||
5234                                                 !tupdesc->attrs[i]->attisdropped)
5235                                         {
5236                                                 appendStringInfoString(buf, sep);
5237                                                 get_rule_expr(e, context, true);
5238                                                 sep = ", ";
5239                                         }
5240                                         i++;
5241                                 }
5242                                 if (tupdesc != NULL)
5243                                 {
5244                                         while (i < tupdesc->natts)
5245                                         {
5246                                                 if (!tupdesc->attrs[i]->attisdropped)
5247                                                 {
5248                                                         appendStringInfoString(buf, sep);
5249                                                         appendStringInfo(buf, "NULL");
5250                                                         sep = ", ";
5251                                                 }
5252                                                 i++;
5253                                         }
5254
5255                                         ReleaseTupleDesc(tupdesc);
5256                                 }
5257                                 appendStringInfo(buf, ")");
5258                                 if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
5259                                         appendStringInfo(buf, "::%s",
5260                                                   format_type_with_typemod(rowexpr->row_typeid, -1));
5261                         }
5262                         break;
5263
5264                 case T_RowCompareExpr:
5265                         {
5266                                 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
5267                                 ListCell   *arg;
5268                                 char       *sep;
5269
5270                                 /*
5271                                  * SQL99 allows "ROW" to be omitted when there is more than
5272                                  * one column, but for simplicity we always print it.
5273                                  */
5274                                 appendStringInfo(buf, "(ROW(");
5275                                 sep = "";
5276                                 foreach(arg, rcexpr->largs)
5277                                 {
5278                                         Node       *e = (Node *) lfirst(arg);
5279
5280                                         appendStringInfoString(buf, sep);
5281                                         get_rule_expr(e, context, true);
5282                                         sep = ", ";
5283                                 }
5284
5285                                 /*
5286                                  * We assume that the name of the first-column operator will
5287                                  * do for all the rest too.  This is definitely open to
5288                                  * failure, eg if some but not all operators were renamed
5289                                  * since the construct was parsed, but there seems no way to
5290                                  * be perfect.
5291                                  */
5292                                 appendStringInfo(buf, ") %s ROW(",
5293                                                   generate_operator_name(linitial_oid(rcexpr->opnos),
5294                                                                                    exprType(linitial(rcexpr->largs)),
5295                                                                                  exprType(linitial(rcexpr->rargs))));
5296                                 sep = "";
5297                                 foreach(arg, rcexpr->rargs)
5298                                 {
5299                                         Node       *e = (Node *) lfirst(arg);
5300
5301                                         appendStringInfoString(buf, sep);
5302                                         get_rule_expr(e, context, true);
5303                                         sep = ", ";
5304                                 }
5305                                 appendStringInfo(buf, "))");
5306                         }
5307                         break;
5308
5309                 case T_CoalesceExpr:
5310                         {
5311                                 CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
5312
5313                                 appendStringInfo(buf, "COALESCE(");
5314                                 get_rule_expr((Node *) coalesceexpr->args, context, true);
5315                                 appendStringInfoChar(buf, ')');
5316                         }
5317                         break;
5318
5319                 case T_MinMaxExpr:
5320                         {
5321                                 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
5322
5323                                 switch (minmaxexpr->op)
5324                                 {
5325                                         case IS_GREATEST:
5326                                                 appendStringInfo(buf, "GREATEST(");
5327                                                 break;
5328                                         case IS_LEAST:
5329                                                 appendStringInfo(buf, "LEAST(");
5330                                                 break;
5331                                 }
5332                                 get_rule_expr((Node *) minmaxexpr->args, context, true);
5333                                 appendStringInfoChar(buf, ')');
5334                         }
5335                         break;
5336
5337                 case T_XmlExpr:
5338                         {
5339                                 XmlExpr    *xexpr = (XmlExpr *) node;
5340                                 bool            needcomma = false;
5341                                 ListCell   *arg;
5342                                 ListCell   *narg;
5343                                 Const      *con;
5344
5345                                 switch (xexpr->op)
5346                                 {
5347                                         case IS_XMLCONCAT:
5348                                                 appendStringInfoString(buf, "XMLCONCAT(");
5349                                                 break;
5350                                         case IS_XMLELEMENT:
5351                                                 appendStringInfoString(buf, "XMLELEMENT(");
5352                                                 break;
5353                                         case IS_XMLFOREST:
5354                                                 appendStringInfoString(buf, "XMLFOREST(");
5355                                                 break;
5356                                         case IS_XMLPARSE:
5357                                                 appendStringInfoString(buf, "XMLPARSE(");
5358                                                 break;
5359                                         case IS_XMLPI:
5360                                                 appendStringInfoString(buf, "XMLPI(");
5361                                                 break;
5362                                         case IS_XMLROOT:
5363                                                 appendStringInfoString(buf, "XMLROOT(");
5364                                                 break;
5365                                         case IS_XMLSERIALIZE:
5366                                                 appendStringInfoString(buf, "XMLSERIALIZE(");
5367                                                 break;
5368                                         case IS_DOCUMENT:
5369                                                 break;
5370                                 }
5371                                 if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
5372                                 {
5373                                         if (xexpr->xmloption == XMLOPTION_DOCUMENT)
5374                                                 appendStringInfoString(buf, "DOCUMENT ");
5375                                         else
5376                                                 appendStringInfoString(buf, "CONTENT ");
5377                                 }
5378                                 if (xexpr->name)
5379                                 {
5380                                         appendStringInfo(buf, "NAME %s",
5381                                                                          quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
5382                                         needcomma = true;
5383                                 }
5384                                 if (xexpr->named_args)
5385                                 {
5386                                         if (xexpr->op != IS_XMLFOREST)
5387                                         {
5388                                                 if (needcomma)
5389                                                         appendStringInfoString(buf, ", ");
5390                                                 appendStringInfoString(buf, "XMLATTRIBUTES(");
5391                                                 needcomma = false;
5392                                         }
5393                                         forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
5394                                         {
5395                                                 Node       *e = (Node *) lfirst(arg);
5396                                                 char       *argname = strVal(lfirst(narg));
5397
5398                                                 if (needcomma)
5399                                                         appendStringInfoString(buf, ", ");
5400                                                 get_rule_expr((Node *) e, context, true);
5401                                                 appendStringInfo(buf, " AS %s",
5402                                                                                  quote_identifier(map_xml_name_to_sql_identifier(argname)));
5403                                                 needcomma = true;
5404                                         }
5405                                         if (xexpr->op != IS_XMLFOREST)
5406                                                 appendStringInfoChar(buf, ')');
5407                                 }
5408                                 if (xexpr->args)
5409                                 {
5410                                         if (needcomma)
5411                                                 appendStringInfoString(buf, ", ");
5412                                         switch (xexpr->op)
5413                                         {
5414                                                 case IS_XMLCONCAT:
5415                                                 case IS_XMLELEMENT:
5416                                                 case IS_XMLFOREST:
5417                                                 case IS_XMLPI:
5418                                                 case IS_XMLSERIALIZE:
5419                                                         /* no extra decoration needed */
5420                                                         get_rule_expr((Node *) xexpr->args, context, true);
5421                                                         break;
5422                                                 case IS_XMLPARSE:
5423                                                         Assert(list_length(xexpr->args) == 2);
5424
5425                                                         get_rule_expr((Node *) linitial(xexpr->args),
5426                                                                                   context, true);
5427
5428                                                         con = (Const *) lsecond(xexpr->args);
5429                                                         Assert(IsA(con, Const));
5430                                                         Assert(!con->constisnull);
5431                                                         if (DatumGetBool(con->constvalue))
5432                                                                 appendStringInfoString(buf,
5433                                                                                                          " PRESERVE WHITESPACE");
5434                                                         else
5435                                                                 appendStringInfoString(buf,
5436                                                                                                            " STRIP WHITESPACE");
5437                                                         break;
5438                                                 case IS_XMLROOT:
5439                                                         Assert(list_length(xexpr->args) == 3);
5440
5441                                                         get_rule_expr((Node *) linitial(xexpr->args),
5442                                                                                   context, true);
5443
5444                                                         appendStringInfoString(buf, ", VERSION ");
5445                                                         con = (Const *) lsecond(xexpr->args);
5446                                                         if (IsA(con, Const) &&
5447                                                                 con->constisnull)
5448                                                                 appendStringInfoString(buf, "NO VALUE");
5449                                                         else
5450                                                                 get_rule_expr((Node *) con, context, false);
5451
5452                                                         con = (Const *) lthird(xexpr->args);
5453                                                         Assert(IsA(con, Const));
5454                                                         if (con->constisnull)
5455                                                                  /* suppress STANDALONE NO VALUE */ ;
5456                                                         else
5457                                                         {
5458                                                                 switch (DatumGetInt32(con->constvalue))
5459                                                                 {
5460                                                                         case XML_STANDALONE_YES:
5461                                                                                 appendStringInfoString(buf,
5462                                                                                                                  ", STANDALONE YES");
5463                                                                                 break;
5464                                                                         case XML_STANDALONE_NO:
5465                                                                                 appendStringInfoString(buf,
5466                                                                                                                   ", STANDALONE NO");
5467                                                                                 break;
5468                                                                         case XML_STANDALONE_NO_VALUE:
5469                                                                                 appendStringInfoString(buf,
5470                                                                                                         ", STANDALONE NO VALUE");
5471                                                                                 break;
5472                                                                         default:
5473                                                                                 break;
5474                                                                 }
5475                                                         }
5476                                                         break;
5477                                                 case IS_DOCUMENT:
5478                                                         get_rule_expr_paren((Node *) xexpr->args, context, false, node);
5479                                                         break;
5480                                         }
5481
5482                                 }
5483                                 if (xexpr->op == IS_XMLSERIALIZE)
5484                                         appendStringInfo(buf, " AS %s", format_type_with_typemod(xexpr->type,
5485                                                                                                                          xexpr->typmod));
5486                                 if (xexpr->op == IS_DOCUMENT)
5487                                         appendStringInfoString(buf, " IS DOCUMENT");
5488                                 else
5489                                         appendStringInfoChar(buf, ')');
5490                         }
5491                         break;
5492
5493                 case T_NullIfExpr:
5494                         {
5495                                 NullIfExpr *nullifexpr = (NullIfExpr *) node;
5496
5497                                 appendStringInfo(buf, "NULLIF(");
5498                                 get_rule_expr((Node *) nullifexpr->args, context, true);
5499                                 appendStringInfoChar(buf, ')');
5500                         }
5501                         break;
5502
5503                 case T_NullTest:
5504                         {
5505                                 NullTest   *ntest = (NullTest *) node;
5506
5507                                 if (!PRETTY_PAREN(context))
5508                                         appendStringInfoChar(buf, '(');
5509                                 get_rule_expr_paren((Node *) ntest->arg, context, true, node);
5510                                 switch (ntest->nulltesttype)
5511                                 {
5512                                         case IS_NULL:
5513                                                 appendStringInfo(buf, " IS NULL");
5514                                                 break;
5515                                         case IS_NOT_NULL:
5516                                                 appendStringInfo(buf, " IS NOT NULL");
5517                                                 break;
5518                                         default:
5519                                                 elog(ERROR, "unrecognized nulltesttype: %d",
5520                                                          (int) ntest->nulltesttype);
5521                                 }
5522                                 if (!PRETTY_PAREN(context))
5523                                         appendStringInfoChar(buf, ')');
5524                         }
5525                         break;
5526
5527                 case T_BooleanTest:
5528                         {
5529                                 BooleanTest *btest = (BooleanTest *) node;
5530
5531                                 if (!PRETTY_PAREN(context))
5532                                         appendStringInfoChar(buf, '(');
5533                                 get_rule_expr_paren((Node *) btest->arg, context, false, node);
5534                                 switch (btest->booltesttype)
5535                                 {
5536                                         case IS_TRUE:
5537                                                 appendStringInfo(buf, " IS TRUE");
5538                                                 break;
5539                                         case IS_NOT_TRUE:
5540                                                 appendStringInfo(buf, " IS NOT TRUE");
5541                                                 break;
5542                                         case IS_FALSE:
5543                                                 appendStringInfo(buf, " IS FALSE");
5544                                                 break;
5545                                         case IS_NOT_FALSE:
5546                                                 appendStringInfo(buf, " IS NOT FALSE");
5547                                                 break;
5548                                         case IS_UNKNOWN:
5549                                                 appendStringInfo(buf, " IS UNKNOWN");
5550                                                 break;
5551                                         case IS_NOT_UNKNOWN:
5552                                                 appendStringInfo(buf, " IS NOT UNKNOWN");
5553                                                 break;
5554                                         default:
5555                                                 elog(ERROR, "unrecognized booltesttype: %d",
5556                                                          (int) btest->booltesttype);
5557                                 }
5558                                 if (!PRETTY_PAREN(context))
5559                                         appendStringInfoChar(buf, ')');
5560                         }
5561                         break;
5562
5563                 case T_CoerceToDomain:
5564                         {
5565                                 CoerceToDomain *ctest = (CoerceToDomain *) node;
5566                                 Node       *arg = (Node *) ctest->arg;
5567
5568                                 if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
5569                                         !showimplicit)
5570                                 {
5571                                         /* don't show the implicit cast */
5572                                         get_rule_expr(arg, context, false);
5573                                 }
5574                                 else
5575                                 {
5576                                         get_coercion_expr(arg, context,
5577                                                                           ctest->resulttype,
5578                                                                           ctest->resulttypmod,
5579                                                                           node);
5580                                 }
5581                         }
5582                         break;
5583
5584                 case T_CoerceToDomainValue:
5585                         appendStringInfo(buf, "VALUE");
5586                         break;
5587
5588                 case T_SetToDefault:
5589                         appendStringInfo(buf, "DEFAULT");
5590                         break;
5591
5592                 case T_CurrentOfExpr:
5593                         {
5594                                 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
5595
5596                                 if (cexpr->cursor_name)
5597                                         appendStringInfo(buf, "CURRENT OF %s",
5598                                                                          quote_identifier(cexpr->cursor_name));
5599                                 else
5600                                         appendStringInfo(buf, "CURRENT OF $%d",
5601                                                                          cexpr->cursor_param);
5602                         }
5603                         break;
5604
5605                 case T_List:
5606                         {
5607                                 char       *sep;
5608                                 ListCell   *l;
5609
5610                                 sep = "";
5611                                 foreach(l, (List *) node)
5612                                 {
5613                                         appendStringInfoString(buf, sep);
5614                                         get_rule_expr((Node *) lfirst(l), context, showimplicit);
5615                                         sep = ", ";
5616                                 }
5617                         }
5618                         break;
5619
5620                 default:
5621                         elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
5622                         break;
5623         }
5624 }
5625
5626
5627 /*
5628  * get_oper_expr                        - Parse back an OpExpr node
5629  */
5630 static void
5631 get_oper_expr(OpExpr *expr, deparse_context *context)
5632 {
5633         StringInfo      buf = context->buf;
5634         Oid                     opno = expr->opno;
5635         List       *args = expr->args;
5636
5637         if (!PRETTY_PAREN(context))
5638                 appendStringInfoChar(buf, '(');
5639         if (list_length(args) == 2)
5640         {
5641                 /* binary operator */
5642                 Node       *arg1 = (Node *) linitial(args);
5643                 Node       *arg2 = (Node *) lsecond(args);
5644
5645                 get_rule_expr_paren(arg1, context, true, (Node *) expr);
5646                 appendStringInfo(buf, " %s ",
5647                                                  generate_operator_name(opno,
5648                                                                                                 exprType(arg1),
5649                                                                                                 exprType(arg2)));
5650                 get_rule_expr_paren(arg2, context, true, (Node *) expr);
5651         }
5652         else
5653         {
5654                 /* unary operator --- but which side? */
5655                 Node       *arg = (Node *) linitial(args);
5656                 HeapTuple       tp;
5657                 Form_pg_operator optup;
5658
5659                 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
5660                 if (!HeapTupleIsValid(tp))
5661                         elog(ERROR, "cache lookup failed for operator %u", opno);
5662                 optup = (Form_pg_operator) GETSTRUCT(tp);
5663                 switch (optup->oprkind)
5664                 {
5665                         case 'l':
5666                                 appendStringInfo(buf, "%s ",
5667                                                                  generate_operator_name(opno,
5668                                                                                                                 InvalidOid,
5669                                                                                                                 exprType(arg)));
5670                                 get_rule_expr_paren(arg, context, true, (Node *) expr);
5671                                 break;
5672                         case 'r':
5673                                 get_rule_expr_paren(arg, context, true, (Node *) expr);
5674                                 appendStringInfo(buf, " %s",
5675                                                                  generate_operator_name(opno,
5676                                                                                                                 exprType(arg),
5677                                                                                                                 InvalidOid));
5678                                 break;
5679                         default:
5680                                 elog(ERROR, "bogus oprkind: %d", optup->oprkind);
5681                 }
5682                 ReleaseSysCache(tp);
5683         }
5684         if (!PRETTY_PAREN(context))
5685                 appendStringInfoChar(buf, ')');
5686 }
5687
5688 /*
5689  * get_func_expr                        - Parse back a FuncExpr node
5690  */
5691 static void
5692 get_func_expr(FuncExpr *expr, deparse_context *context,
5693                           bool showimplicit)
5694 {
5695         StringInfo      buf = context->buf;
5696         Oid                     funcoid = expr->funcid;
5697         Oid                     argtypes[FUNC_MAX_ARGS];
5698         int                     nargs;
5699         List       *argnames;
5700         bool            is_variadic;
5701         ListCell   *l;
5702
5703         /*
5704          * If the function call came from an implicit coercion, then just show the
5705          * first argument --- unless caller wants to see implicit coercions.
5706          */
5707         if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
5708         {
5709                 get_rule_expr_paren((Node *) linitial(expr->args), context,
5710                                                         false, (Node *) expr);
5711                 return;
5712         }
5713
5714         /*
5715          * If the function call came from a cast, then show the first argument
5716          * plus an explicit cast operation.
5717          */
5718         if (expr->funcformat == COERCE_EXPLICIT_CAST ||
5719                 expr->funcformat == COERCE_IMPLICIT_CAST)
5720         {
5721                 Node       *arg = linitial(expr->args);
5722                 Oid                     rettype = expr->funcresulttype;
5723                 int32           coercedTypmod;
5724
5725                 /* Get the typmod if this is a length-coercion function */
5726                 (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
5727
5728                 get_coercion_expr(arg, context,
5729                                                   rettype, coercedTypmod,
5730                                                   (Node *) expr);
5731
5732                 return;
5733         }
5734
5735         /*
5736          * Normal function: display as proname(args).  First we need to extract
5737          * the argument datatypes.
5738          */
5739         if (list_length(expr->args) > FUNC_MAX_ARGS)
5740                 ereport(ERROR,
5741                                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5742                                  errmsg("too many arguments")));
5743         nargs = 0;
5744         argnames = NIL;
5745         foreach(l, expr->args)
5746         {
5747                 Node       *arg = (Node *) lfirst(l);
5748
5749                 if (IsA(arg, NamedArgExpr))
5750                         argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
5751                 argtypes[nargs] = exprType(arg);
5752                 nargs++;
5753         }
5754
5755         appendStringInfo(buf, "%s(",
5756                                          generate_function_name(funcoid, nargs,
5757                                                                                         argnames, argtypes,
5758                                                                                         &is_variadic));
5759         nargs = 0;
5760         foreach(l, expr->args)
5761         {
5762                 if (nargs++ > 0)
5763                         appendStringInfoString(buf, ", ");
5764                 if (is_variadic && lnext(l) == NULL)
5765                         appendStringInfoString(buf, "VARIADIC ");
5766                 get_rule_expr((Node *) lfirst(l), context, true);
5767         }
5768         appendStringInfoChar(buf, ')');
5769 }
5770
5771 /*
5772  * get_agg_expr                 - Parse back an Aggref node
5773  */
5774 static void
5775 get_agg_expr(Aggref *aggref, deparse_context *context)
5776 {
5777         StringInfo      buf = context->buf;
5778         Oid                     argtypes[FUNC_MAX_ARGS];
5779         List       *arglist;
5780         int                     nargs;
5781         ListCell   *l;
5782
5783         /* Extract the regular arguments, ignoring resjunk stuff for the moment */
5784         arglist = NIL;
5785         nargs = 0;
5786         foreach(l, aggref->args)
5787         {
5788                 TargetEntry *tle = (TargetEntry *) lfirst(l);
5789                 Node       *arg = (Node *) tle->expr;
5790
5791                 Assert(!IsA(arg, NamedArgExpr));
5792                 if (tle->resjunk)
5793                         continue;
5794                 if (nargs >= FUNC_MAX_ARGS)             /* paranoia */
5795                         ereport(ERROR,
5796                                         (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5797                                          errmsg("too many arguments")));
5798                 argtypes[nargs] = exprType(arg);
5799                 arglist = lappend(arglist, arg);
5800                 nargs++;
5801         }
5802
5803         appendStringInfo(buf, "%s(%s",
5804                                          generate_function_name(aggref->aggfnoid, nargs,
5805                                                                                         NIL, argtypes, NULL),
5806                                          (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
5807         /* aggstar can be set only in zero-argument aggregates */
5808         if (aggref->aggstar)
5809                 appendStringInfoChar(buf, '*');
5810         else
5811                 get_rule_expr((Node *) arglist, context, true);
5812         if (aggref->aggorder != NIL)
5813         {
5814                 appendStringInfoString(buf, " ORDER BY ");
5815                 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
5816         }
5817         appendStringInfoChar(buf, ')');
5818 }
5819
5820 /*
5821  * get_windowfunc_expr  - Parse back a WindowFunc node
5822  */
5823 static void
5824 get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
5825 {
5826         StringInfo      buf = context->buf;
5827         Oid                     argtypes[FUNC_MAX_ARGS];
5828         int                     nargs;
5829         ListCell   *l;
5830
5831         if (list_length(wfunc->args) > FUNC_MAX_ARGS)
5832                 ereport(ERROR,
5833                                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5834                                  errmsg("too many arguments")));
5835         nargs = 0;
5836         foreach(l, wfunc->args)
5837         {
5838                 Node       *arg = (Node *) lfirst(l);
5839
5840                 Assert(!IsA(arg, NamedArgExpr));
5841                 argtypes[nargs] = exprType(arg);
5842                 nargs++;
5843         }
5844
5845         appendStringInfo(buf, "%s(",
5846                                          generate_function_name(wfunc->winfnoid, nargs,
5847                                                                                         NIL, argtypes, NULL));
5848         /* winstar can be set only in zero-argument aggregates */
5849         if (wfunc->winstar)
5850                 appendStringInfoChar(buf, '*');
5851         else
5852                 get_rule_expr((Node *) wfunc->args, context, true);
5853         appendStringInfoString(buf, ") OVER ");
5854
5855         foreach(l, context->windowClause)
5856         {
5857                 WindowClause *wc = (WindowClause *) lfirst(l);
5858
5859                 if (wc->winref == wfunc->winref)
5860                 {
5861                         if (wc->name)
5862                                 appendStringInfoString(buf, quote_identifier(wc->name));
5863                         else
5864                                 get_rule_windowspec(wc, context->windowTList, context);
5865                         break;
5866                 }
5867         }
5868         if (l == NULL)
5869         {
5870                 if (context->windowClause)
5871                         elog(ERROR, "could not find window clause for winref %u",
5872                                  wfunc->winref);
5873
5874                 /*
5875                  * In EXPLAIN, we don't have window context information available, so
5876                  * we have to settle for this:
5877                  */
5878                 appendStringInfoString(buf, "(?)");
5879         }
5880 }
5881
5882 /* ----------
5883  * get_coercion_expr
5884  *
5885  *      Make a string representation of a value coerced to a specific type
5886  * ----------
5887  */
5888 static void
5889 get_coercion_expr(Node *arg, deparse_context *context,
5890                                   Oid resulttype, int32 resulttypmod,
5891                                   Node *parentNode)
5892 {
5893         StringInfo      buf = context->buf;
5894
5895         /*
5896          * Since parse_coerce.c doesn't immediately collapse application of
5897          * length-coercion functions to constants, what we'll typically see in
5898          * such cases is a Const with typmod -1 and a length-coercion function
5899          * right above it.      Avoid generating redundant output. However, beware of
5900          * suppressing casts when the user actually wrote something like
5901          * 'foo'::text::char(3).
5902          */
5903         if (arg && IsA(arg, Const) &&
5904                 ((Const *) arg)->consttype == resulttype &&
5905                 ((Const *) arg)->consttypmod == -1)
5906         {
5907                 /* Show the constant without normal ::typename decoration */
5908                 get_const_expr((Const *) arg, context, -1);
5909         }
5910         else
5911         {
5912                 if (!PRETTY_PAREN(context))
5913                         appendStringInfoChar(buf, '(');
5914                 get_rule_expr_paren(arg, context, false, parentNode);
5915                 if (!PRETTY_PAREN(context))
5916                         appendStringInfoChar(buf, ')');
5917         }
5918         appendStringInfo(buf, "::%s",
5919                                          format_type_with_typemod(resulttype, resulttypmod));
5920 }
5921
5922 /* ----------
5923  * get_const_expr
5924  *
5925  *      Make a string representation of a Const
5926  *
5927  * showtype can be -1 to never show "::typename" decoration, or +1 to always
5928  * show it, or 0 to show it only if the constant wouldn't be assumed to be
5929  * the right type by default.
5930  * ----------
5931  */
5932 static void
5933 get_const_expr(Const *constval, deparse_context *context, int showtype)
5934 {
5935         StringInfo      buf = context->buf;
5936         Oid                     typoutput;
5937         bool            typIsVarlena;
5938         char       *extval;
5939         bool            isfloat = false;
5940         bool            needlabel;
5941
5942         if (constval->constisnull)
5943         {
5944                 /*
5945                  * Always label the type of a NULL constant to prevent misdecisions
5946                  * about type when reparsing.
5947                  */
5948                 appendStringInfo(buf, "NULL");
5949                 if (showtype >= 0)
5950                         appendStringInfo(buf, "::%s",
5951                                                          format_type_with_typemod(constval->consttype,
5952                                                                                                           constval->consttypmod));
5953                 return;
5954         }
5955
5956         getTypeOutputInfo(constval->consttype,
5957                                           &typoutput, &typIsVarlena);
5958
5959         extval = OidOutputFunctionCall(typoutput, constval->constvalue);
5960
5961         switch (constval->consttype)
5962         {
5963                 case INT2OID:
5964                 case INT4OID:
5965                 case INT8OID:
5966                 case OIDOID:
5967                 case FLOAT4OID:
5968                 case FLOAT8OID:
5969                 case NUMERICOID:
5970                         {
5971                                 /*
5972                                  * These types are printed without quotes unless they contain
5973                                  * values that aren't accepted by the scanner unquoted (e.g.,
5974                                  * 'NaN').      Note that strtod() and friends might accept NaN,
5975                                  * so we can't use that to test.
5976                                  *
5977                                  * In reality we only need to defend against infinity and NaN,
5978                                  * so we need not get too crazy about pattern matching here.
5979                                  *
5980                                  * There is a special-case gotcha: if the constant is signed,
5981                                  * we need to parenthesize it, else the parser might see a
5982                                  * leading plus/minus as binding less tightly than adjacent
5983                                  * operators --- particularly, the cast that we might attach
5984                                  * below.
5985                                  */
5986                                 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
5987                                 {
5988                                         if (extval[0] == '+' || extval[0] == '-')
5989                                                 appendStringInfo(buf, "(%s)", extval);
5990                                         else
5991                                                 appendStringInfoString(buf, extval);
5992                                         if (strcspn(extval, "eE.") != strlen(extval))
5993                                                 isfloat = true; /* it looks like a float */
5994                                 }
5995                                 else
5996                                         appendStringInfo(buf, "'%s'", extval);
5997                         }
5998                         break;
5999
6000                 case BITOID:
6001                 case VARBITOID:
6002                         appendStringInfo(buf, "B'%s'", extval);
6003                         break;
6004
6005                 case BOOLOID:
6006                         if (strcmp(extval, "t") == 0)
6007                                 appendStringInfo(buf, "true");
6008                         else
6009                                 appendStringInfo(buf, "false");
6010                         break;
6011
6012                 default:
6013                         simple_quote_literal(buf, extval);
6014                         break;
6015         }
6016
6017         pfree(extval);
6018
6019         if (showtype < 0)
6020                 return;
6021
6022         /*
6023          * For showtype == 0, append ::typename unless the constant will be
6024          * implicitly typed as the right type when it is read in.
6025          *
6026          * XXX this code has to be kept in sync with the behavior of the parser,
6027          * especially make_const.
6028          */
6029         switch (constval->consttype)
6030         {
6031                 case BOOLOID:
6032                 case INT4OID:
6033                 case UNKNOWNOID:
6034                         /* These types can be left unlabeled */
6035                         needlabel = false;
6036                         break;
6037                 case NUMERICOID:
6038
6039                         /*
6040                          * Float-looking constants will be typed as numeric, but if
6041                          * there's a specific typmod we need to show it.
6042                          */
6043                         needlabel = !isfloat || (constval->consttypmod >= 0);
6044                         break;
6045                 default:
6046                         needlabel = true;
6047                         break;
6048         }
6049         if (needlabel || showtype > 0)
6050                 appendStringInfo(buf, "::%s",
6051                                                  format_type_with_typemod(constval->consttype,
6052                                                                                                   constval->consttypmod));
6053 }
6054
6055 /*
6056  * simple_quote_literal - Format a string as a SQL literal, append to buf
6057  */
6058 static void
6059 simple_quote_literal(StringInfo buf, const char *val)
6060 {
6061         const char *valptr;
6062
6063         /*
6064          * We form the string literal according to the prevailing setting of
6065          * standard_conforming_strings; we never use E''. User is responsible for
6066          * making sure result is used correctly.
6067          */
6068         appendStringInfoChar(buf, '\'');
6069         for (valptr = val; *valptr; valptr++)
6070         {
6071                 char            ch = *valptr;
6072
6073                 if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
6074                         appendStringInfoChar(buf, ch);
6075                 appendStringInfoChar(buf, ch);
6076         }
6077         appendStringInfoChar(buf, '\'');
6078 }
6079
6080
6081 /* ----------
6082  * get_sublink_expr                     - Parse back a sublink
6083  * ----------
6084  */
6085 static void
6086 get_sublink_expr(SubLink *sublink, deparse_context *context)
6087 {
6088         StringInfo      buf = context->buf;
6089         Query      *query = (Query *) (sublink->subselect);
6090         char       *opname = NULL;
6091         bool            need_paren;
6092
6093         if (sublink->subLinkType == ARRAY_SUBLINK)
6094                 appendStringInfo(buf, "ARRAY(");
6095         else
6096                 appendStringInfoChar(buf, '(');
6097
6098         /*
6099          * Note that we print the name of only the first operator, when there are
6100          * multiple combining operators.  This is an approximation that could go
6101          * wrong in various scenarios (operators in different schemas, renamed
6102          * operators, etc) but there is not a whole lot we can do about it, since
6103          * the syntax allows only one operator to be shown.
6104          */
6105         if (sublink->testexpr)
6106         {
6107                 if (IsA(sublink->testexpr, OpExpr))
6108                 {
6109                         /* single combining operator */
6110                         OpExpr     *opexpr = (OpExpr *) sublink->testexpr;
6111
6112                         get_rule_expr(linitial(opexpr->args), context, true);
6113                         opname = generate_operator_name(opexpr->opno,
6114                                                                                         exprType(linitial(opexpr->args)),
6115                                                                                         exprType(lsecond(opexpr->args)));
6116                 }
6117                 else if (IsA(sublink->testexpr, BoolExpr))
6118                 {
6119                         /* multiple combining operators, = or <> cases */
6120                         char       *sep;
6121                         ListCell   *l;
6122
6123                         appendStringInfoChar(buf, '(');
6124                         sep = "";
6125                         foreach(l, ((BoolExpr *) sublink->testexpr)->args)
6126                         {
6127                                 OpExpr     *opexpr = (OpExpr *) lfirst(l);
6128
6129                                 Assert(IsA(opexpr, OpExpr));
6130                                 appendStringInfoString(buf, sep);
6131                                 get_rule_expr(linitial(opexpr->args), context, true);
6132                                 if (!opname)
6133                                         opname = generate_operator_name(opexpr->opno,
6134                                                                                         exprType(linitial(opexpr->args)),
6135                                                                                         exprType(lsecond(opexpr->args)));
6136                                 sep = ", ";
6137                         }
6138                         appendStringInfoChar(buf, ')');
6139                 }
6140                 else if (IsA(sublink->testexpr, RowCompareExpr))
6141                 {
6142                         /* multiple combining operators, < <= > >= cases */
6143                         RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
6144
6145                         appendStringInfoChar(buf, '(');
6146                         get_rule_expr((Node *) rcexpr->largs, context, true);
6147                         opname = generate_operator_name(linitial_oid(rcexpr->opnos),
6148                                                                                         exprType(linitial(rcexpr->largs)),
6149                                                                                   exprType(linitial(rcexpr->rargs)));
6150                         appendStringInfoChar(buf, ')');
6151                 }
6152                 else
6153                         elog(ERROR, "unrecognized testexpr type: %d",
6154                                  (int) nodeTag(sublink->testexpr));
6155         }
6156
6157         need_paren = true;
6158
6159         switch (sublink->subLinkType)
6160         {
6161                 case EXISTS_SUBLINK:
6162                         appendStringInfo(buf, "EXISTS ");
6163                         break;
6164
6165                 case ANY_SUBLINK:
6166                         if (strcmp(opname, "=") == 0)           /* Represent = ANY as IN */
6167                                 appendStringInfo(buf, " IN ");
6168                         else
6169                                 appendStringInfo(buf, " %s ANY ", opname);
6170                         break;
6171
6172                 case ALL_SUBLINK:
6173                         appendStringInfo(buf, " %s ALL ", opname);
6174                         break;
6175
6176                 case ROWCOMPARE_SUBLINK:
6177                         appendStringInfo(buf, " %s ", opname);
6178                         break;
6179
6180                 case EXPR_SUBLINK:
6181                 case ARRAY_SUBLINK:
6182                         need_paren = false;
6183                         break;
6184
6185                 case CTE_SUBLINK:               /* shouldn't occur in a SubLink */
6186                 default:
6187                         elog(ERROR, "unrecognized sublink type: %d",
6188                                  (int) sublink->subLinkType);
6189                         break;
6190         }
6191
6192         if (need_paren)
6193                 appendStringInfoChar(buf, '(');
6194
6195         get_query_def(query, buf, context->namespaces, NULL,
6196                                   context->prettyFlags, context->indentLevel);
6197
6198         if (need_paren)
6199                 appendStringInfo(buf, "))");
6200         else
6201                 appendStringInfoChar(buf, ')');
6202 }
6203
6204
6205 /* ----------
6206  * get_from_clause                      - Parse back a FROM clause
6207  *
6208  * "prefix" is the keyword that denotes the start of the list of FROM
6209  * elements. It is FROM when used to parse back SELECT and UPDATE, but
6210  * is USING when parsing back DELETE.
6211  * ----------
6212  */
6213 static void
6214 get_from_clause(Query *query, const char *prefix, deparse_context *context)
6215 {
6216         StringInfo      buf = context->buf;
6217         bool            first = true;
6218         ListCell   *l;
6219
6220         /*
6221          * We use the query's jointree as a guide to what to print.  However, we
6222          * must ignore auto-added RTEs that are marked not inFromCl. (These can
6223          * only appear at the top level of the jointree, so it's sufficient to
6224          * check here.)  This check also ensures we ignore the rule pseudo-RTEs
6225          * for NEW and OLD.
6226          */
6227         foreach(l, query->jointree->fromlist)
6228         {
6229                 Node       *jtnode = (Node *) lfirst(l);
6230
6231                 if (IsA(jtnode, RangeTblRef))
6232                 {
6233                         int                     varno = ((RangeTblRef *) jtnode)->rtindex;
6234                         RangeTblEntry *rte = rt_fetch(varno, query->rtable);
6235
6236                         if (!rte->inFromCl)
6237                                 continue;
6238                 }
6239
6240                 if (first)
6241                 {
6242                         appendContextKeyword(context, prefix,
6243                                                                  -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
6244                         first = false;
6245                 }
6246                 else
6247                         appendStringInfoString(buf, ", ");
6248
6249                 get_from_clause_item(jtnode, query, context);
6250         }
6251 }
6252
6253 static void
6254 get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
6255 {
6256         StringInfo      buf = context->buf;
6257
6258         if (IsA(jtnode, RangeTblRef))
6259         {
6260                 int                     varno = ((RangeTblRef *) jtnode)->rtindex;
6261                 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
6262                 bool            gavealias = false;
6263
6264                 switch (rte->rtekind)
6265                 {
6266                         case RTE_RELATION:
6267                                 /* Normal relation RTE */
6268                                 appendStringInfo(buf, "%s%s",
6269                                                                  only_marker(rte),
6270                                                                  generate_relation_name(rte->relid,
6271                                                                                                                 context->namespaces));
6272                                 break;
6273                         case RTE_SUBQUERY:
6274                                 /* Subquery RTE */
6275                                 appendStringInfoChar(buf, '(');
6276                                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
6277                                                           context->prettyFlags, context->indentLevel);
6278                                 appendStringInfoChar(buf, ')');
6279                                 break;
6280                         case RTE_FUNCTION:
6281                                 /* Function RTE */
6282                                 get_rule_expr(rte->funcexpr, context, true);
6283                                 break;
6284                         case RTE_VALUES:
6285                                 /* Values list RTE */
6286                                 get_values_def(rte->values_lists, context);
6287                                 break;
6288                         case RTE_CTE:
6289                                 appendStringInfoString(buf, quote_identifier(rte->ctename));
6290                                 break;
6291                         default:
6292                                 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
6293                                 break;
6294                 }
6295
6296                 if (rte->alias != NULL)
6297                 {
6298                         appendStringInfo(buf, " %s",
6299                                                          quote_identifier(rte->alias->aliasname));
6300                         gavealias = true;
6301                 }
6302                 else if (rte->rtekind == RTE_RELATION &&
6303                                  strcmp(rte->eref->aliasname, get_rel_name(rte->relid)) != 0)
6304                 {
6305                         /*
6306                          * Apparently the rel has been renamed since the rule was made.
6307                          * Emit a fake alias clause so that variable references will still
6308                          * work.  This is not a 100% solution but should work in most
6309                          * reasonable situations.
6310                          */
6311                         appendStringInfo(buf, " %s",
6312                                                          quote_identifier(rte->eref->aliasname));
6313                         gavealias = true;
6314                 }
6315                 else if (rte->rtekind == RTE_FUNCTION)
6316                 {
6317                         /*
6318                          * For a function RTE, always give an alias. This covers possible
6319                          * renaming of the function and/or instability of the
6320                          * FigureColname rules for things that aren't simple functions.
6321                          */
6322                         appendStringInfo(buf, " %s",
6323                                                          quote_identifier(rte->eref->aliasname));
6324                         gavealias = true;
6325                 }
6326
6327                 if (rte->rtekind == RTE_FUNCTION)
6328                 {
6329                         if (rte->funccoltypes != NIL)
6330                         {
6331                                 /* Function returning RECORD, reconstruct the columndefs */
6332                                 if (!gavealias)
6333                                         appendStringInfo(buf, " AS ");
6334                                 get_from_clause_coldeflist(rte->eref->colnames,
6335                                                                                    rte->funccoltypes,
6336                                                                                    rte->funccoltypmods,
6337                                                                                    context);
6338                         }
6339                         else
6340                         {
6341                                 /*
6342                                  * For a function RTE, always emit a complete column alias
6343                                  * list; this is to protect against possible instability of
6344                                  * the default column names (eg, from altering parameter
6345                                  * names).
6346                                  */
6347                                 get_from_clause_alias(rte->eref, rte, context);
6348                         }
6349                 }
6350                 else
6351                 {
6352                         /*
6353                          * For non-function RTEs, just report whatever the user originally
6354                          * gave as column aliases.
6355                          */
6356                         get_from_clause_alias(rte->alias, rte, context);
6357                 }
6358         }
6359         else if (IsA(jtnode, JoinExpr))
6360         {
6361                 JoinExpr   *j = (JoinExpr *) jtnode;
6362                 bool            need_paren_on_right;
6363
6364                 need_paren_on_right = PRETTY_PAREN(context) &&
6365                         !IsA(j->rarg, RangeTblRef) &&
6366                         !(IsA(j->rarg, JoinExpr) &&((JoinExpr *) j->rarg)->alias != NULL);
6367
6368                 if (!PRETTY_PAREN(context) || j->alias != NULL)
6369                         appendStringInfoChar(buf, '(');
6370
6371                 get_from_clause_item(j->larg, query, context);
6372
6373                 if (j->isNatural)
6374                 {
6375                         if (!PRETTY_INDENT(context))
6376                                 appendStringInfoChar(buf, ' ');
6377                         switch (j->jointype)
6378                         {
6379                                 case JOIN_INNER:
6380                                         appendContextKeyword(context, "NATURAL JOIN ",
6381                                                                                  -PRETTYINDENT_JOIN,
6382                                                                                  PRETTYINDENT_JOIN, 0);
6383                                         break;
6384                                 case JOIN_LEFT:
6385                                         appendContextKeyword(context, "NATURAL LEFT JOIN ",
6386                                                                                  -PRETTYINDENT_JOIN,
6387                                                                                  PRETTYINDENT_JOIN, 0);
6388                                         break;
6389                                 case JOIN_FULL:
6390                                         appendContextKeyword(context, "NATURAL FULL JOIN ",
6391                                                                                  -PRETTYINDENT_JOIN,
6392                                                                                  PRETTYINDENT_JOIN, 0);
6393                                         break;
6394                                 case JOIN_RIGHT:
6395                                         appendContextKeyword(context, "NATURAL RIGHT JOIN ",
6396                                                                                  -PRETTYINDENT_JOIN,
6397                                                                                  PRETTYINDENT_JOIN, 0);
6398                                         break;
6399                                 default:
6400                                         elog(ERROR, "unrecognized join type: %d",
6401                                                  (int) j->jointype);
6402                         }
6403                 }
6404                 else
6405                 {
6406                         switch (j->jointype)
6407                         {
6408                                 case JOIN_INNER:
6409                                         if (j->quals)
6410                                                 appendContextKeyword(context, " JOIN ",
6411                                                                                          -PRETTYINDENT_JOIN,
6412                                                                                          PRETTYINDENT_JOIN, 2);
6413                                         else
6414                                                 appendContextKeyword(context, " CROSS JOIN ",
6415                                                                                          -PRETTYINDENT_JOIN,
6416                                                                                          PRETTYINDENT_JOIN, 1);
6417                                         break;
6418                                 case JOIN_LEFT:
6419                                         appendContextKeyword(context, " LEFT JOIN ",
6420                                                                                  -PRETTYINDENT_JOIN,
6421                                                                                  PRETTYINDENT_JOIN, 2);
6422                                         break;
6423                                 case JOIN_FULL:
6424                                         appendContextKeyword(context, " FULL JOIN ",
6425                                                                                  -PRETTYINDENT_JOIN,
6426                                                                                  PRETTYINDENT_JOIN, 2);
6427                                         break;
6428                                 case JOIN_RIGHT:
6429                                         appendContextKeyword(context, " RIGHT JOIN ",
6430                                                                                  -PRETTYINDENT_JOIN,
6431                                                                                  PRETTYINDENT_JOIN, 2);
6432                                         break;
6433                                 default:
6434                                         elog(ERROR, "unrecognized join type: %d",
6435                                                  (int) j->jointype);
6436                         }
6437                 }
6438
6439                 if (need_paren_on_right)
6440                         appendStringInfoChar(buf, '(');
6441                 get_from_clause_item(j->rarg, query, context);
6442                 if (need_paren_on_right)
6443                         appendStringInfoChar(buf, ')');
6444
6445                 context->indentLevel -= PRETTYINDENT_JOIN_ON;
6446
6447                 if (!j->isNatural)
6448                 {
6449                         if (j->usingClause)
6450                         {
6451                                 ListCell   *col;
6452
6453                                 appendStringInfo(buf, " USING (");
6454                                 foreach(col, j->usingClause)
6455                                 {
6456                                         if (col != list_head(j->usingClause))
6457                                                 appendStringInfo(buf, ", ");
6458                                         appendStringInfoString(buf,
6459                                                                           quote_identifier(strVal(lfirst(col))));
6460                                 }
6461                                 appendStringInfoChar(buf, ')');
6462                         }
6463                         else if (j->quals)
6464                         {
6465                                 appendStringInfo(buf, " ON ");
6466                                 if (!PRETTY_PAREN(context))
6467                                         appendStringInfoChar(buf, '(');
6468                                 get_rule_expr(j->quals, context, false);
6469                                 if (!PRETTY_PAREN(context))
6470                                         appendStringInfoChar(buf, ')');
6471                         }
6472                 }
6473                 if (!PRETTY_PAREN(context) || j->alias != NULL)
6474                         appendStringInfoChar(buf, ')');
6475
6476                 /* Yes, it's correct to put alias after the right paren ... */
6477                 if (j->alias != NULL)
6478                 {
6479                         appendStringInfo(buf, " %s",
6480                                                          quote_identifier(j->alias->aliasname));
6481                         get_from_clause_alias(j->alias,
6482                                                                   rt_fetch(j->rtindex, query->rtable),
6483                                                                   context);
6484                 }
6485         }
6486         else
6487                 elog(ERROR, "unrecognized node type: %d",
6488                          (int) nodeTag(jtnode));
6489 }
6490
6491 /*
6492  * get_from_clause_alias - reproduce column alias list
6493  *
6494  * This is tricky because we must ignore dropped columns.
6495  */
6496 static void
6497 get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
6498                                           deparse_context *context)
6499 {
6500         StringInfo      buf = context->buf;
6501         ListCell   *col;
6502         AttrNumber      attnum;
6503         bool            first = true;
6504
6505         if (alias == NULL || alias->colnames == NIL)
6506                 return;                                 /* definitely nothing to do */
6507
6508         attnum = 0;
6509         foreach(col, alias->colnames)
6510         {
6511                 attnum++;
6512                 if (get_rte_attribute_is_dropped(rte, attnum))
6513                         continue;
6514                 if (first)
6515                 {
6516                         appendStringInfoChar(buf, '(');
6517                         first = false;
6518                 }
6519                 else
6520                         appendStringInfo(buf, ", ");
6521                 appendStringInfoString(buf,
6522                                                            quote_identifier(strVal(lfirst(col))));
6523         }
6524         if (!first)
6525                 appendStringInfoChar(buf, ')');
6526 }
6527
6528 /*
6529  * get_from_clause_coldeflist - reproduce FROM clause coldeflist
6530  *
6531  * The coldeflist is appended immediately (no space) to buf.  Caller is
6532  * responsible for ensuring that an alias or AS is present before it.
6533  */
6534 static void
6535 get_from_clause_coldeflist(List *names, List *types, List *typmods,
6536                                                    deparse_context *context)
6537 {
6538         StringInfo      buf = context->buf;
6539         ListCell   *l1;
6540         ListCell   *l2;
6541         ListCell   *l3;
6542         int                     i = 0;
6543
6544         appendStringInfoChar(buf, '(');
6545
6546         l2 = list_head(types);
6547         l3 = list_head(typmods);
6548         foreach(l1, names)
6549         {
6550                 char       *attname = strVal(lfirst(l1));
6551                 Oid                     atttypid;
6552                 int32           atttypmod;
6553
6554                 atttypid = lfirst_oid(l2);
6555                 l2 = lnext(l2);
6556                 atttypmod = lfirst_int(l3);
6557                 l3 = lnext(l3);
6558
6559                 if (i > 0)
6560                         appendStringInfo(buf, ", ");
6561                 appendStringInfo(buf, "%s %s",
6562                                                  quote_identifier(attname),
6563                                                  format_type_with_typemod(atttypid, atttypmod));
6564                 i++;
6565         }
6566
6567         appendStringInfoChar(buf, ')');
6568 }
6569
6570 /*
6571  * get_opclass_name                     - fetch name of an index operator class
6572  *
6573  * The opclass name is appended (after a space) to buf.
6574  *
6575  * Output is suppressed if the opclass is the default for the given
6576  * actual_datatype.  (If you don't want this behavior, just pass
6577  * InvalidOid for actual_datatype.)
6578  */
6579 static void
6580 get_opclass_name(Oid opclass, Oid actual_datatype,
6581                                  StringInfo buf)
6582 {
6583         HeapTuple       ht_opc;
6584         Form_pg_opclass opcrec;
6585         char       *opcname;
6586         char       *nspname;
6587
6588         ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
6589         if (!HeapTupleIsValid(ht_opc))
6590                 elog(ERROR, "cache lookup failed for opclass %u", opclass);
6591         opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
6592
6593         if (!OidIsValid(actual_datatype) ||
6594                 GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
6595         {
6596                 /* Okay, we need the opclass name.      Do we need to qualify it? */
6597                 opcname = NameStr(opcrec->opcname);
6598                 if (OpclassIsVisible(opclass))
6599                         appendStringInfo(buf, " %s", quote_identifier(opcname));
6600                 else
6601                 {
6602                         nspname = get_namespace_name(opcrec->opcnamespace);
6603                         appendStringInfo(buf, " %s.%s",
6604                                                          quote_identifier(nspname),
6605                                                          quote_identifier(opcname));
6606                 }
6607         }
6608         ReleaseSysCache(ht_opc);
6609 }
6610
6611 /*
6612  * processIndirection - take care of array and subfield assignment
6613  *
6614  * We strip any top-level FieldStore or assignment ArrayRef nodes that
6615  * appear in the input, and return the subexpression that's to be assigned.
6616  * If printit is true, we also print out the appropriate decoration for the
6617  * base column name (that the caller just printed).
6618  */
6619 static Node *
6620 processIndirection(Node *node, deparse_context *context, bool printit)
6621 {
6622         StringInfo      buf = context->buf;
6623
6624         for (;;)
6625         {
6626                 if (node == NULL)
6627                         break;
6628                 if (IsA(node, FieldStore))
6629                 {
6630                         FieldStore *fstore = (FieldStore *) node;
6631                         Oid                     typrelid;
6632                         char       *fieldname;
6633
6634                         /* lookup tuple type */
6635                         typrelid = get_typ_typrelid(fstore->resulttype);
6636                         if (!OidIsValid(typrelid))
6637                                 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
6638                                          format_type_be(fstore->resulttype));
6639
6640                         /*
6641                          * Print the field name.  There should only be one target field in
6642                          * stored rules.  There could be more than that in executable
6643                          * target lists, but this function cannot be used for that case.
6644                          */
6645                         Assert(list_length(fstore->fieldnums) == 1);
6646                         fieldname = get_relid_attribute_name(typrelid,
6647                                                                                         linitial_int(fstore->fieldnums));
6648                         if (printit)
6649                                 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
6650
6651                         /*
6652                          * We ignore arg since it should be an uninteresting reference to
6653                          * the target column or subcolumn.
6654                          */
6655                         node = (Node *) linitial(fstore->newvals);
6656                 }
6657                 else if (IsA(node, ArrayRef))
6658                 {
6659                         ArrayRef   *aref = (ArrayRef *) node;
6660
6661                         if (aref->refassgnexpr == NULL)
6662                                 break;
6663                         if (printit)
6664                                 printSubscripts(aref, context);
6665
6666                         /*
6667                          * We ignore refexpr since it should be an uninteresting reference
6668                          * to the target column or subcolumn.
6669                          */
6670                         node = (Node *) aref->refassgnexpr;
6671                 }
6672                 else
6673                         break;
6674         }
6675
6676         return node;
6677 }
6678
6679 static void
6680 printSubscripts(ArrayRef *aref, deparse_context *context)
6681 {
6682         StringInfo      buf = context->buf;
6683         ListCell   *lowlist_item;
6684         ListCell   *uplist_item;
6685
6686         lowlist_item = list_head(aref->reflowerindexpr);        /* could be NULL */
6687         foreach(uplist_item, aref->refupperindexpr)
6688         {
6689                 appendStringInfoChar(buf, '[');
6690                 if (lowlist_item)
6691                 {
6692                         get_rule_expr((Node *) lfirst(lowlist_item), context, false);
6693                         appendStringInfoChar(buf, ':');
6694                         lowlist_item = lnext(lowlist_item);
6695                 }
6696                 get_rule_expr((Node *) lfirst(uplist_item), context, false);
6697                 appendStringInfoChar(buf, ']');
6698         }
6699 }
6700
6701 /*
6702  * quote_identifier                     - Quote an identifier only if needed
6703  *
6704  * When quotes are needed, we palloc the required space; slightly
6705  * space-wasteful but well worth it for notational simplicity.
6706  */
6707 const char *
6708 quote_identifier(const char *ident)
6709 {
6710         /*
6711          * Can avoid quoting if ident starts with a lowercase letter or underscore
6712          * and contains only lowercase letters, digits, and underscores, *and* is
6713          * not any SQL keyword.  Otherwise, supply quotes.
6714          */
6715         int                     nquotes = 0;
6716         bool            safe;
6717         const char *ptr;
6718         char       *result;
6719         char       *optr;
6720
6721         /*
6722          * would like to use <ctype.h> macros here, but they might yield unwanted
6723          * locale-specific results...
6724          */
6725         safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
6726
6727         for (ptr = ident; *ptr; ptr++)
6728         {
6729                 char            ch = *ptr;
6730
6731                 if ((ch >= 'a' && ch <= 'z') ||
6732                         (ch >= '0' && ch <= '9') ||
6733                         (ch == '_'))
6734                 {
6735                         /* okay */
6736                 }
6737                 else
6738                 {
6739                         safe = false;
6740                         if (ch == '"')
6741                                 nquotes++;
6742                 }
6743         }
6744
6745         if (quote_all_identifiers)
6746                 safe = false;
6747
6748         if (safe)
6749         {
6750                 /*
6751                  * Check for keyword.  We quote keywords except for unreserved ones.
6752                  * (In some cases we could avoid quoting a col_name or type_func_name
6753                  * keyword, but it seems much harder than it's worth to tell that.)
6754                  *
6755                  * Note: ScanKeywordLookup() does case-insensitive comparison, but
6756                  * that's fine, since we already know we have all-lower-case.
6757                  */
6758                 const ScanKeyword *keyword = ScanKeywordLookup(ident,
6759                                                                                                            ScanKeywords,
6760                                                                                                            NumScanKeywords);
6761
6762                 if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
6763                         safe = false;
6764         }
6765
6766         if (safe)
6767                 return ident;                   /* no change needed */
6768
6769         result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
6770
6771         optr = result;
6772         *optr++ = '"';
6773         for (ptr = ident; *ptr; ptr++)
6774         {
6775                 char            ch = *ptr;
6776
6777                 if (ch == '"')
6778                         *optr++ = '"';
6779                 *optr++ = ch;
6780         }
6781         *optr++ = '"';
6782         *optr = '\0';
6783
6784         return result;
6785 }
6786
6787 /*
6788  * quote_qualified_identifier   - Quote a possibly-qualified identifier
6789  *
6790  * Return a name of the form qualifier.ident, or just ident if qualifier
6791  * is NULL, quoting each component if necessary.  The result is palloc'd.
6792  */
6793 char *
6794 quote_qualified_identifier(const char *qualifier,
6795                                                    const char *ident)
6796 {
6797         StringInfoData buf;
6798
6799         initStringInfo(&buf);
6800         if (qualifier)
6801                 appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
6802         appendStringInfoString(&buf, quote_identifier(ident));
6803         return buf.data;
6804 }
6805
6806 /*
6807  * generate_relation_name
6808  *              Compute the name to display for a relation specified by OID
6809  *
6810  * The result includes all necessary quoting and schema-prefixing.
6811  *
6812  * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
6813  * We will forcibly qualify the relation name if it equals any CTE name
6814  * visible in the namespace list.
6815  */
6816 static char *
6817 generate_relation_name(Oid relid, List *namespaces)
6818 {
6819         HeapTuple       tp;
6820         Form_pg_class reltup;
6821         bool            need_qual;
6822         ListCell   *nslist;
6823         char       *relname;
6824         char       *nspname;
6825         char       *result;
6826
6827         tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
6828         if (!HeapTupleIsValid(tp))
6829                 elog(ERROR, "cache lookup failed for relation %u", relid);
6830         reltup = (Form_pg_class) GETSTRUCT(tp);
6831         relname = NameStr(reltup->relname);
6832
6833         /* Check for conflicting CTE name */
6834         need_qual = false;
6835         foreach(nslist, namespaces)
6836         {
6837                 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
6838                 ListCell   *ctlist;
6839
6840                 foreach(ctlist, dpns->ctes)
6841                 {
6842                         CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
6843
6844                         if (strcmp(cte->ctename, relname) == 0)
6845                         {
6846                                 need_qual = true;
6847                                 break;
6848                         }
6849                 }
6850                 if (need_qual)
6851                         break;
6852         }
6853
6854         /* Otherwise, qualify the name if not visible in search path */
6855         if (!need_qual)
6856                 need_qual = !RelationIsVisible(relid);
6857
6858         if (need_qual)
6859                 nspname = get_namespace_name(reltup->relnamespace);
6860         else
6861                 nspname = NULL;
6862
6863         result = quote_qualified_identifier(nspname, relname);
6864
6865         ReleaseSysCache(tp);
6866
6867         return result;
6868 }
6869
6870 /*
6871  * generate_function_name
6872  *              Compute the name to display for a function specified by OID,
6873  *              given that it is being called with the specified actual arg names and
6874  *              types.  (Those matter because of ambiguous-function resolution rules.)
6875  *
6876  * The result includes all necessary quoting and schema-prefixing.      We can
6877  * also pass back an indication of whether the function is variadic.
6878  */
6879 static char *
6880 generate_function_name(Oid funcid, int nargs, List *argnames,
6881                                            Oid *argtypes, bool *is_variadic)
6882 {
6883         HeapTuple       proctup;
6884         Form_pg_proc procform;
6885         char       *proname;
6886         char       *nspname;
6887         char       *result;
6888         FuncDetailCode p_result;
6889         Oid                     p_funcid;
6890         Oid                     p_rettype;
6891         bool            p_retset;
6892         int                     p_nvargs;
6893         Oid                *p_true_typeids;
6894
6895         proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
6896         if (!HeapTupleIsValid(proctup))
6897                 elog(ERROR, "cache lookup failed for function %u", funcid);
6898         procform = (Form_pg_proc) GETSTRUCT(proctup);
6899         proname = NameStr(procform->proname);
6900
6901         /*
6902          * The idea here is to schema-qualify only if the parser would fail to
6903          * resolve the correct function given the unqualified func name with the
6904          * specified argtypes.  If the function is variadic, we should presume
6905          * that VARIADIC will be included in the call.
6906          */
6907         p_result = func_get_detail(list_make1(makeString(proname)),
6908                                                            NIL, argnames, nargs, argtypes,
6909                                                            !OidIsValid(procform->provariadic), true,
6910                                                            &p_funcid, &p_rettype,
6911                                                            &p_retset, &p_nvargs, &p_true_typeids, NULL);
6912         if ((p_result == FUNCDETAIL_NORMAL ||
6913                  p_result == FUNCDETAIL_AGGREGATE ||
6914                  p_result == FUNCDETAIL_WINDOWFUNC) &&
6915                 p_funcid == funcid)
6916                 nspname = NULL;
6917         else
6918                 nspname = get_namespace_name(procform->pronamespace);
6919
6920         result = quote_qualified_identifier(nspname, proname);
6921
6922         /* Check variadic-ness if caller cares */
6923         if (is_variadic)
6924         {
6925                 /* "any" variadics are not treated as variadics for listing */
6926                 if (OidIsValid(procform->provariadic) &&
6927                         procform->provariadic != ANYOID)
6928                         *is_variadic = true;
6929                 else
6930                         *is_variadic = false;
6931         }
6932
6933         ReleaseSysCache(proctup);
6934
6935         return result;
6936 }
6937
6938 /*
6939  * generate_operator_name
6940  *              Compute the name to display for an operator specified by OID,
6941  *              given that it is being called with the specified actual arg types.
6942  *              (Arg types matter because of ambiguous-operator resolution rules.
6943  *              Pass InvalidOid for unused arg of a unary operator.)
6944  *
6945  * The result includes all necessary quoting and schema-prefixing,
6946  * plus the OPERATOR() decoration needed to use a qualified operator name
6947  * in an expression.
6948  */
6949 static char *
6950 generate_operator_name(Oid operid, Oid arg1, Oid arg2)
6951 {
6952         StringInfoData buf;
6953         HeapTuple       opertup;
6954         Form_pg_operator operform;
6955         char       *oprname;
6956         char       *nspname;
6957         Operator        p_result;
6958
6959         initStringInfo(&buf);
6960
6961         opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
6962         if (!HeapTupleIsValid(opertup))
6963                 elog(ERROR, "cache lookup failed for operator %u", operid);
6964         operform = (Form_pg_operator) GETSTRUCT(opertup);
6965         oprname = NameStr(operform->oprname);
6966
6967         /*
6968          * The idea here is to schema-qualify only if the parser would fail to
6969          * resolve the correct operator given the unqualified op name with the
6970          * specified argtypes.
6971          */
6972         switch (operform->oprkind)
6973         {
6974                 case 'b':
6975                         p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
6976                                                         true, -1);
6977                         break;
6978                 case 'l':
6979                         p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
6980                                                                  true, -1);
6981                         break;
6982                 case 'r':
6983                         p_result = right_oper(NULL, list_make1(makeString(oprname)), arg1,
6984                                                                   true, -1);
6985                         break;
6986                 default:
6987                         elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
6988                         p_result = NULL;        /* keep compiler quiet */
6989                         break;
6990         }
6991
6992         if (p_result != NULL && oprid(p_result) == operid)
6993                 nspname = NULL;
6994         else
6995         {
6996                 nspname = get_namespace_name(operform->oprnamespace);
6997                 appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
6998         }
6999
7000         appendStringInfoString(&buf, oprname);
7001
7002         if (nspname)
7003                 appendStringInfoChar(&buf, ')');
7004
7005         if (p_result != NULL)
7006                 ReleaseSysCache(p_result);
7007
7008         ReleaseSysCache(opertup);
7009
7010         return buf.data;
7011 }
7012
7013 /*
7014  * Given a C string, produce a TEXT datum.
7015  *
7016  * We assume that the input was palloc'd and may be freed.
7017  */
7018 static text *
7019 string_to_text(char *str)
7020 {
7021         text       *result;
7022
7023         result = cstring_to_text(str);
7024         pfree(str);
7025         return result;
7026 }
7027
7028 /*
7029  * Generate a C string representing a relation's reloptions, or NULL if none.
7030  */
7031 static char *
7032 flatten_reloptions(Oid relid)
7033 {
7034         char       *result = NULL;
7035         HeapTuple       tuple;
7036         Datum           reloptions;
7037         bool            isnull;
7038
7039         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
7040         if (!HeapTupleIsValid(tuple))
7041                 elog(ERROR, "cache lookup failed for relation %u", relid);
7042
7043         reloptions = SysCacheGetAttr(RELOID, tuple,
7044                                                                  Anum_pg_class_reloptions, &isnull);
7045         if (!isnull)
7046         {
7047                 Datum           sep,
7048                                         txt;
7049
7050                 /*
7051                  * We want to use array_to_text(reloptions, ', ') --- but
7052                  * DirectFunctionCall2(array_to_text) does not work, because
7053                  * array_to_text() relies on flinfo to be valid.  So use
7054                  * OidFunctionCall2.
7055                  */
7056                 sep = CStringGetTextDatum(", ");
7057                 txt = OidFunctionCall2(F_ARRAY_TO_TEXT, reloptions, sep);
7058                 result = TextDatumGetCString(txt);
7059         }
7060
7061         ReleaseSysCache(tuple);
7062
7063         return result;
7064 }