]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/ruleutils.c
Allow WITH clauses to be attached to INSERT, UPDATE, DELETE statements.
[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         /* Insert the WITH clause if given */
3356         get_with_clause(query, context);
3357
3358         /*
3359          * If it's an INSERT ... SELECT or VALUES (...), (...), ... there will be
3360          * a single RTE for the SELECT or VALUES.
3361          */
3362         foreach(l, query->rtable)
3363         {
3364                 rte = (RangeTblEntry *) lfirst(l);
3365
3366                 if (rte->rtekind == RTE_SUBQUERY)
3367                 {
3368                         if (select_rte)
3369                                 elog(ERROR, "too many subquery RTEs in INSERT");
3370                         select_rte = rte;
3371                 }
3372
3373                 if (rte->rtekind == RTE_VALUES)
3374                 {
3375                         if (values_rte)
3376                                 elog(ERROR, "too many values RTEs in INSERT");
3377                         values_rte = rte;
3378                 }
3379         }
3380         if (select_rte && values_rte)
3381                 elog(ERROR, "both subquery and values RTEs in INSERT");
3382
3383         /*
3384          * Start the query with INSERT INTO relname
3385          */
3386         rte = rt_fetch(query->resultRelation, query->rtable);
3387         Assert(rte->rtekind == RTE_RELATION);
3388
3389         if (PRETTY_INDENT(context))
3390         {
3391                 context->indentLevel += PRETTYINDENT_STD;
3392                 appendStringInfoChar(buf, ' ');
3393         }
3394         appendStringInfo(buf, "INSERT INTO %s (",
3395                                          generate_relation_name(rte->relid, NIL));
3396
3397         /*
3398          * Add the insert-column-names list.  To handle indirection properly, we
3399          * need to look for indirection nodes in the top targetlist (if it's
3400          * INSERT ... SELECT or INSERT ... single VALUES), or in the first
3401          * expression list of the VALUES RTE (if it's INSERT ... multi VALUES). We
3402          * assume that all the expression lists will have similar indirection in
3403          * the latter case.
3404          */
3405         if (values_rte)
3406                 values_cell = list_head((List *) linitial(values_rte->values_lists));
3407         else
3408                 values_cell = NULL;
3409         strippedexprs = NIL;
3410         sep = "";
3411         foreach(l, query->targetList)
3412         {
3413                 TargetEntry *tle = (TargetEntry *) lfirst(l);
3414
3415                 if (tle->resjunk)
3416                         continue;                       /* ignore junk entries */
3417
3418                 appendStringInfoString(buf, sep);
3419                 sep = ", ";
3420
3421                 /*
3422                  * Put out name of target column; look in the catalogs, not at
3423                  * tle->resname, since resname will fail to track RENAME.
3424                  */
3425                 appendStringInfoString(buf,
3426                                                 quote_identifier(get_relid_attribute_name(rte->relid,
3427                                                                                                                            tle->resno)));
3428
3429                 /*
3430                  * Print any indirection needed (subfields or subscripts), and strip
3431                  * off the top-level nodes representing the indirection assignments.
3432                  */
3433                 if (values_cell)
3434                 {
3435                         /* we discard the stripped expression in this case */
3436                         processIndirection((Node *) lfirst(values_cell), context, true);
3437                         values_cell = lnext(values_cell);
3438                 }
3439                 else
3440                 {
3441                         /* we keep a list of the stripped expressions in this case */
3442                         strippedexprs = lappend(strippedexprs,
3443                                                                         processIndirection((Node *) tle->expr,
3444                                                                                                            context, true));
3445                 }
3446         }
3447         appendStringInfo(buf, ") ");
3448
3449         if (select_rte)
3450         {
3451                 /* Add the SELECT */
3452                 get_query_def(select_rte->subquery, buf, NIL, NULL,
3453                                           context->prettyFlags, context->indentLevel);
3454         }
3455         else if (values_rte)
3456         {
3457                 /* Add the multi-VALUES expression lists */
3458                 get_values_def(values_rte->values_lists, context);
3459         }
3460         else
3461         {
3462                 /* Add the single-VALUES expression list */
3463                 appendContextKeyword(context, "VALUES (",
3464                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
3465                 get_rule_expr((Node *) strippedexprs, context, false);
3466                 appendStringInfoChar(buf, ')');
3467         }
3468
3469         /* Add RETURNING if present */
3470         if (query->returningList)
3471         {
3472                 appendContextKeyword(context, " RETURNING",
3473                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3474                 get_target_list(query->returningList, context, NULL);
3475         }
3476 }
3477
3478
3479 /* ----------
3480  * get_update_query_def                 - Parse back an UPDATE parsetree
3481  * ----------
3482  */
3483 static void
3484 get_update_query_def(Query *query, deparse_context *context)
3485 {
3486         StringInfo      buf = context->buf;
3487         char       *sep;
3488         RangeTblEntry *rte;
3489         ListCell   *l;
3490
3491         /* Insert the WITH clause if given */
3492         get_with_clause(query, context);
3493
3494         /*
3495          * Start the query with UPDATE relname SET
3496          */
3497         rte = rt_fetch(query->resultRelation, query->rtable);
3498         Assert(rte->rtekind == RTE_RELATION);
3499         if (PRETTY_INDENT(context))
3500         {
3501                 appendStringInfoChar(buf, ' ');
3502                 context->indentLevel += PRETTYINDENT_STD;
3503         }
3504         appendStringInfo(buf, "UPDATE %s%s",
3505                                          only_marker(rte),
3506                                          generate_relation_name(rte->relid, NIL));
3507         if (rte->alias != NULL)
3508                 appendStringInfo(buf, " %s",
3509                                                  quote_identifier(rte->alias->aliasname));
3510         appendStringInfoString(buf, " SET ");
3511
3512         /* Add the comma separated list of 'attname = value' */
3513         sep = "";
3514         foreach(l, query->targetList)
3515         {
3516                 TargetEntry *tle = (TargetEntry *) lfirst(l);
3517                 Node       *expr;
3518
3519                 if (tle->resjunk)
3520                         continue;                       /* ignore junk entries */
3521
3522                 appendStringInfoString(buf, sep);
3523                 sep = ", ";
3524
3525                 /*
3526                  * Put out name of target column; look in the catalogs, not at
3527                  * tle->resname, since resname will fail to track RENAME.
3528                  */
3529                 appendStringInfoString(buf,
3530                                                 quote_identifier(get_relid_attribute_name(rte->relid,
3531                                                                                                                            tle->resno)));
3532
3533                 /*
3534                  * Print any indirection needed (subfields or subscripts), and strip
3535                  * off the top-level nodes representing the indirection assignments.
3536                  */
3537                 expr = processIndirection((Node *) tle->expr, context, true);
3538
3539                 appendStringInfo(buf, " = ");
3540
3541                 get_rule_expr(expr, context, false);
3542         }
3543
3544         /* Add the FROM clause if needed */
3545         get_from_clause(query, " FROM ", context);
3546
3547         /* Add a WHERE clause if given */
3548         if (query->jointree->quals != NULL)
3549         {
3550                 appendContextKeyword(context, " WHERE ",
3551                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3552                 get_rule_expr(query->jointree->quals, context, false);
3553         }
3554
3555         /* Add RETURNING if present */
3556         if (query->returningList)
3557         {
3558                 appendContextKeyword(context, " RETURNING",
3559                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3560                 get_target_list(query->returningList, context, NULL);
3561         }
3562 }
3563
3564
3565 /* ----------
3566  * get_delete_query_def                 - Parse back a DELETE parsetree
3567  * ----------
3568  */
3569 static void
3570 get_delete_query_def(Query *query, deparse_context *context)
3571 {
3572         StringInfo      buf = context->buf;
3573         RangeTblEntry *rte;
3574
3575         /* Insert the WITH clause if given */
3576         get_with_clause(query, context);
3577
3578         /*
3579          * Start the query with DELETE FROM relname
3580          */
3581         rte = rt_fetch(query->resultRelation, query->rtable);
3582         Assert(rte->rtekind == RTE_RELATION);
3583         if (PRETTY_INDENT(context))
3584         {
3585                 appendStringInfoChar(buf, ' ');
3586                 context->indentLevel += PRETTYINDENT_STD;
3587         }
3588         appendStringInfo(buf, "DELETE FROM %s%s",
3589                                          only_marker(rte),
3590                                          generate_relation_name(rte->relid, NIL));
3591         if (rte->alias != NULL)
3592                 appendStringInfo(buf, " %s",
3593                                                  quote_identifier(rte->alias->aliasname));
3594
3595         /* Add the USING clause if given */
3596         get_from_clause(query, " USING ", context);
3597
3598         /* Add a WHERE clause if given */
3599         if (query->jointree->quals != NULL)
3600         {
3601                 appendContextKeyword(context, " WHERE ",
3602                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3603                 get_rule_expr(query->jointree->quals, context, false);
3604         }
3605
3606         /* Add RETURNING if present */
3607         if (query->returningList)
3608         {
3609                 appendContextKeyword(context, " RETURNING",
3610                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3611                 get_target_list(query->returningList, context, NULL);
3612         }
3613 }
3614
3615
3616 /* ----------
3617  * get_utility_query_def                        - Parse back a UTILITY parsetree
3618  * ----------
3619  */
3620 static void
3621 get_utility_query_def(Query *query, deparse_context *context)
3622 {
3623         StringInfo      buf = context->buf;
3624
3625         if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
3626         {
3627                 NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
3628
3629                 appendContextKeyword(context, "",
3630                                                          0, PRETTYINDENT_STD, 1);
3631                 appendStringInfo(buf, "NOTIFY %s",
3632                                                  quote_identifier(stmt->conditionname));
3633                 if (stmt->payload)
3634                 {
3635                         appendStringInfoString(buf, ", ");
3636                         simple_quote_literal(buf, stmt->payload);
3637                 }
3638         }
3639         else
3640         {
3641                 /* Currently only NOTIFY utility commands can appear in rules */
3642                 elog(ERROR, "unexpected utility statement type");
3643         }
3644 }
3645
3646
3647 /*
3648  * Display a Var appropriately.
3649  *
3650  * In some cases (currently only when recursing into an unnamed join)
3651  * the Var's varlevelsup has to be interpreted with respect to a context
3652  * above the current one; levelsup indicates the offset.
3653  *
3654  * If showstar is TRUE, whole-row Vars are displayed as "foo.*";
3655  * if FALSE, merely as "foo".
3656  *
3657  * Returns the attname of the Var, or NULL if not determinable.
3658  */
3659 static char *
3660 get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
3661 {
3662         StringInfo      buf = context->buf;
3663         RangeTblEntry *rte;
3664         AttrNumber      attnum;
3665         int                     netlevelsup;
3666         deparse_namespace *dpns;
3667         char       *schemaname;
3668         char       *refname;
3669         char       *attname;
3670
3671         /* Find appropriate nesting depth */
3672         netlevelsup = var->varlevelsup + levelsup;
3673         if (netlevelsup >= list_length(context->namespaces))
3674                 elog(ERROR, "bogus varlevelsup: %d offset %d",
3675                          var->varlevelsup, levelsup);
3676         dpns = (deparse_namespace *) list_nth(context->namespaces,
3677                                                                                   netlevelsup);
3678
3679         /*
3680          * Try to find the relevant RTE in this rtable.  In a plan tree, it's
3681          * likely that varno is OUTER or INNER, in which case we must dig down
3682          * into the subplans.
3683          */
3684         if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
3685         {
3686                 rte = rt_fetch(var->varno, dpns->rtable);
3687                 attnum = var->varattno;
3688         }
3689         else if (var->varno == OUTER && dpns->outer_plan)
3690         {
3691                 TargetEntry *tle;
3692                 deparse_namespace save_dpns;
3693
3694                 tle = get_tle_by_resno(dpns->outer_plan->targetlist, var->varattno);
3695                 if (!tle)
3696                         elog(ERROR, "bogus varattno for OUTER var: %d", var->varattno);
3697
3698                 Assert(netlevelsup == 0);
3699                 push_child_plan(dpns, dpns->outer_planstate, &save_dpns);
3700
3701                 /*
3702                  * Force parentheses because our caller probably assumed a Var is a
3703                  * simple expression.
3704                  */
3705                 if (!IsA(tle->expr, Var))
3706                         appendStringInfoChar(buf, '(');
3707                 get_rule_expr((Node *) tle->expr, context, true);
3708                 if (!IsA(tle->expr, Var))
3709                         appendStringInfoChar(buf, ')');
3710
3711                 pop_child_plan(dpns, &save_dpns);
3712                 return NULL;
3713         }
3714         else if (var->varno == INNER && dpns->inner_plan)
3715         {
3716                 TargetEntry *tle;
3717                 deparse_namespace save_dpns;
3718
3719                 tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno);
3720                 if (!tle)
3721                         elog(ERROR, "bogus varattno for INNER var: %d", var->varattno);
3722
3723                 Assert(netlevelsup == 0);
3724                 push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
3725
3726                 /*
3727                  * Force parentheses because our caller probably assumed a Var is a
3728                  * simple expression.
3729                  */
3730                 if (!IsA(tle->expr, Var))
3731                         appendStringInfoChar(buf, '(');
3732                 get_rule_expr((Node *) tle->expr, context, true);
3733                 if (!IsA(tle->expr, Var))
3734                         appendStringInfoChar(buf, ')');
3735
3736                 pop_child_plan(dpns, &save_dpns);
3737                 return NULL;
3738         }
3739         else
3740         {
3741                 elog(ERROR, "bogus varno: %d", var->varno);
3742                 return NULL;                    /* keep compiler quiet */
3743         }
3744
3745         /*
3746          * The planner will sometimes emit Vars referencing resjunk elements of a
3747          * subquery's target list (this is currently only possible if it chooses
3748          * to generate a "physical tlist" for a SubqueryScan or CteScan node).
3749          * Although we prefer to print subquery-referencing Vars using the
3750          * subquery's alias, that's not possible for resjunk items since they have
3751          * no alias.  So in that case, drill down to the subplan and print the
3752          * contents of the referenced tlist item.  This works because in a plan
3753          * tree, such Vars can only occur in a SubqueryScan or CteScan node,
3754          * and we'll have set dpns->inner_plan to reference the child plan node.
3755          */
3756         if ((rte->rtekind == RTE_SUBQUERY || rte->rtekind == RTE_CTE) &&
3757                 attnum > list_length(rte->eref->colnames) &&
3758                 dpns->inner_plan)
3759         {
3760                 TargetEntry *tle;
3761                 deparse_namespace save_dpns;
3762
3763                 tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno);
3764                 if (!tle)
3765                         elog(ERROR, "bogus varattno for subquery var: %d", var->varattno);
3766
3767                 Assert(netlevelsup == 0);
3768                 push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
3769
3770                 /*
3771                  * Force parentheses because our caller probably assumed a Var is a
3772                  * simple expression.
3773                  */
3774                 if (!IsA(tle->expr, Var))
3775                         appendStringInfoChar(buf, '(');
3776                 get_rule_expr((Node *) tle->expr, context, true);
3777                 if (!IsA(tle->expr, Var))
3778                         appendStringInfoChar(buf, ')');
3779
3780                 pop_child_plan(dpns, &save_dpns);
3781                 return NULL;
3782         }
3783
3784         /* Identify names to use */
3785         schemaname = NULL;                      /* default assumptions */
3786         refname = rte->eref->aliasname;
3787
3788         /* Exceptions occur only if the RTE is alias-less */
3789         if (rte->alias == NULL)
3790         {
3791                 if (rte->rtekind == RTE_RELATION)
3792                 {
3793                         /*
3794                          * It's possible that use of the bare refname would find another
3795                          * more-closely-nested RTE, or be ambiguous, in which case we need
3796                          * to specify the schemaname to avoid these errors.
3797                          */
3798                         if (find_rte_by_refname(rte->eref->aliasname, context) != rte)
3799                                 schemaname = get_namespace_name(get_rel_namespace(rte->relid));
3800                 }
3801                 else if (rte->rtekind == RTE_JOIN)
3802                 {
3803                         /*
3804                          * If it's an unnamed join, look at the expansion of the alias
3805                          * variable.  If it's a simple reference to one of the input vars
3806                          * then recursively print the name of that var, instead. (This
3807                          * allows correct decompiling of cases where there are identically
3808                          * named columns on both sides of the join.) When it's not a
3809                          * simple reference, we have to just print the unqualified
3810                          * variable name (this can only happen with columns that were
3811                          * merged by USING or NATURAL clauses).
3812                          *
3813                          * This wouldn't work in decompiling plan trees, because we don't
3814                          * store joinaliasvars lists after planning; but a plan tree
3815                          * should never contain a join alias variable.
3816                          */
3817                         if (rte->joinaliasvars == NIL)
3818                                 elog(ERROR, "cannot decompile join alias var in plan tree");
3819                         if (attnum > 0)
3820                         {
3821                                 Var                *aliasvar;
3822
3823                                 aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
3824                                 if (IsA(aliasvar, Var))
3825                                 {
3826                                         return get_variable(aliasvar, var->varlevelsup + levelsup,
3827                                                                                 showstar, context);
3828                                 }
3829                         }
3830                         /* Unnamed join has neither schemaname nor refname */
3831                         refname = NULL;
3832                 }
3833         }
3834
3835         if (attnum == InvalidAttrNumber)
3836                 attname = NULL;
3837         else
3838                 attname = get_rte_attribute_name(rte, attnum);
3839
3840         if (refname && (context->varprefix || attname == NULL))
3841         {
3842                 if (schemaname)
3843                         appendStringInfo(buf, "%s.",
3844                                                          quote_identifier(schemaname));
3845                 appendStringInfoString(buf, quote_identifier(refname));
3846                 if (attname || showstar)
3847                         appendStringInfoChar(buf, '.');
3848         }
3849         if (attname)
3850                 appendStringInfoString(buf, quote_identifier(attname));
3851         else if (showstar)
3852                 appendStringInfoChar(buf, '*');
3853
3854         return attname;
3855 }
3856
3857
3858 /*
3859  * Get the name of a field of an expression of composite type.
3860  *
3861  * This is fairly straightforward except for the case of a Var of type RECORD.
3862  * Since no actual table or view column is allowed to have type RECORD, such
3863  * a Var must refer to a JOIN or FUNCTION RTE or to a subquery output.  We
3864  * drill down to find the ultimate defining expression and attempt to infer
3865  * the field name from it.      We ereport if we can't determine the name.
3866  *
3867  * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
3868  */
3869 static const char *
3870 get_name_for_var_field(Var *var, int fieldno,
3871                                            int levelsup, deparse_context *context)
3872 {
3873         RangeTblEntry *rte;
3874         AttrNumber      attnum;
3875         int                     netlevelsup;
3876         deparse_namespace *dpns;
3877         TupleDesc       tupleDesc;
3878         Node       *expr;
3879
3880         /*
3881          * If it's a RowExpr that was expanded from a whole-row Var, use the
3882          * column names attached to it.
3883          */
3884         if (IsA(var, RowExpr))
3885         {
3886                 RowExpr    *r = (RowExpr *) var;
3887
3888                 if (fieldno > 0 && fieldno <= list_length(r->colnames))
3889                         return strVal(list_nth(r->colnames, fieldno - 1));
3890         }
3891
3892         /*
3893          * If it's a Var of type RECORD, we have to find what the Var refers to;
3894          * if not, we can use get_expr_result_type. If that fails, we try
3895          * lookup_rowtype_tupdesc, which will probably fail too, but will ereport
3896          * an acceptable message.
3897          */
3898         if (!IsA(var, Var) ||
3899                 var->vartype != RECORDOID)
3900         {
3901                 if (get_expr_result_type((Node *) var, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
3902                         tupleDesc = lookup_rowtype_tupdesc_copy(exprType((Node *) var),
3903                                                                                                         exprTypmod((Node *) var));
3904                 Assert(tupleDesc);
3905                 /* Got the tupdesc, so we can extract the field name */
3906                 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
3907                 return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
3908         }
3909
3910         /* Find appropriate nesting depth */
3911         netlevelsup = var->varlevelsup + levelsup;
3912         if (netlevelsup >= list_length(context->namespaces))
3913                 elog(ERROR, "bogus varlevelsup: %d offset %d",
3914                          var->varlevelsup, levelsup);
3915         dpns = (deparse_namespace *) list_nth(context->namespaces,
3916                                                                                   netlevelsup);
3917
3918         /*
3919          * Try to find the relevant RTE in this rtable.  In a plan tree, it's
3920          * likely that varno is OUTER or INNER, in which case we must dig down
3921          * into the subplans.
3922          */
3923         if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
3924         {
3925                 rte = rt_fetch(var->varno, dpns->rtable);
3926                 attnum = var->varattno;
3927         }
3928         else if (var->varno == OUTER && dpns->outer_plan)
3929         {
3930                 TargetEntry *tle;
3931                 deparse_namespace save_dpns;
3932                 const char *result;
3933
3934                 tle = get_tle_by_resno(dpns->outer_plan->targetlist, var->varattno);
3935                 if (!tle)
3936                         elog(ERROR, "bogus varattno for OUTER var: %d", var->varattno);
3937
3938                 Assert(netlevelsup == 0);
3939                 push_child_plan(dpns, dpns->outer_planstate, &save_dpns);
3940
3941                 result = get_name_for_var_field((Var *) tle->expr, fieldno,
3942                                                                                 levelsup, context);
3943
3944                 pop_child_plan(dpns, &save_dpns);
3945                 return result;
3946         }
3947         else if (var->varno == INNER && dpns->inner_plan)
3948         {
3949                 TargetEntry *tle;
3950                 deparse_namespace save_dpns;
3951                 const char *result;
3952
3953                 tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno);
3954                 if (!tle)
3955                         elog(ERROR, "bogus varattno for INNER var: %d", var->varattno);
3956
3957                 Assert(netlevelsup == 0);
3958                 push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
3959
3960                 result = get_name_for_var_field((Var *) tle->expr, fieldno,
3961                                                                                 levelsup, context);
3962
3963                 pop_child_plan(dpns, &save_dpns);
3964                 return result;
3965         }
3966         else
3967         {
3968                 elog(ERROR, "bogus varno: %d", var->varno);
3969                 return NULL;                    /* keep compiler quiet */
3970         }
3971
3972         if (attnum == InvalidAttrNumber)
3973         {
3974                 /* Var is whole-row reference to RTE, so select the right field */
3975                 return get_rte_attribute_name(rte, fieldno);
3976         }
3977
3978         /*
3979          * This part has essentially the same logic as the parser's
3980          * expandRecordVariable() function, but we are dealing with a different
3981          * representation of the input context, and we only need one field name
3982          * not a TupleDesc.  Also, we need special cases for finding subquery and
3983          * CTE subplans when deparsing Plan trees.
3984          */
3985         expr = (Node *) var;            /* default if we can't drill down */
3986
3987         switch (rte->rtekind)
3988         {
3989                 case RTE_RELATION:
3990                 case RTE_SPECIAL:
3991                 case RTE_VALUES:
3992
3993                         /*
3994                          * This case should not occur: a column of a table or values list
3995                          * shouldn't have type RECORD.  Fall through and fail (most
3996                          * likely) at the bottom.
3997                          */
3998                         break;
3999                 case RTE_SUBQUERY:
4000                         /* Subselect-in-FROM: examine sub-select's output expr */
4001                         {
4002                                 if (rte->subquery)
4003                                 {
4004                                         TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
4005                                                                                                                 attnum);
4006
4007                                         if (ste == NULL || ste->resjunk)
4008                                                 elog(ERROR, "subquery %s does not have attribute %d",
4009                                                          rte->eref->aliasname, attnum);
4010                                         expr = (Node *) ste->expr;
4011                                         if (IsA(expr, Var))
4012                                         {
4013                                                 /*
4014                                                  * Recurse into the sub-select to see what its Var
4015                                                  * refers to. We have to build an additional level of
4016                                                  * namespace to keep in step with varlevelsup in the
4017                                                  * subselect.
4018                                                  */
4019                                                 deparse_namespace mydpns;
4020                                                 const char *result;
4021
4022                                                 memset(&mydpns, 0, sizeof(mydpns));
4023                                                 mydpns.rtable = rte->subquery->rtable;
4024                                                 mydpns.ctes = rte->subquery->cteList;
4025
4026                                                 context->namespaces = lcons(&mydpns,
4027                                                                                                         context->namespaces);
4028
4029                                                 result = get_name_for_var_field((Var *) expr, fieldno,
4030                                                                                                                 0, context);
4031
4032                                                 context->namespaces =
4033                                                         list_delete_first(context->namespaces);
4034
4035                                                 return result;
4036                                         }
4037                                         /* else fall through to inspect the expression */
4038                                 }
4039                                 else
4040                                 {
4041                                         /*
4042                                          * We're deparsing a Plan tree so we don't have complete
4043                                          * RTE entries (in particular, rte->subquery is NULL). But
4044                                          * the only place we'd see a Var directly referencing a
4045                                          * SUBQUERY RTE is in a SubqueryScan plan node, and we can
4046                                          * look into the child plan's tlist instead.
4047                                          */
4048                                         TargetEntry *tle;
4049                                         deparse_namespace save_dpns;
4050                                         const char *result;
4051
4052                                         if (!dpns->inner_plan)
4053                                                 elog(ERROR, "failed to find plan for subquery %s",
4054                                                          rte->eref->aliasname);
4055                                         tle = get_tle_by_resno(dpns->inner_plan->targetlist,
4056                                                                                    attnum);
4057                                         if (!tle)
4058                                                 elog(ERROR, "bogus varattno for subquery var: %d",
4059                                                          attnum);
4060                                         Assert(netlevelsup == 0);
4061                                         push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
4062
4063                                         result = get_name_for_var_field((Var *) tle->expr, fieldno,
4064                                                                                                         levelsup, context);
4065
4066                                         pop_child_plan(dpns, &save_dpns);
4067                                         return result;
4068                                 }
4069                         }
4070                         break;
4071                 case RTE_JOIN:
4072                         /* Join RTE --- recursively inspect the alias variable */
4073                         if (rte->joinaliasvars == NIL)
4074                                 elog(ERROR, "cannot decompile join alias var in plan tree");
4075                         Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
4076                         expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
4077                         if (IsA(expr, Var))
4078                                 return get_name_for_var_field((Var *) expr, fieldno,
4079                                                                                           var->varlevelsup + levelsup,
4080                                                                                           context);
4081                         /* else fall through to inspect the expression */
4082                         break;
4083                 case RTE_FUNCTION:
4084
4085                         /*
4086                          * We couldn't get here unless a function is declared with one of
4087                          * its result columns as RECORD, which is not allowed.
4088                          */
4089                         break;
4090                 case RTE_CTE:
4091                         /* CTE reference: examine subquery's output expr */
4092                         {
4093                                 CommonTableExpr *cte = NULL;
4094                                 Index           ctelevelsup;
4095                                 ListCell   *lc;
4096
4097                                 /*
4098                                  * Try to find the referenced CTE using the namespace stack.
4099                                  */
4100                                 ctelevelsup = rte->ctelevelsup + netlevelsup;
4101                                 if (ctelevelsup >= list_length(context->namespaces))
4102                                         lc = NULL;
4103                                 else
4104                                 {
4105                                         deparse_namespace *ctedpns;
4106
4107                                         ctedpns = (deparse_namespace *)
4108                                                 list_nth(context->namespaces, ctelevelsup);
4109                                         foreach(lc, ctedpns->ctes)
4110                                         {
4111                                                 cte = (CommonTableExpr *) lfirst(lc);
4112                                                 if (strcmp(cte->ctename, rte->ctename) == 0)
4113                                                         break;
4114                                         }
4115                                 }
4116                                 if (lc != NULL)
4117                                 {
4118                                         Query      *ctequery = (Query *) cte->ctequery;
4119                                         TargetEntry *ste = get_tle_by_resno(ctequery->targetList,
4120                                                                                                                 attnum);
4121
4122                                         if (ste == NULL || ste->resjunk)
4123                                                 elog(ERROR, "subquery %s does not have attribute %d",
4124                                                          rte->eref->aliasname, attnum);
4125                                         expr = (Node *) ste->expr;
4126                                         if (IsA(expr, Var))
4127                                         {
4128                                                 /*
4129                                                  * Recurse into the CTE to see what its Var refers to.
4130                                                  * We have to build an additional level of namespace
4131                                                  * to keep in step with varlevelsup in the CTE.
4132                                                  * Furthermore it could be an outer CTE, so we may
4133                                                  * have to delete some levels of namespace.
4134                                                  */
4135                                                 List       *save_nslist = context->namespaces;
4136                                                 List       *new_nslist;
4137                                                 deparse_namespace mydpns;
4138                                                 const char *result;
4139
4140                                                 memset(&mydpns, 0, sizeof(mydpns));
4141                                                 mydpns.rtable = ctequery->rtable;
4142                                                 mydpns.ctes = ctequery->cteList;
4143
4144                                                 new_nslist = list_copy_tail(context->namespaces,
4145                                                                                                         ctelevelsup);
4146                                                 context->namespaces = lcons(&mydpns, new_nslist);
4147
4148                                                 result = get_name_for_var_field((Var *) expr, fieldno,
4149                                                                                                                 0, context);
4150
4151                                                 context->namespaces = save_nslist;
4152
4153                                                 return result;
4154                                         }
4155                                         /* else fall through to inspect the expression */
4156                                 }
4157                                 else
4158                                 {
4159                                         /*
4160                                          * We're deparsing a Plan tree so we don't have a CTE
4161                                          * list.  But the only place we'd see a Var directly
4162                                          * referencing a CTE RTE is in a CteScan plan node, and we
4163                                          * can look into the subplan's tlist instead.
4164                                          */
4165                                         TargetEntry *tle;
4166                                         deparse_namespace save_dpns;
4167                                         const char *result;
4168
4169                                         if (!dpns->inner_plan)
4170                                                 elog(ERROR, "failed to find plan for CTE %s",
4171                                                          rte->eref->aliasname);
4172                                         tle = get_tle_by_resno(dpns->inner_plan->targetlist,
4173                                                                                    attnum);
4174                                         if (!tle)
4175                                                 elog(ERROR, "bogus varattno for subquery var: %d",
4176                                                          attnum);
4177                                         Assert(netlevelsup == 0);
4178                                         push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
4179
4180                                         result = get_name_for_var_field((Var *) tle->expr, fieldno,
4181                                                                                                         levelsup, context);
4182
4183                                         pop_child_plan(dpns, &save_dpns);
4184                                         return result;
4185                                 }
4186                         }
4187                         break;
4188         }
4189
4190         /*
4191          * We now have an expression we can't expand any more, so see if
4192          * get_expr_result_type() can do anything with it.      If not, pass to
4193          * lookup_rowtype_tupdesc() which will probably fail, but will give an
4194          * appropriate error message while failing.
4195          */
4196         if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
4197                 tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr),
4198                                                                                                 exprTypmod(expr));
4199         Assert(tupleDesc);
4200         /* Got the tupdesc, so we can extract the field name */
4201         Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
4202         return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
4203 }
4204
4205
4206 /*
4207  * find_rte_by_refname          - look up an RTE by refname in a deparse context
4208  *
4209  * Returns NULL if there is no matching RTE or the refname is ambiguous.
4210  *
4211  * NOTE: this code is not really correct since it does not take account of
4212  * the fact that not all the RTEs in a rangetable may be visible from the
4213  * point where a Var reference appears.  For the purposes we need, however,
4214  * the only consequence of a false match is that we might stick a schema
4215  * qualifier on a Var that doesn't really need it.  So it seems close
4216  * enough.
4217  */
4218 static RangeTblEntry *
4219 find_rte_by_refname(const char *refname, deparse_context *context)
4220 {
4221         RangeTblEntry *result = NULL;
4222         ListCell   *nslist;
4223
4224         foreach(nslist, context->namespaces)
4225         {
4226                 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
4227                 ListCell   *rtlist;
4228
4229                 foreach(rtlist, dpns->rtable)
4230                 {
4231                         RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtlist);
4232
4233                         if (strcmp(rte->eref->aliasname, refname) == 0)
4234                         {
4235                                 if (result)
4236                                         return NULL;    /* it's ambiguous */
4237                                 result = rte;
4238                         }
4239                 }
4240                 if (result)
4241                         break;
4242         }
4243         return result;
4244 }
4245
4246 /*
4247  * Display a Param appropriately.
4248  */
4249 static void
4250 get_parameter(Param *param, deparse_context *context)
4251 {
4252         /*
4253          * If it's a PARAM_EXEC parameter, try to locate the expression from
4254          * which the parameter was computed.  This will necessarily be in some
4255          * ancestor of the current expression's PlanState.  Note that failing
4256          * to find a referent isn't an error, since the Param might well be a
4257          * subplan output rather than an input.
4258          */
4259         if (param->paramkind == PARAM_EXEC)
4260         {
4261                 deparse_namespace *dpns;
4262                 PlanState  *child_ps;
4263                 bool            in_same_plan_level;
4264                 ListCell   *lc;
4265
4266                 dpns = (deparse_namespace *) linitial(context->namespaces);
4267                 child_ps = dpns->planstate;
4268                 in_same_plan_level = true;
4269
4270                 foreach(lc, dpns->ancestors)
4271                 {
4272                         PlanState  *ps = (PlanState *) lfirst(lc);
4273                         ListCell   *lc2;
4274
4275                         /*
4276                          * NestLoops transmit params to their inner child only; also,
4277                          * once we've crawled up out of a subplan, this couldn't
4278                          * possibly be the right match.
4279                          */
4280                         if (IsA(ps, NestLoopState) &&
4281                                 child_ps == innerPlanState(ps) &&
4282                                 in_same_plan_level)
4283                         {
4284                                 NestLoop   *nl = (NestLoop *) ps->plan;
4285
4286                                 foreach(lc2, nl->nestParams)
4287                                 {
4288                                         NestLoopParam  *nlp = (NestLoopParam *) lfirst(lc2);
4289
4290                                         if (nlp->paramno == param->paramid)
4291                                         {
4292                                                 /* Found a match, so print it */
4293                                                 print_parameter_expr((Node *) nlp->paramval, lc,
4294                                                                                          dpns, context);
4295                                                 return;
4296                                         }
4297                                 }
4298                         }
4299
4300                         /*
4301                          * Check to see if we're crawling up from a subplan.
4302                          */
4303                         foreach(lc2, ps->subPlan)
4304                         {
4305                                 SubPlanState *sstate = (SubPlanState *) lfirst(lc2);
4306                                 SubPlan    *subplan = (SubPlan *) sstate->xprstate.expr;
4307                                 ListCell   *lc3;
4308                                 ListCell   *lc4;
4309
4310                                 if (child_ps != sstate->planstate)
4311                                         continue;
4312
4313                                 /* Matched subplan, so check its arguments */
4314                                 forboth(lc3, subplan->parParam, lc4, subplan->args)
4315                                 {
4316                                         int             paramid = lfirst_int(lc3);
4317                                         Node   *arg = (Node *) lfirst(lc4);
4318
4319                                         if (paramid == param->paramid)
4320                                         {
4321                                                 /* Found a match, so print it */
4322                                                 print_parameter_expr(arg, lc, dpns, context);
4323                                                 return;
4324                                         }
4325                                 }
4326
4327                                 /* Keep looking, but we are emerging from a subplan. */
4328                                 in_same_plan_level = false;
4329                                 break;
4330                         }
4331
4332                         /*
4333                          * Likewise check to see if we're emerging from an initplan.
4334                          * Initplans never have any parParams, so no need to search that
4335                          * list, but we need to know if we should reset
4336                          * in_same_plan_level.
4337                          */
4338                         foreach(lc2, ps->initPlan)
4339                         {
4340                                 SubPlanState *sstate = (SubPlanState *) lfirst(lc2);
4341
4342                                 if (child_ps != sstate->planstate)
4343                                         continue;
4344
4345                                 /* No parameters to be had here. */
4346                                 Assert(((SubPlan *) sstate->xprstate.expr)->parParam == NIL);
4347
4348                                 /* Keep looking, but we are emerging from an initplan. */
4349                                 in_same_plan_level = false;
4350                                 break;
4351                         }
4352
4353                         /* No luck, crawl up to next ancestor */
4354                         child_ps = ps;
4355                 }
4356         }
4357
4358         /*
4359          * Not PARAM_EXEC, or couldn't find referent: just print $N.
4360          */
4361         appendStringInfo(context->buf, "$%d", param->paramid);
4362 }
4363
4364 /* Print a parameter reference expression found by get_parameter */
4365 static void
4366 print_parameter_expr(Node *expr, ListCell *ancestor_cell,
4367                                          deparse_namespace *dpns, deparse_context *context)
4368 {
4369         deparse_namespace save_dpns;
4370         bool            save_varprefix;
4371
4372         /* Switch attention to the ancestor plan node */
4373         push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
4374
4375         /*
4376          * Force prefixing of Vars, since they won't belong to the relation being
4377          * scanned in the original plan node.
4378          */
4379         save_varprefix = context->varprefix;
4380         context->varprefix = true;
4381
4382         /*
4383          * We don't need to add parentheses because a Param's expansion is
4384          * (currently) always a Var or Aggref.
4385          */
4386         Assert(IsA(expr, Var) || IsA(expr, Aggref));
4387
4388         get_rule_expr(expr, context, false);
4389
4390         context->varprefix = save_varprefix;
4391
4392         pop_ancestor_plan(dpns, &save_dpns);
4393 }
4394
4395 /*
4396  * get_simple_binary_op_name
4397  *
4398  * helper function for isSimpleNode
4399  * will return single char binary operator name, or NULL if it's not
4400  */
4401 static const char *
4402 get_simple_binary_op_name(OpExpr *expr)
4403 {
4404         List       *args = expr->args;
4405
4406         if (list_length(args) == 2)
4407         {
4408                 /* binary operator */
4409                 Node       *arg1 = (Node *) linitial(args);
4410                 Node       *arg2 = (Node *) lsecond(args);
4411                 const char *op;
4412
4413                 op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
4414                 if (strlen(op) == 1)
4415                         return op;
4416         }
4417         return NULL;
4418 }
4419
4420
4421 /*
4422  * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
4423  *
4424  *      true   : simple in the context of parent node's type
4425  *      false  : not simple
4426  */
4427 static bool
4428 isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
4429 {
4430         if (!node)
4431                 return false;
4432
4433         switch (nodeTag(node))
4434         {
4435                 case T_Var:
4436                 case T_Const:
4437                 case T_Param:
4438                 case T_CoerceToDomainValue:
4439                 case T_SetToDefault:
4440                 case T_CurrentOfExpr:
4441                         /* single words: always simple */
4442                         return true;
4443
4444                 case T_ArrayRef:
4445                 case T_ArrayExpr:
4446                 case T_RowExpr:
4447                 case T_CoalesceExpr:
4448                 case T_MinMaxExpr:
4449                 case T_XmlExpr:
4450                 case T_NullIfExpr:
4451                 case T_Aggref:
4452                 case T_WindowFunc:
4453                 case T_FuncExpr:
4454                         /* function-like: name(..) or name[..] */
4455                         return true;
4456
4457                         /* CASE keywords act as parentheses */
4458                 case T_CaseExpr:
4459                         return true;
4460
4461                 case T_FieldSelect:
4462
4463                         /*
4464                          * appears simple since . has top precedence, unless parent is
4465                          * T_FieldSelect itself!
4466                          */
4467                         return (IsA(parentNode, FieldSelect) ? false : true);
4468
4469                 case T_FieldStore:
4470
4471                         /*
4472                          * treat like FieldSelect (probably doesn't matter)
4473                          */
4474                         return (IsA(parentNode, FieldStore) ? false : true);
4475
4476                 case T_CoerceToDomain:
4477                         /* maybe simple, check args */
4478                         return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
4479                                                                 node, prettyFlags);
4480                 case T_RelabelType:
4481                         return isSimpleNode((Node *) ((RelabelType *) node)->arg,
4482                                                                 node, prettyFlags);
4483                 case T_CoerceViaIO:
4484                         return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
4485                                                                 node, prettyFlags);
4486                 case T_ArrayCoerceExpr:
4487                         return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
4488                                                                 node, prettyFlags);
4489                 case T_ConvertRowtypeExpr:
4490                         return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
4491                                                                 node, prettyFlags);
4492
4493                 case T_OpExpr:
4494                         {
4495                                 /* depends on parent node type; needs further checking */
4496                                 if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
4497                                 {
4498                                         const char *op;
4499                                         const char *parentOp;
4500                                         bool            is_lopriop;
4501                                         bool            is_hipriop;
4502                                         bool            is_lopriparent;
4503                                         bool            is_hipriparent;
4504
4505                                         op = get_simple_binary_op_name((OpExpr *) node);
4506                                         if (!op)
4507                                                 return false;
4508
4509                                         /* We know only the basic operators + - and * / % */
4510                                         is_lopriop = (strchr("+-", *op) != NULL);
4511                                         is_hipriop = (strchr("*/%", *op) != NULL);
4512                                         if (!(is_lopriop || is_hipriop))
4513                                                 return false;
4514
4515                                         parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
4516                                         if (!parentOp)
4517                                                 return false;
4518
4519                                         is_lopriparent = (strchr("+-", *parentOp) != NULL);
4520                                         is_hipriparent = (strchr("*/%", *parentOp) != NULL);
4521                                         if (!(is_lopriparent || is_hipriparent))
4522                                                 return false;
4523
4524                                         if (is_hipriop && is_lopriparent)
4525                                                 return true;    /* op binds tighter than parent */
4526
4527                                         if (is_lopriop && is_hipriparent)
4528                                                 return false;
4529
4530                                         /*
4531                                          * Operators are same priority --- can skip parens only if
4532                                          * we have (a - b) - c, not a - (b - c).
4533                                          */
4534                                         if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
4535                                                 return true;
4536
4537                                         return false;
4538                                 }
4539                                 /* else do the same stuff as for T_SubLink et al. */
4540                                 /* FALL THROUGH */
4541                         }
4542
4543                 case T_SubLink:
4544                 case T_NullTest:
4545                 case T_BooleanTest:
4546                 case T_DistinctExpr:
4547                         switch (nodeTag(parentNode))
4548                         {
4549                                 case T_FuncExpr:
4550                                         {
4551                                                 /* special handling for casts */
4552                                                 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
4553
4554                                                 if (type == COERCE_EXPLICIT_CAST ||
4555                                                         type == COERCE_IMPLICIT_CAST)
4556                                                         return false;
4557                                                 return true;    /* own parentheses */
4558                                         }
4559                                 case T_BoolExpr:                /* lower precedence */
4560                                 case T_ArrayRef:                /* other separators */
4561                                 case T_ArrayExpr:               /* other separators */
4562                                 case T_RowExpr: /* other separators */
4563                                 case T_CoalesceExpr:    /* own parentheses */
4564                                 case T_MinMaxExpr:              /* own parentheses */
4565                                 case T_XmlExpr: /* own parentheses */
4566                                 case T_NullIfExpr:              /* other separators */
4567                                 case T_Aggref:  /* own parentheses */
4568                                 case T_WindowFunc:              /* own parentheses */
4569                                 case T_CaseExpr:                /* other separators */
4570                                         return true;
4571                                 default:
4572                                         return false;
4573                         }
4574
4575                 case T_BoolExpr:
4576                         switch (nodeTag(parentNode))
4577                         {
4578                                 case T_BoolExpr:
4579                                         if (prettyFlags & PRETTYFLAG_PAREN)
4580                                         {
4581                                                 BoolExprType type;
4582                                                 BoolExprType parentType;
4583
4584                                                 type = ((BoolExpr *) node)->boolop;
4585                                                 parentType = ((BoolExpr *) parentNode)->boolop;
4586                                                 switch (type)
4587                                                 {
4588                                                         case NOT_EXPR:
4589                                                         case AND_EXPR:
4590                                                                 if (parentType == AND_EXPR || parentType == OR_EXPR)
4591                                                                         return true;
4592                                                                 break;
4593                                                         case OR_EXPR:
4594                                                                 if (parentType == OR_EXPR)
4595                                                                         return true;
4596                                                                 break;
4597                                                 }
4598                                         }
4599                                         return false;
4600                                 case T_FuncExpr:
4601                                         {
4602                                                 /* special handling for casts */
4603                                                 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
4604
4605                                                 if (type == COERCE_EXPLICIT_CAST ||
4606                                                         type == COERCE_IMPLICIT_CAST)
4607                                                         return false;
4608                                                 return true;    /* own parentheses */
4609                                         }
4610                                 case T_ArrayRef:                /* other separators */
4611                                 case T_ArrayExpr:               /* other separators */
4612                                 case T_RowExpr: /* other separators */
4613                                 case T_CoalesceExpr:    /* own parentheses */
4614                                 case T_MinMaxExpr:              /* own parentheses */
4615                                 case T_XmlExpr: /* own parentheses */
4616                                 case T_NullIfExpr:              /* other separators */
4617                                 case T_Aggref:  /* own parentheses */
4618                                 case T_WindowFunc:              /* own parentheses */
4619                                 case T_CaseExpr:                /* other separators */
4620                                         return true;
4621                                 default:
4622                                         return false;
4623                         }
4624
4625                 default:
4626                         break;
4627         }
4628         /* those we don't know: in dubio complexo */
4629         return false;
4630 }
4631
4632
4633 /*
4634  * appendContextKeyword - append a keyword to buffer
4635  *
4636  * If prettyPrint is enabled, perform a line break, and adjust indentation.
4637  * Otherwise, just append the keyword.
4638  */
4639 static void
4640 appendContextKeyword(deparse_context *context, const char *str,
4641                                          int indentBefore, int indentAfter, int indentPlus)
4642 {
4643         if (PRETTY_INDENT(context))
4644         {
4645                 context->indentLevel += indentBefore;
4646
4647                 appendStringInfoChar(context->buf, '\n');
4648                 appendStringInfoSpaces(context->buf,
4649                                                            Max(context->indentLevel, 0) + indentPlus);
4650                 appendStringInfoString(context->buf, str);
4651
4652                 context->indentLevel += indentAfter;
4653                 if (context->indentLevel < 0)
4654                         context->indentLevel = 0;
4655         }
4656         else
4657                 appendStringInfoString(context->buf, str);
4658 }
4659
4660 /*
4661  * get_rule_expr_paren  - deparse expr using get_rule_expr,
4662  * embracing the string with parentheses if necessary for prettyPrint.
4663  *
4664  * Never embrace if prettyFlags=0, because it's done in the calling node.
4665  *
4666  * Any node that does *not* embrace its argument node by sql syntax (with
4667  * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
4668  * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
4669  * added.
4670  */
4671 static void
4672 get_rule_expr_paren(Node *node, deparse_context *context,
4673                                         bool showimplicit, Node *parentNode)
4674 {
4675         bool            need_paren;
4676
4677         need_paren = PRETTY_PAREN(context) &&
4678                 !isSimpleNode(node, parentNode, context->prettyFlags);
4679
4680         if (need_paren)
4681                 appendStringInfoChar(context->buf, '(');
4682
4683         get_rule_expr(node, context, showimplicit);
4684
4685         if (need_paren)
4686                 appendStringInfoChar(context->buf, ')');
4687 }
4688
4689
4690 /* ----------
4691  * get_rule_expr                        - Parse back an expression
4692  *
4693  * Note: showimplicit determines whether we display any implicit cast that
4694  * is present at the top of the expression tree.  It is a passed argument,
4695  * not a field of the context struct, because we change the value as we
4696  * recurse down into the expression.  In general we suppress implicit casts
4697  * when the result type is known with certainty (eg, the arguments of an
4698  * OR must be boolean).  We display implicit casts for arguments of functions
4699  * and operators, since this is needed to be certain that the same function
4700  * or operator will be chosen when the expression is re-parsed.
4701  * ----------
4702  */
4703 static void
4704 get_rule_expr(Node *node, deparse_context *context,
4705                           bool showimplicit)
4706 {
4707         StringInfo      buf = context->buf;
4708
4709         if (node == NULL)
4710                 return;
4711
4712         /*
4713          * Each level of get_rule_expr must emit an indivisible term
4714          * (parenthesized if necessary) to ensure result is reparsed into the same
4715          * expression tree.  The only exception is that when the input is a List,
4716          * we emit the component items comma-separated with no surrounding
4717          * decoration; this is convenient for most callers.
4718          */
4719         switch (nodeTag(node))
4720         {
4721                 case T_Var:
4722                         (void) get_variable((Var *) node, 0, true, context);
4723                         break;
4724
4725                 case T_Const:
4726                         get_const_expr((Const *) node, context, 0);
4727                         break;
4728
4729                 case T_Param:
4730                         get_parameter((Param *) node, context);
4731                         break;
4732
4733                 case T_Aggref:
4734                         get_agg_expr((Aggref *) node, context);
4735                         break;
4736
4737                 case T_WindowFunc:
4738                         get_windowfunc_expr((WindowFunc *) node, context);
4739                         break;
4740
4741                 case T_ArrayRef:
4742                         {
4743                                 ArrayRef   *aref = (ArrayRef *) node;
4744                                 bool            need_parens;
4745
4746                                 /*
4747                                  * If the argument is a CaseTestExpr, we must be inside a
4748                                  * FieldStore, ie, we are assigning to an element of an array
4749                                  * within a composite column.  Since we already punted on
4750                                  * displaying the FieldStore's target information, just punt
4751                                  * here too, and display only the assignment source
4752                                  * expression.
4753                                  */
4754                                 if (IsA(aref->refexpr, CaseTestExpr))
4755                                 {
4756                                         Assert(aref->refassgnexpr);
4757                                         get_rule_expr((Node *) aref->refassgnexpr,
4758                                                                   context, showimplicit);
4759                                         break;
4760                                 }
4761
4762                                 /*
4763                                  * Parenthesize the argument unless it's a simple Var or a
4764                                  * FieldSelect.  (In particular, if it's another ArrayRef, we
4765                                  * *must* parenthesize to avoid confusion.)
4766                                  */
4767                                 need_parens = !IsA(aref->refexpr, Var) &&
4768                                         !IsA(aref->refexpr, FieldSelect);
4769                                 if (need_parens)
4770                                         appendStringInfoChar(buf, '(');
4771                                 get_rule_expr((Node *) aref->refexpr, context, showimplicit);
4772                                 if (need_parens)
4773                                         appendStringInfoChar(buf, ')');
4774
4775                                 /*
4776                                  * If there's a refassgnexpr, we want to print the node in the
4777                                  * format "array[subscripts] := refassgnexpr".  This is not
4778                                  * legal SQL, so decompilation of INSERT or UPDATE statements
4779                                  * should always use processIndirection as part of the
4780                                  * statement-level syntax.      We should only see this when
4781                                  * EXPLAIN tries to print the targetlist of a plan resulting
4782                                  * from such a statement.
4783                                  */
4784                                 if (aref->refassgnexpr)
4785                                 {
4786                                         Node       *refassgnexpr;
4787
4788                                         /*
4789                                          * Use processIndirection to print this node's subscripts
4790                                          * as well as any additional field selections or
4791                                          * subscripting in immediate descendants.  It returns the
4792                                          * RHS expr that is actually being "assigned".
4793                                          */
4794                                         refassgnexpr = processIndirection(node, context, true);
4795                                         appendStringInfoString(buf, " := ");
4796                                         get_rule_expr(refassgnexpr, context, showimplicit);
4797                                 }
4798                                 else
4799                                 {
4800                                         /* Just an ordinary array fetch, so print subscripts */
4801                                         printSubscripts(aref, context);
4802                                 }
4803                         }
4804                         break;
4805
4806                 case T_FuncExpr:
4807                         get_func_expr((FuncExpr *) node, context, showimplicit);
4808                         break;
4809
4810                 case T_NamedArgExpr:
4811                         {
4812                                 NamedArgExpr *na = (NamedArgExpr *) node;
4813
4814                                 appendStringInfo(buf, "%s := ", quote_identifier(na->name));
4815                                 get_rule_expr((Node *) na->arg, context, showimplicit);
4816                         }
4817                         break;
4818
4819                 case T_OpExpr:
4820                         get_oper_expr((OpExpr *) node, context);
4821                         break;
4822
4823                 case T_DistinctExpr:
4824                         {
4825                                 DistinctExpr *expr = (DistinctExpr *) node;
4826                                 List       *args = expr->args;
4827                                 Node       *arg1 = (Node *) linitial(args);
4828                                 Node       *arg2 = (Node *) lsecond(args);
4829
4830                                 if (!PRETTY_PAREN(context))
4831                                         appendStringInfoChar(buf, '(');
4832                                 get_rule_expr_paren(arg1, context, true, node);
4833                                 appendStringInfo(buf, " IS DISTINCT FROM ");
4834                                 get_rule_expr_paren(arg2, context, true, node);
4835                                 if (!PRETTY_PAREN(context))
4836                                         appendStringInfoChar(buf, ')');
4837                         }
4838                         break;
4839
4840                 case T_ScalarArrayOpExpr:
4841                         {
4842                                 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
4843                                 List       *args = expr->args;
4844                                 Node       *arg1 = (Node *) linitial(args);
4845                                 Node       *arg2 = (Node *) lsecond(args);
4846
4847                                 if (!PRETTY_PAREN(context))
4848                                         appendStringInfoChar(buf, '(');
4849                                 get_rule_expr_paren(arg1, context, true, node);
4850                                 appendStringInfo(buf, " %s %s (",
4851                                                                  generate_operator_name(expr->opno,
4852                                                                                                                 exprType(arg1),
4853                                                                                    get_element_type(exprType(arg2))),
4854                                                                  expr->useOr ? "ANY" : "ALL");
4855                                 get_rule_expr_paren(arg2, context, true, node);
4856                                 appendStringInfoChar(buf, ')');
4857                                 if (!PRETTY_PAREN(context))
4858                                         appendStringInfoChar(buf, ')');
4859                         }
4860                         break;
4861
4862                 case T_BoolExpr:
4863                         {
4864                                 BoolExpr   *expr = (BoolExpr *) node;
4865                                 Node       *first_arg = linitial(expr->args);
4866                                 ListCell   *arg = lnext(list_head(expr->args));
4867
4868                                 switch (expr->boolop)
4869                                 {
4870                                         case AND_EXPR:
4871                                                 if (!PRETTY_PAREN(context))
4872                                                         appendStringInfoChar(buf, '(');
4873                                                 get_rule_expr_paren(first_arg, context,
4874                                                                                         false, node);
4875                                                 while (arg)
4876                                                 {
4877                                                         appendStringInfo(buf, " AND ");
4878                                                         get_rule_expr_paren((Node *) lfirst(arg), context,
4879                                                                                                 false, node);
4880                                                         arg = lnext(arg);
4881                                                 }
4882                                                 if (!PRETTY_PAREN(context))
4883                                                         appendStringInfoChar(buf, ')');
4884                                                 break;
4885
4886                                         case OR_EXPR:
4887                                                 if (!PRETTY_PAREN(context))
4888                                                         appendStringInfoChar(buf, '(');
4889                                                 get_rule_expr_paren(first_arg, context,
4890                                                                                         false, node);
4891                                                 while (arg)
4892                                                 {
4893                                                         appendStringInfo(buf, " OR ");
4894                                                         get_rule_expr_paren((Node *) lfirst(arg), context,
4895                                                                                                 false, node);
4896                                                         arg = lnext(arg);
4897                                                 }
4898                                                 if (!PRETTY_PAREN(context))
4899                                                         appendStringInfoChar(buf, ')');
4900                                                 break;
4901
4902                                         case NOT_EXPR:
4903                                                 if (!PRETTY_PAREN(context))
4904                                                         appendStringInfoChar(buf, '(');
4905                                                 appendStringInfo(buf, "NOT ");
4906                                                 get_rule_expr_paren(first_arg, context,
4907                                                                                         false, node);
4908                                                 if (!PRETTY_PAREN(context))
4909                                                         appendStringInfoChar(buf, ')');
4910                                                 break;
4911
4912                                         default:
4913                                                 elog(ERROR, "unrecognized boolop: %d",
4914                                                          (int) expr->boolop);
4915                                 }
4916                         }
4917                         break;
4918
4919                 case T_SubLink:
4920                         get_sublink_expr((SubLink *) node, context);
4921                         break;
4922
4923                 case T_SubPlan:
4924                         {
4925                                 SubPlan    *subplan = (SubPlan *) node;
4926
4927                                 /*
4928                                  * We cannot see an already-planned subplan in rule deparsing,
4929                                  * only while EXPLAINing a query plan.  We don't try to
4930                                  * reconstruct the original SQL, just reference the subplan
4931                                  * that appears elsewhere in EXPLAIN's result.
4932                                  */
4933                                 if (subplan->useHashTable)
4934                                         appendStringInfo(buf, "(hashed %s)", subplan->plan_name);
4935                                 else
4936                                         appendStringInfo(buf, "(%s)", subplan->plan_name);
4937                         }
4938                         break;
4939
4940                 case T_AlternativeSubPlan:
4941                         {
4942                                 AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
4943                                 ListCell   *lc;
4944
4945                                 /* As above, this can only happen during EXPLAIN */
4946                                 appendStringInfo(buf, "(alternatives: ");
4947                                 foreach(lc, asplan->subplans)
4948                                 {
4949                                         SubPlan    *splan = (SubPlan *) lfirst(lc);
4950
4951                                         Assert(IsA(splan, SubPlan));
4952                                         if (splan->useHashTable)
4953                                                 appendStringInfo(buf, "hashed %s", splan->plan_name);
4954                                         else
4955                                                 appendStringInfo(buf, "%s", splan->plan_name);
4956                                         if (lnext(lc))
4957                                                 appendStringInfo(buf, " or ");
4958                                 }
4959                                 appendStringInfo(buf, ")");
4960                         }
4961                         break;
4962
4963                 case T_FieldSelect:
4964                         {
4965                                 FieldSelect *fselect = (FieldSelect *) node;
4966                                 Node       *arg = (Node *) fselect->arg;
4967                                 int                     fno = fselect->fieldnum;
4968                                 const char *fieldname;
4969                                 bool            need_parens;
4970
4971                                 /*
4972                                  * Parenthesize the argument unless it's an ArrayRef or
4973                                  * another FieldSelect.  Note in particular that it would be
4974                                  * WRONG to not parenthesize a Var argument; simplicity is not
4975                                  * the issue here, having the right number of names is.
4976                                  */
4977                                 need_parens = !IsA(arg, ArrayRef) &&!IsA(arg, FieldSelect);
4978                                 if (need_parens)
4979                                         appendStringInfoChar(buf, '(');
4980                                 get_rule_expr(arg, context, true);
4981                                 if (need_parens)
4982                                         appendStringInfoChar(buf, ')');
4983
4984                                 /*
4985                                  * Get and print the field name.
4986                                  */
4987                                 fieldname = get_name_for_var_field((Var *) arg, fno,
4988                                                                                                    0, context);
4989                                 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
4990                         }
4991                         break;
4992
4993                 case T_FieldStore:
4994                         {
4995                                 FieldStore *fstore = (FieldStore *) node;
4996                                 bool            need_parens;
4997
4998                                 /*
4999                                  * There is no good way to represent a FieldStore as real SQL,
5000                                  * so decompilation of INSERT or UPDATE statements should
5001                                  * always use processIndirection as part of the
5002                                  * statement-level syntax.      We should only get here when
5003                                  * EXPLAIN tries to print the targetlist of a plan resulting
5004                                  * from such a statement.  The plan case is even harder than
5005                                  * ordinary rules would be, because the planner tries to
5006                                  * collapse multiple assignments to the same field or subfield
5007                                  * into one FieldStore; so we can see a list of target fields
5008                                  * not just one, and the arguments could be FieldStores
5009                                  * themselves.  We don't bother to try to print the target
5010                                  * field names; we just print the source arguments, with a
5011                                  * ROW() around them if there's more than one.  This isn't
5012                                  * terribly complete, but it's probably good enough for
5013                                  * EXPLAIN's purposes; especially since anything more would be
5014                                  * either hopelessly confusing or an even poorer
5015                                  * representation of what the plan is actually doing.
5016                                  */
5017                                 need_parens = (list_length(fstore->newvals) != 1);
5018                                 if (need_parens)
5019                                         appendStringInfoString(buf, "ROW(");
5020                                 get_rule_expr((Node *) fstore->newvals, context, showimplicit);
5021                                 if (need_parens)
5022                                         appendStringInfoChar(buf, ')');
5023                         }
5024                         break;
5025
5026                 case T_RelabelType:
5027                         {
5028                                 RelabelType *relabel = (RelabelType *) node;
5029                                 Node       *arg = (Node *) relabel->arg;
5030
5031                                 if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
5032                                         !showimplicit)
5033                                 {
5034                                         /* don't show the implicit cast */
5035                                         get_rule_expr_paren(arg, context, false, node);
5036                                 }
5037                                 else
5038                                 {
5039                                         get_coercion_expr(arg, context,
5040                                                                           relabel->resulttype,
5041                                                                           relabel->resulttypmod,
5042                                                                           node);
5043                                 }
5044                         }
5045                         break;
5046
5047                 case T_CoerceViaIO:
5048                         {
5049                                 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
5050                                 Node       *arg = (Node *) iocoerce->arg;
5051
5052                                 if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
5053                                         !showimplicit)
5054                                 {
5055                                         /* don't show the implicit cast */
5056                                         get_rule_expr_paren(arg, context, false, node);
5057                                 }
5058                                 else
5059                                 {
5060                                         get_coercion_expr(arg, context,
5061                                                                           iocoerce->resulttype,
5062                                                                           -1,
5063                                                                           node);
5064                                 }
5065                         }
5066                         break;
5067
5068                 case T_ArrayCoerceExpr:
5069                         {
5070                                 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
5071                                 Node       *arg = (Node *) acoerce->arg;
5072
5073                                 if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
5074                                         !showimplicit)
5075                                 {
5076                                         /* don't show the implicit cast */
5077                                         get_rule_expr_paren(arg, context, false, node);
5078                                 }
5079                                 else
5080                                 {
5081                                         get_coercion_expr(arg, context,
5082                                                                           acoerce->resulttype,
5083                                                                           acoerce->resulttypmod,
5084                                                                           node);
5085                                 }
5086                         }
5087                         break;
5088
5089                 case T_ConvertRowtypeExpr:
5090                         {
5091                                 ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
5092                                 Node       *arg = (Node *) convert->arg;
5093
5094                                 if (convert->convertformat == COERCE_IMPLICIT_CAST &&
5095                                         !showimplicit)
5096                                 {
5097                                         /* don't show the implicit cast */
5098                                         get_rule_expr_paren(arg, context, false, node);
5099                                 }
5100                                 else
5101                                 {
5102                                         get_coercion_expr(arg, context,
5103                                                                           convert->resulttype, -1,
5104                                                                           node);
5105                                 }
5106                         }
5107                         break;
5108
5109                 case T_CaseExpr:
5110                         {
5111                                 CaseExpr   *caseexpr = (CaseExpr *) node;
5112                                 ListCell   *temp;
5113
5114                                 appendContextKeyword(context, "CASE",
5115                                                                          0, PRETTYINDENT_VAR, 0);
5116                                 if (caseexpr->arg)
5117                                 {
5118                                         appendStringInfoChar(buf, ' ');
5119                                         get_rule_expr((Node *) caseexpr->arg, context, true);
5120                                 }
5121                                 foreach(temp, caseexpr->args)
5122                                 {
5123                                         CaseWhen   *when = (CaseWhen *) lfirst(temp);
5124                                         Node       *w = (Node *) when->expr;
5125
5126                                         if (!PRETTY_INDENT(context))
5127                                                 appendStringInfoChar(buf, ' ');
5128                                         appendContextKeyword(context, "WHEN ",
5129                                                                                  0, 0, 0);
5130                                         if (caseexpr->arg)
5131                                         {
5132                                                 /*
5133                                                  * The parser should have produced WHEN clauses of the
5134                                                  * form "CaseTestExpr = RHS"; we want to show just the
5135                                                  * RHS.  If the user wrote something silly like "CASE
5136                                                  * boolexpr WHEN TRUE THEN ...", then the optimizer's
5137                                                  * simplify_boolean_equality() may have reduced this
5138                                                  * to just "CaseTestExpr" or "NOT CaseTestExpr", for
5139                                                  * which we have to show "TRUE" or "FALSE".  Also,
5140                                                  * depending on context the original CaseTestExpr
5141                                                  * might have been reduced to a Const (but we won't
5142                                                  * see "WHEN Const").  We have also to consider the
5143                                                  * possibility that an implicit coercion was inserted
5144                                                  * between the CaseTestExpr and the operator.
5145                                                  */
5146                                                 if (IsA(w, OpExpr))
5147                                                 {
5148                                                         List       *args = ((OpExpr *) w)->args;
5149                                                         Node       *lhs;
5150                                                         Node       *rhs;
5151
5152                                                         Assert(list_length(args) == 2);
5153                                                         lhs = strip_implicit_coercions(linitial(args));
5154                                                         Assert(IsA(lhs, CaseTestExpr) ||
5155                                                                    IsA(lhs, Const));
5156                                                         rhs = (Node *) lsecond(args);
5157                                                         get_rule_expr(rhs, context, false);
5158                                                 }
5159                                                 else if (IsA(strip_implicit_coercions(w),
5160                                                                          CaseTestExpr))
5161                                                         appendStringInfo(buf, "TRUE");
5162                                                 else if (not_clause(w))
5163                                                 {
5164                                                         Assert(IsA(strip_implicit_coercions((Node *) get_notclausearg((Expr *) w)),
5165                                                                            CaseTestExpr));
5166                                                         appendStringInfo(buf, "FALSE");
5167                                                 }
5168                                                 else
5169                                                         elog(ERROR, "unexpected CASE WHEN clause: %d",
5170                                                                  (int) nodeTag(w));
5171                                         }
5172                                         else
5173                                                 get_rule_expr(w, context, false);
5174                                         appendStringInfo(buf, " THEN ");
5175                                         get_rule_expr((Node *) when->result, context, true);
5176                                 }
5177                                 if (!PRETTY_INDENT(context))
5178                                         appendStringInfoChar(buf, ' ');
5179                                 appendContextKeyword(context, "ELSE ",
5180                                                                          0, 0, 0);
5181                                 get_rule_expr((Node *) caseexpr->defresult, context, true);
5182                                 if (!PRETTY_INDENT(context))
5183                                         appendStringInfoChar(buf, ' ');
5184                                 appendContextKeyword(context, "END",
5185                                                                          -PRETTYINDENT_VAR, 0, 0);
5186                         }
5187                         break;
5188
5189                 case T_ArrayExpr:
5190                         {
5191                                 ArrayExpr  *arrayexpr = (ArrayExpr *) node;
5192
5193                                 appendStringInfo(buf, "ARRAY[");
5194                                 get_rule_expr((Node *) arrayexpr->elements, context, true);
5195                                 appendStringInfoChar(buf, ']');
5196
5197                                 /*
5198                                  * If the array isn't empty, we assume its elements are
5199                                  * coerced to the desired type.  If it's empty, though, we
5200                                  * need an explicit coercion to the array type.
5201                                  */
5202                                 if (arrayexpr->elements == NIL)
5203                                         appendStringInfo(buf, "::%s",
5204                                           format_type_with_typemod(arrayexpr->array_typeid, -1));
5205                         }
5206                         break;
5207
5208                 case T_RowExpr:
5209                         {
5210                                 RowExpr    *rowexpr = (RowExpr *) node;
5211                                 TupleDesc       tupdesc = NULL;
5212                                 ListCell   *arg;
5213                                 int                     i;
5214                                 char       *sep;
5215
5216                                 /*
5217                                  * If it's a named type and not RECORD, we may have to skip
5218                                  * dropped columns and/or claim there are NULLs for added
5219                                  * columns.
5220                                  */
5221                                 if (rowexpr->row_typeid != RECORDOID)
5222                                 {
5223                                         tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
5224                                         Assert(list_length(rowexpr->args) <= tupdesc->natts);
5225                                 }
5226
5227                                 /*
5228                                  * SQL99 allows "ROW" to be omitted when there is more than
5229                                  * one column, but for simplicity we always print it.
5230                                  */
5231                                 appendStringInfo(buf, "ROW(");
5232                                 sep = "";
5233                                 i = 0;
5234                                 foreach(arg, rowexpr->args)
5235                                 {
5236                                         Node       *e = (Node *) lfirst(arg);
5237
5238                                         if (tupdesc == NULL ||
5239                                                 !tupdesc->attrs[i]->attisdropped)
5240                                         {
5241                                                 appendStringInfoString(buf, sep);
5242                                                 get_rule_expr(e, context, true);
5243                                                 sep = ", ";
5244                                         }
5245                                         i++;
5246                                 }
5247                                 if (tupdesc != NULL)
5248                                 {
5249                                         while (i < tupdesc->natts)
5250                                         {
5251                                                 if (!tupdesc->attrs[i]->attisdropped)
5252                                                 {
5253                                                         appendStringInfoString(buf, sep);
5254                                                         appendStringInfo(buf, "NULL");
5255                                                         sep = ", ";
5256                                                 }
5257                                                 i++;
5258                                         }
5259
5260                                         ReleaseTupleDesc(tupdesc);
5261                                 }
5262                                 appendStringInfo(buf, ")");
5263                                 if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
5264                                         appendStringInfo(buf, "::%s",
5265                                                   format_type_with_typemod(rowexpr->row_typeid, -1));
5266                         }
5267                         break;
5268
5269                 case T_RowCompareExpr:
5270                         {
5271                                 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
5272                                 ListCell   *arg;
5273                                 char       *sep;
5274
5275                                 /*
5276                                  * SQL99 allows "ROW" to be omitted when there is more than
5277                                  * one column, but for simplicity we always print it.
5278                                  */
5279                                 appendStringInfo(buf, "(ROW(");
5280                                 sep = "";
5281                                 foreach(arg, rcexpr->largs)
5282                                 {
5283                                         Node       *e = (Node *) lfirst(arg);
5284
5285                                         appendStringInfoString(buf, sep);
5286                                         get_rule_expr(e, context, true);
5287                                         sep = ", ";
5288                                 }
5289
5290                                 /*
5291                                  * We assume that the name of the first-column operator will
5292                                  * do for all the rest too.  This is definitely open to
5293                                  * failure, eg if some but not all operators were renamed
5294                                  * since the construct was parsed, but there seems no way to
5295                                  * be perfect.
5296                                  */
5297                                 appendStringInfo(buf, ") %s ROW(",
5298                                                   generate_operator_name(linitial_oid(rcexpr->opnos),
5299                                                                                    exprType(linitial(rcexpr->largs)),
5300                                                                                  exprType(linitial(rcexpr->rargs))));
5301                                 sep = "";
5302                                 foreach(arg, rcexpr->rargs)
5303                                 {
5304                                         Node       *e = (Node *) lfirst(arg);
5305
5306                                         appendStringInfoString(buf, sep);
5307                                         get_rule_expr(e, context, true);
5308                                         sep = ", ";
5309                                 }
5310                                 appendStringInfo(buf, "))");
5311                         }
5312                         break;
5313
5314                 case T_CoalesceExpr:
5315                         {
5316                                 CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
5317
5318                                 appendStringInfo(buf, "COALESCE(");
5319                                 get_rule_expr((Node *) coalesceexpr->args, context, true);
5320                                 appendStringInfoChar(buf, ')');
5321                         }
5322                         break;
5323
5324                 case T_MinMaxExpr:
5325                         {
5326                                 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
5327
5328                                 switch (minmaxexpr->op)
5329                                 {
5330                                         case IS_GREATEST:
5331                                                 appendStringInfo(buf, "GREATEST(");
5332                                                 break;
5333                                         case IS_LEAST:
5334                                                 appendStringInfo(buf, "LEAST(");
5335                                                 break;
5336                                 }
5337                                 get_rule_expr((Node *) minmaxexpr->args, context, true);
5338                                 appendStringInfoChar(buf, ')');
5339                         }
5340                         break;
5341
5342                 case T_XmlExpr:
5343                         {
5344                                 XmlExpr    *xexpr = (XmlExpr *) node;
5345                                 bool            needcomma = false;
5346                                 ListCell   *arg;
5347                                 ListCell   *narg;
5348                                 Const      *con;
5349
5350                                 switch (xexpr->op)
5351                                 {
5352                                         case IS_XMLCONCAT:
5353                                                 appendStringInfoString(buf, "XMLCONCAT(");
5354                                                 break;
5355                                         case IS_XMLELEMENT:
5356                                                 appendStringInfoString(buf, "XMLELEMENT(");
5357                                                 break;
5358                                         case IS_XMLFOREST:
5359                                                 appendStringInfoString(buf, "XMLFOREST(");
5360                                                 break;
5361                                         case IS_XMLPARSE:
5362                                                 appendStringInfoString(buf, "XMLPARSE(");
5363                                                 break;
5364                                         case IS_XMLPI:
5365                                                 appendStringInfoString(buf, "XMLPI(");
5366                                                 break;
5367                                         case IS_XMLROOT:
5368                                                 appendStringInfoString(buf, "XMLROOT(");
5369                                                 break;
5370                                         case IS_XMLSERIALIZE:
5371                                                 appendStringInfoString(buf, "XMLSERIALIZE(");
5372                                                 break;
5373                                         case IS_DOCUMENT:
5374                                                 break;
5375                                 }
5376                                 if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
5377                                 {
5378                                         if (xexpr->xmloption == XMLOPTION_DOCUMENT)
5379                                                 appendStringInfoString(buf, "DOCUMENT ");
5380                                         else
5381                                                 appendStringInfoString(buf, "CONTENT ");
5382                                 }
5383                                 if (xexpr->name)
5384                                 {
5385                                         appendStringInfo(buf, "NAME %s",
5386                                                                          quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
5387                                         needcomma = true;
5388                                 }
5389                                 if (xexpr->named_args)
5390                                 {
5391                                         if (xexpr->op != IS_XMLFOREST)
5392                                         {
5393                                                 if (needcomma)
5394                                                         appendStringInfoString(buf, ", ");
5395                                                 appendStringInfoString(buf, "XMLATTRIBUTES(");
5396                                                 needcomma = false;
5397                                         }
5398                                         forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
5399                                         {
5400                                                 Node       *e = (Node *) lfirst(arg);
5401                                                 char       *argname = strVal(lfirst(narg));
5402
5403                                                 if (needcomma)
5404                                                         appendStringInfoString(buf, ", ");
5405                                                 get_rule_expr((Node *) e, context, true);
5406                                                 appendStringInfo(buf, " AS %s",
5407                                                                                  quote_identifier(map_xml_name_to_sql_identifier(argname)));
5408                                                 needcomma = true;
5409                                         }
5410                                         if (xexpr->op != IS_XMLFOREST)
5411                                                 appendStringInfoChar(buf, ')');
5412                                 }
5413                                 if (xexpr->args)
5414                                 {
5415                                         if (needcomma)
5416                                                 appendStringInfoString(buf, ", ");
5417                                         switch (xexpr->op)
5418                                         {
5419                                                 case IS_XMLCONCAT:
5420                                                 case IS_XMLELEMENT:
5421                                                 case IS_XMLFOREST:
5422                                                 case IS_XMLPI:
5423                                                 case IS_XMLSERIALIZE:
5424                                                         /* no extra decoration needed */
5425                                                         get_rule_expr((Node *) xexpr->args, context, true);
5426                                                         break;
5427                                                 case IS_XMLPARSE:
5428                                                         Assert(list_length(xexpr->args) == 2);
5429
5430                                                         get_rule_expr((Node *) linitial(xexpr->args),
5431                                                                                   context, true);
5432
5433                                                         con = (Const *) lsecond(xexpr->args);
5434                                                         Assert(IsA(con, Const));
5435                                                         Assert(!con->constisnull);
5436                                                         if (DatumGetBool(con->constvalue))
5437                                                                 appendStringInfoString(buf,
5438                                                                                                          " PRESERVE WHITESPACE");
5439                                                         else
5440                                                                 appendStringInfoString(buf,
5441                                                                                                            " STRIP WHITESPACE");
5442                                                         break;
5443                                                 case IS_XMLROOT:
5444                                                         Assert(list_length(xexpr->args) == 3);
5445
5446                                                         get_rule_expr((Node *) linitial(xexpr->args),
5447                                                                                   context, true);
5448
5449                                                         appendStringInfoString(buf, ", VERSION ");
5450                                                         con = (Const *) lsecond(xexpr->args);
5451                                                         if (IsA(con, Const) &&
5452                                                                 con->constisnull)
5453                                                                 appendStringInfoString(buf, "NO VALUE");
5454                                                         else
5455                                                                 get_rule_expr((Node *) con, context, false);
5456
5457                                                         con = (Const *) lthird(xexpr->args);
5458                                                         Assert(IsA(con, Const));
5459                                                         if (con->constisnull)
5460                                                                  /* suppress STANDALONE NO VALUE */ ;
5461                                                         else
5462                                                         {
5463                                                                 switch (DatumGetInt32(con->constvalue))
5464                                                                 {
5465                                                                         case XML_STANDALONE_YES:
5466                                                                                 appendStringInfoString(buf,
5467                                                                                                                  ", STANDALONE YES");
5468                                                                                 break;
5469                                                                         case XML_STANDALONE_NO:
5470                                                                                 appendStringInfoString(buf,
5471                                                                                                                   ", STANDALONE NO");
5472                                                                                 break;
5473                                                                         case XML_STANDALONE_NO_VALUE:
5474                                                                                 appendStringInfoString(buf,
5475                                                                                                         ", STANDALONE NO VALUE");
5476                                                                                 break;
5477                                                                         default:
5478                                                                                 break;
5479                                                                 }
5480                                                         }
5481                                                         break;
5482                                                 case IS_DOCUMENT:
5483                                                         get_rule_expr_paren((Node *) xexpr->args, context, false, node);
5484                                                         break;
5485                                         }
5486
5487                                 }
5488                                 if (xexpr->op == IS_XMLSERIALIZE)
5489                                         appendStringInfo(buf, " AS %s", format_type_with_typemod(xexpr->type,
5490                                                                                                                          xexpr->typmod));
5491                                 if (xexpr->op == IS_DOCUMENT)
5492                                         appendStringInfoString(buf, " IS DOCUMENT");
5493                                 else
5494                                         appendStringInfoChar(buf, ')');
5495                         }
5496                         break;
5497
5498                 case T_NullIfExpr:
5499                         {
5500                                 NullIfExpr *nullifexpr = (NullIfExpr *) node;
5501
5502                                 appendStringInfo(buf, "NULLIF(");
5503                                 get_rule_expr((Node *) nullifexpr->args, context, true);
5504                                 appendStringInfoChar(buf, ')');
5505                         }
5506                         break;
5507
5508                 case T_NullTest:
5509                         {
5510                                 NullTest   *ntest = (NullTest *) node;
5511
5512                                 if (!PRETTY_PAREN(context))
5513                                         appendStringInfoChar(buf, '(');
5514                                 get_rule_expr_paren((Node *) ntest->arg, context, true, node);
5515                                 switch (ntest->nulltesttype)
5516                                 {
5517                                         case IS_NULL:
5518                                                 appendStringInfo(buf, " IS NULL");
5519                                                 break;
5520                                         case IS_NOT_NULL:
5521                                                 appendStringInfo(buf, " IS NOT NULL");
5522                                                 break;
5523                                         default:
5524                                                 elog(ERROR, "unrecognized nulltesttype: %d",
5525                                                          (int) ntest->nulltesttype);
5526                                 }
5527                                 if (!PRETTY_PAREN(context))
5528                                         appendStringInfoChar(buf, ')');
5529                         }
5530                         break;
5531
5532                 case T_BooleanTest:
5533                         {
5534                                 BooleanTest *btest = (BooleanTest *) node;
5535
5536                                 if (!PRETTY_PAREN(context))
5537                                         appendStringInfoChar(buf, '(');
5538                                 get_rule_expr_paren((Node *) btest->arg, context, false, node);
5539                                 switch (btest->booltesttype)
5540                                 {
5541                                         case IS_TRUE:
5542                                                 appendStringInfo(buf, " IS TRUE");
5543                                                 break;
5544                                         case IS_NOT_TRUE:
5545                                                 appendStringInfo(buf, " IS NOT TRUE");
5546                                                 break;
5547                                         case IS_FALSE:
5548                                                 appendStringInfo(buf, " IS FALSE");
5549                                                 break;
5550                                         case IS_NOT_FALSE:
5551                                                 appendStringInfo(buf, " IS NOT FALSE");
5552                                                 break;
5553                                         case IS_UNKNOWN:
5554                                                 appendStringInfo(buf, " IS UNKNOWN");
5555                                                 break;
5556                                         case IS_NOT_UNKNOWN:
5557                                                 appendStringInfo(buf, " IS NOT UNKNOWN");
5558                                                 break;
5559                                         default:
5560                                                 elog(ERROR, "unrecognized booltesttype: %d",
5561                                                          (int) btest->booltesttype);
5562                                 }
5563                                 if (!PRETTY_PAREN(context))
5564                                         appendStringInfoChar(buf, ')');
5565                         }
5566                         break;
5567
5568                 case T_CoerceToDomain:
5569                         {
5570                                 CoerceToDomain *ctest = (CoerceToDomain *) node;
5571                                 Node       *arg = (Node *) ctest->arg;
5572
5573                                 if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
5574                                         !showimplicit)
5575                                 {
5576                                         /* don't show the implicit cast */
5577                                         get_rule_expr(arg, context, false);
5578                                 }
5579                                 else
5580                                 {
5581                                         get_coercion_expr(arg, context,
5582                                                                           ctest->resulttype,
5583                                                                           ctest->resulttypmod,
5584                                                                           node);
5585                                 }
5586                         }
5587                         break;
5588
5589                 case T_CoerceToDomainValue:
5590                         appendStringInfo(buf, "VALUE");
5591                         break;
5592
5593                 case T_SetToDefault:
5594                         appendStringInfo(buf, "DEFAULT");
5595                         break;
5596
5597                 case T_CurrentOfExpr:
5598                         {
5599                                 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
5600
5601                                 if (cexpr->cursor_name)
5602                                         appendStringInfo(buf, "CURRENT OF %s",
5603                                                                          quote_identifier(cexpr->cursor_name));
5604                                 else
5605                                         appendStringInfo(buf, "CURRENT OF $%d",
5606                                                                          cexpr->cursor_param);
5607                         }
5608                         break;
5609
5610                 case T_List:
5611                         {
5612                                 char       *sep;
5613                                 ListCell   *l;
5614
5615                                 sep = "";
5616                                 foreach(l, (List *) node)
5617                                 {
5618                                         appendStringInfoString(buf, sep);
5619                                         get_rule_expr((Node *) lfirst(l), context, showimplicit);
5620                                         sep = ", ";
5621                                 }
5622                         }
5623                         break;
5624
5625                 default:
5626                         elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
5627                         break;
5628         }
5629 }
5630
5631
5632 /*
5633  * get_oper_expr                        - Parse back an OpExpr node
5634  */
5635 static void
5636 get_oper_expr(OpExpr *expr, deparse_context *context)
5637 {
5638         StringInfo      buf = context->buf;
5639         Oid                     opno = expr->opno;
5640         List       *args = expr->args;
5641
5642         if (!PRETTY_PAREN(context))
5643                 appendStringInfoChar(buf, '(');
5644         if (list_length(args) == 2)
5645         {
5646                 /* binary operator */
5647                 Node       *arg1 = (Node *) linitial(args);
5648                 Node       *arg2 = (Node *) lsecond(args);
5649
5650                 get_rule_expr_paren(arg1, context, true, (Node *) expr);
5651                 appendStringInfo(buf, " %s ",
5652                                                  generate_operator_name(opno,
5653                                                                                                 exprType(arg1),
5654                                                                                                 exprType(arg2)));
5655                 get_rule_expr_paren(arg2, context, true, (Node *) expr);
5656         }
5657         else
5658         {
5659                 /* unary operator --- but which side? */
5660                 Node       *arg = (Node *) linitial(args);
5661                 HeapTuple       tp;
5662                 Form_pg_operator optup;
5663
5664                 tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
5665                 if (!HeapTupleIsValid(tp))
5666                         elog(ERROR, "cache lookup failed for operator %u", opno);
5667                 optup = (Form_pg_operator) GETSTRUCT(tp);
5668                 switch (optup->oprkind)
5669                 {
5670                         case 'l':
5671                                 appendStringInfo(buf, "%s ",
5672                                                                  generate_operator_name(opno,
5673                                                                                                                 InvalidOid,
5674                                                                                                                 exprType(arg)));
5675                                 get_rule_expr_paren(arg, context, true, (Node *) expr);
5676                                 break;
5677                         case 'r':
5678                                 get_rule_expr_paren(arg, context, true, (Node *) expr);
5679                                 appendStringInfo(buf, " %s",
5680                                                                  generate_operator_name(opno,
5681                                                                                                                 exprType(arg),
5682                                                                                                                 InvalidOid));
5683                                 break;
5684                         default:
5685                                 elog(ERROR, "bogus oprkind: %d", optup->oprkind);
5686                 }
5687                 ReleaseSysCache(tp);
5688         }
5689         if (!PRETTY_PAREN(context))
5690                 appendStringInfoChar(buf, ')');
5691 }
5692
5693 /*
5694  * get_func_expr                        - Parse back a FuncExpr node
5695  */
5696 static void
5697 get_func_expr(FuncExpr *expr, deparse_context *context,
5698                           bool showimplicit)
5699 {
5700         StringInfo      buf = context->buf;
5701         Oid                     funcoid = expr->funcid;
5702         Oid                     argtypes[FUNC_MAX_ARGS];
5703         int                     nargs;
5704         List       *argnames;
5705         bool            is_variadic;
5706         ListCell   *l;
5707
5708         /*
5709          * If the function call came from an implicit coercion, then just show the
5710          * first argument --- unless caller wants to see implicit coercions.
5711          */
5712         if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
5713         {
5714                 get_rule_expr_paren((Node *) linitial(expr->args), context,
5715                                                         false, (Node *) expr);
5716                 return;
5717         }
5718
5719         /*
5720          * If the function call came from a cast, then show the first argument
5721          * plus an explicit cast operation.
5722          */
5723         if (expr->funcformat == COERCE_EXPLICIT_CAST ||
5724                 expr->funcformat == COERCE_IMPLICIT_CAST)
5725         {
5726                 Node       *arg = linitial(expr->args);
5727                 Oid                     rettype = expr->funcresulttype;
5728                 int32           coercedTypmod;
5729
5730                 /* Get the typmod if this is a length-coercion function */
5731                 (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
5732
5733                 get_coercion_expr(arg, context,
5734                                                   rettype, coercedTypmod,
5735                                                   (Node *) expr);
5736
5737                 return;
5738         }
5739
5740         /*
5741          * Normal function: display as proname(args).  First we need to extract
5742          * the argument datatypes.
5743          */
5744         if (list_length(expr->args) > FUNC_MAX_ARGS)
5745                 ereport(ERROR,
5746                                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5747                                  errmsg("too many arguments")));
5748         nargs = 0;
5749         argnames = NIL;
5750         foreach(l, expr->args)
5751         {
5752                 Node       *arg = (Node *) lfirst(l);
5753
5754                 if (IsA(arg, NamedArgExpr))
5755                         argnames = lappend(argnames, ((NamedArgExpr *) arg)->name);
5756                 argtypes[nargs] = exprType(arg);
5757                 nargs++;
5758         }
5759
5760         appendStringInfo(buf, "%s(",
5761                                          generate_function_name(funcoid, nargs,
5762                                                                                         argnames, argtypes,
5763                                                                                         &is_variadic));
5764         nargs = 0;
5765         foreach(l, expr->args)
5766         {
5767                 if (nargs++ > 0)
5768                         appendStringInfoString(buf, ", ");
5769                 if (is_variadic && lnext(l) == NULL)
5770                         appendStringInfoString(buf, "VARIADIC ");
5771                 get_rule_expr((Node *) lfirst(l), context, true);
5772         }
5773         appendStringInfoChar(buf, ')');
5774 }
5775
5776 /*
5777  * get_agg_expr                 - Parse back an Aggref node
5778  */
5779 static void
5780 get_agg_expr(Aggref *aggref, deparse_context *context)
5781 {
5782         StringInfo      buf = context->buf;
5783         Oid                     argtypes[FUNC_MAX_ARGS];
5784         List       *arglist;
5785         int                     nargs;
5786         ListCell   *l;
5787
5788         /* Extract the regular arguments, ignoring resjunk stuff for the moment */
5789         arglist = NIL;
5790         nargs = 0;
5791         foreach(l, aggref->args)
5792         {
5793                 TargetEntry *tle = (TargetEntry *) lfirst(l);
5794                 Node       *arg = (Node *) tle->expr;
5795
5796                 Assert(!IsA(arg, NamedArgExpr));
5797                 if (tle->resjunk)
5798                         continue;
5799                 if (nargs >= FUNC_MAX_ARGS)             /* paranoia */
5800                         ereport(ERROR,
5801                                         (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5802                                          errmsg("too many arguments")));
5803                 argtypes[nargs] = exprType(arg);
5804                 arglist = lappend(arglist, arg);
5805                 nargs++;
5806         }
5807
5808         appendStringInfo(buf, "%s(%s",
5809                                          generate_function_name(aggref->aggfnoid, nargs,
5810                                                                                         NIL, argtypes, NULL),
5811                                          (aggref->aggdistinct != NIL) ? "DISTINCT " : "");
5812         /* aggstar can be set only in zero-argument aggregates */
5813         if (aggref->aggstar)
5814                 appendStringInfoChar(buf, '*');
5815         else
5816                 get_rule_expr((Node *) arglist, context, true);
5817         if (aggref->aggorder != NIL)
5818         {
5819                 appendStringInfoString(buf, " ORDER BY ");
5820                 get_rule_orderby(aggref->aggorder, aggref->args, false, context);
5821         }
5822         appendStringInfoChar(buf, ')');
5823 }
5824
5825 /*
5826  * get_windowfunc_expr  - Parse back a WindowFunc node
5827  */
5828 static void
5829 get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
5830 {
5831         StringInfo      buf = context->buf;
5832         Oid                     argtypes[FUNC_MAX_ARGS];
5833         int                     nargs;
5834         ListCell   *l;
5835
5836         if (list_length(wfunc->args) > FUNC_MAX_ARGS)
5837                 ereport(ERROR,
5838                                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5839                                  errmsg("too many arguments")));
5840         nargs = 0;
5841         foreach(l, wfunc->args)
5842         {
5843                 Node       *arg = (Node *) lfirst(l);
5844
5845                 Assert(!IsA(arg, NamedArgExpr));
5846                 argtypes[nargs] = exprType(arg);
5847                 nargs++;
5848         }
5849
5850         appendStringInfo(buf, "%s(",
5851                                          generate_function_name(wfunc->winfnoid, nargs,
5852                                                                                         NIL, argtypes, NULL));
5853         /* winstar can be set only in zero-argument aggregates */
5854         if (wfunc->winstar)
5855                 appendStringInfoChar(buf, '*');
5856         else
5857                 get_rule_expr((Node *) wfunc->args, context, true);
5858         appendStringInfoString(buf, ") OVER ");
5859
5860         foreach(l, context->windowClause)
5861         {
5862                 WindowClause *wc = (WindowClause *) lfirst(l);
5863
5864                 if (wc->winref == wfunc->winref)
5865                 {
5866                         if (wc->name)
5867                                 appendStringInfoString(buf, quote_identifier(wc->name));
5868                         else
5869                                 get_rule_windowspec(wc, context->windowTList, context);
5870                         break;
5871                 }
5872         }
5873         if (l == NULL)
5874         {
5875                 if (context->windowClause)
5876                         elog(ERROR, "could not find window clause for winref %u",
5877                                  wfunc->winref);
5878
5879                 /*
5880                  * In EXPLAIN, we don't have window context information available, so
5881                  * we have to settle for this:
5882                  */
5883                 appendStringInfoString(buf, "(?)");
5884         }
5885 }
5886
5887 /* ----------
5888  * get_coercion_expr
5889  *
5890  *      Make a string representation of a value coerced to a specific type
5891  * ----------
5892  */
5893 static void
5894 get_coercion_expr(Node *arg, deparse_context *context,
5895                                   Oid resulttype, int32 resulttypmod,
5896                                   Node *parentNode)
5897 {
5898         StringInfo      buf = context->buf;
5899
5900         /*
5901          * Since parse_coerce.c doesn't immediately collapse application of
5902          * length-coercion functions to constants, what we'll typically see in
5903          * such cases is a Const with typmod -1 and a length-coercion function
5904          * right above it.      Avoid generating redundant output. However, beware of
5905          * suppressing casts when the user actually wrote something like
5906          * 'foo'::text::char(3).
5907          */
5908         if (arg && IsA(arg, Const) &&
5909                 ((Const *) arg)->consttype == resulttype &&
5910                 ((Const *) arg)->consttypmod == -1)
5911         {
5912                 /* Show the constant without normal ::typename decoration */
5913                 get_const_expr((Const *) arg, context, -1);
5914         }
5915         else
5916         {
5917                 if (!PRETTY_PAREN(context))
5918                         appendStringInfoChar(buf, '(');
5919                 get_rule_expr_paren(arg, context, false, parentNode);
5920                 if (!PRETTY_PAREN(context))
5921                         appendStringInfoChar(buf, ')');
5922         }
5923         appendStringInfo(buf, "::%s",
5924                                          format_type_with_typemod(resulttype, resulttypmod));
5925 }
5926
5927 /* ----------
5928  * get_const_expr
5929  *
5930  *      Make a string representation of a Const
5931  *
5932  * showtype can be -1 to never show "::typename" decoration, or +1 to always
5933  * show it, or 0 to show it only if the constant wouldn't be assumed to be
5934  * the right type by default.
5935  * ----------
5936  */
5937 static void
5938 get_const_expr(Const *constval, deparse_context *context, int showtype)
5939 {
5940         StringInfo      buf = context->buf;
5941         Oid                     typoutput;
5942         bool            typIsVarlena;
5943         char       *extval;
5944         bool            isfloat = false;
5945         bool            needlabel;
5946
5947         if (constval->constisnull)
5948         {
5949                 /*
5950                  * Always label the type of a NULL constant to prevent misdecisions
5951                  * about type when reparsing.
5952                  */
5953                 appendStringInfo(buf, "NULL");
5954                 if (showtype >= 0)
5955                         appendStringInfo(buf, "::%s",
5956                                                          format_type_with_typemod(constval->consttype,
5957                                                                                                           constval->consttypmod));
5958                 return;
5959         }
5960
5961         getTypeOutputInfo(constval->consttype,
5962                                           &typoutput, &typIsVarlena);
5963
5964         extval = OidOutputFunctionCall(typoutput, constval->constvalue);
5965
5966         switch (constval->consttype)
5967         {
5968                 case INT2OID:
5969                 case INT4OID:
5970                 case INT8OID:
5971                 case OIDOID:
5972                 case FLOAT4OID:
5973                 case FLOAT8OID:
5974                 case NUMERICOID:
5975                         {
5976                                 /*
5977                                  * These types are printed without quotes unless they contain
5978                                  * values that aren't accepted by the scanner unquoted (e.g.,
5979                                  * 'NaN').      Note that strtod() and friends might accept NaN,
5980                                  * so we can't use that to test.
5981                                  *
5982                                  * In reality we only need to defend against infinity and NaN,
5983                                  * so we need not get too crazy about pattern matching here.
5984                                  *
5985                                  * There is a special-case gotcha: if the constant is signed,
5986                                  * we need to parenthesize it, else the parser might see a
5987                                  * leading plus/minus as binding less tightly than adjacent
5988                                  * operators --- particularly, the cast that we might attach
5989                                  * below.
5990                                  */
5991                                 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
5992                                 {
5993                                         if (extval[0] == '+' || extval[0] == '-')
5994                                                 appendStringInfo(buf, "(%s)", extval);
5995                                         else
5996                                                 appendStringInfoString(buf, extval);
5997                                         if (strcspn(extval, "eE.") != strlen(extval))
5998                                                 isfloat = true; /* it looks like a float */
5999                                 }
6000                                 else
6001                                         appendStringInfo(buf, "'%s'", extval);
6002                         }
6003                         break;
6004
6005                 case BITOID:
6006                 case VARBITOID:
6007                         appendStringInfo(buf, "B'%s'", extval);
6008                         break;
6009
6010                 case BOOLOID:
6011                         if (strcmp(extval, "t") == 0)
6012                                 appendStringInfo(buf, "true");
6013                         else
6014                                 appendStringInfo(buf, "false");
6015                         break;
6016
6017                 default:
6018                         simple_quote_literal(buf, extval);
6019                         break;
6020         }
6021
6022         pfree(extval);
6023
6024         if (showtype < 0)
6025                 return;
6026
6027         /*
6028          * For showtype == 0, append ::typename unless the constant will be
6029          * implicitly typed as the right type when it is read in.
6030          *
6031          * XXX this code has to be kept in sync with the behavior of the parser,
6032          * especially make_const.
6033          */
6034         switch (constval->consttype)
6035         {
6036                 case BOOLOID:
6037                 case INT4OID:
6038                 case UNKNOWNOID:
6039                         /* These types can be left unlabeled */
6040                         needlabel = false;
6041                         break;
6042                 case NUMERICOID:
6043
6044                         /*
6045                          * Float-looking constants will be typed as numeric, but if
6046                          * there's a specific typmod we need to show it.
6047                          */
6048                         needlabel = !isfloat || (constval->consttypmod >= 0);
6049                         break;
6050                 default:
6051                         needlabel = true;
6052                         break;
6053         }
6054         if (needlabel || showtype > 0)
6055                 appendStringInfo(buf, "::%s",
6056                                                  format_type_with_typemod(constval->consttype,
6057                                                                                                   constval->consttypmod));
6058 }
6059
6060 /*
6061  * simple_quote_literal - Format a string as a SQL literal, append to buf
6062  */
6063 static void
6064 simple_quote_literal(StringInfo buf, const char *val)
6065 {
6066         const char *valptr;
6067
6068         /*
6069          * We form the string literal according to the prevailing setting of
6070          * standard_conforming_strings; we never use E''. User is responsible for
6071          * making sure result is used correctly.
6072          */
6073         appendStringInfoChar(buf, '\'');
6074         for (valptr = val; *valptr; valptr++)
6075         {
6076                 char            ch = *valptr;
6077
6078                 if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
6079                         appendStringInfoChar(buf, ch);
6080                 appendStringInfoChar(buf, ch);
6081         }
6082         appendStringInfoChar(buf, '\'');
6083 }
6084
6085
6086 /* ----------
6087  * get_sublink_expr                     - Parse back a sublink
6088  * ----------
6089  */
6090 static void
6091 get_sublink_expr(SubLink *sublink, deparse_context *context)
6092 {
6093         StringInfo      buf = context->buf;
6094         Query      *query = (Query *) (sublink->subselect);
6095         char       *opname = NULL;
6096         bool            need_paren;
6097
6098         if (sublink->subLinkType == ARRAY_SUBLINK)
6099                 appendStringInfo(buf, "ARRAY(");
6100         else
6101                 appendStringInfoChar(buf, '(');
6102
6103         /*
6104          * Note that we print the name of only the first operator, when there are
6105          * multiple combining operators.  This is an approximation that could go
6106          * wrong in various scenarios (operators in different schemas, renamed
6107          * operators, etc) but there is not a whole lot we can do about it, since
6108          * the syntax allows only one operator to be shown.
6109          */
6110         if (sublink->testexpr)
6111         {
6112                 if (IsA(sublink->testexpr, OpExpr))
6113                 {
6114                         /* single combining operator */
6115                         OpExpr     *opexpr = (OpExpr *) sublink->testexpr;
6116
6117                         get_rule_expr(linitial(opexpr->args), context, true);
6118                         opname = generate_operator_name(opexpr->opno,
6119                                                                                         exprType(linitial(opexpr->args)),
6120                                                                                         exprType(lsecond(opexpr->args)));
6121                 }
6122                 else if (IsA(sublink->testexpr, BoolExpr))
6123                 {
6124                         /* multiple combining operators, = or <> cases */
6125                         char       *sep;
6126                         ListCell   *l;
6127
6128                         appendStringInfoChar(buf, '(');
6129                         sep = "";
6130                         foreach(l, ((BoolExpr *) sublink->testexpr)->args)
6131                         {
6132                                 OpExpr     *opexpr = (OpExpr *) lfirst(l);
6133
6134                                 Assert(IsA(opexpr, OpExpr));
6135                                 appendStringInfoString(buf, sep);
6136                                 get_rule_expr(linitial(opexpr->args), context, true);
6137                                 if (!opname)
6138                                         opname = generate_operator_name(opexpr->opno,
6139                                                                                         exprType(linitial(opexpr->args)),
6140                                                                                         exprType(lsecond(opexpr->args)));
6141                                 sep = ", ";
6142                         }
6143                         appendStringInfoChar(buf, ')');
6144                 }
6145                 else if (IsA(sublink->testexpr, RowCompareExpr))
6146                 {
6147                         /* multiple combining operators, < <= > >= cases */
6148                         RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
6149
6150                         appendStringInfoChar(buf, '(');
6151                         get_rule_expr((Node *) rcexpr->largs, context, true);
6152                         opname = generate_operator_name(linitial_oid(rcexpr->opnos),
6153                                                                                         exprType(linitial(rcexpr->largs)),
6154                                                                                   exprType(linitial(rcexpr->rargs)));
6155                         appendStringInfoChar(buf, ')');
6156                 }
6157                 else
6158                         elog(ERROR, "unrecognized testexpr type: %d",
6159                                  (int) nodeTag(sublink->testexpr));
6160         }
6161
6162         need_paren = true;
6163
6164         switch (sublink->subLinkType)
6165         {
6166                 case EXISTS_SUBLINK:
6167                         appendStringInfo(buf, "EXISTS ");
6168                         break;
6169
6170                 case ANY_SUBLINK:
6171                         if (strcmp(opname, "=") == 0)           /* Represent = ANY as IN */
6172                                 appendStringInfo(buf, " IN ");
6173                         else
6174                                 appendStringInfo(buf, " %s ANY ", opname);
6175                         break;
6176
6177                 case ALL_SUBLINK:
6178                         appendStringInfo(buf, " %s ALL ", opname);
6179                         break;
6180
6181                 case ROWCOMPARE_SUBLINK:
6182                         appendStringInfo(buf, " %s ", opname);
6183                         break;
6184
6185                 case EXPR_SUBLINK:
6186                 case ARRAY_SUBLINK:
6187                         need_paren = false;
6188                         break;
6189
6190                 case CTE_SUBLINK:               /* shouldn't occur in a SubLink */
6191                 default:
6192                         elog(ERROR, "unrecognized sublink type: %d",
6193                                  (int) sublink->subLinkType);
6194                         break;
6195         }
6196
6197         if (need_paren)
6198                 appendStringInfoChar(buf, '(');
6199
6200         get_query_def(query, buf, context->namespaces, NULL,
6201                                   context->prettyFlags, context->indentLevel);
6202
6203         if (need_paren)
6204                 appendStringInfo(buf, "))");
6205         else
6206                 appendStringInfoChar(buf, ')');
6207 }
6208
6209
6210 /* ----------
6211  * get_from_clause                      - Parse back a FROM clause
6212  *
6213  * "prefix" is the keyword that denotes the start of the list of FROM
6214  * elements. It is FROM when used to parse back SELECT and UPDATE, but
6215  * is USING when parsing back DELETE.
6216  * ----------
6217  */
6218 static void
6219 get_from_clause(Query *query, const char *prefix, deparse_context *context)
6220 {
6221         StringInfo      buf = context->buf;
6222         bool            first = true;
6223         ListCell   *l;
6224
6225         /*
6226          * We use the query's jointree as a guide to what to print.  However, we
6227          * must ignore auto-added RTEs that are marked not inFromCl. (These can
6228          * only appear at the top level of the jointree, so it's sufficient to
6229          * check here.)  This check also ensures we ignore the rule pseudo-RTEs
6230          * for NEW and OLD.
6231          */
6232         foreach(l, query->jointree->fromlist)
6233         {
6234                 Node       *jtnode = (Node *) lfirst(l);
6235
6236                 if (IsA(jtnode, RangeTblRef))
6237                 {
6238                         int                     varno = ((RangeTblRef *) jtnode)->rtindex;
6239                         RangeTblEntry *rte = rt_fetch(varno, query->rtable);
6240
6241                         if (!rte->inFromCl)
6242                                 continue;
6243                 }
6244
6245                 if (first)
6246                 {
6247                         appendContextKeyword(context, prefix,
6248                                                                  -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
6249                         first = false;
6250                 }
6251                 else
6252                         appendStringInfoString(buf, ", ");
6253
6254                 get_from_clause_item(jtnode, query, context);
6255         }
6256 }
6257
6258 static void
6259 get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
6260 {
6261         StringInfo      buf = context->buf;
6262
6263         if (IsA(jtnode, RangeTblRef))
6264         {
6265                 int                     varno = ((RangeTblRef *) jtnode)->rtindex;
6266                 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
6267                 bool            gavealias = false;
6268
6269                 switch (rte->rtekind)
6270                 {
6271                         case RTE_RELATION:
6272                                 /* Normal relation RTE */
6273                                 appendStringInfo(buf, "%s%s",
6274                                                                  only_marker(rte),
6275                                                                  generate_relation_name(rte->relid,
6276                                                                                                                 context->namespaces));
6277                                 break;
6278                         case RTE_SUBQUERY:
6279                                 /* Subquery RTE */
6280                                 appendStringInfoChar(buf, '(');
6281                                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
6282                                                           context->prettyFlags, context->indentLevel);
6283                                 appendStringInfoChar(buf, ')');
6284                                 break;
6285                         case RTE_FUNCTION:
6286                                 /* Function RTE */
6287                                 get_rule_expr(rte->funcexpr, context, true);
6288                                 break;
6289                         case RTE_VALUES:
6290                                 /* Values list RTE */
6291                                 get_values_def(rte->values_lists, context);
6292                                 break;
6293                         case RTE_CTE:
6294                                 appendStringInfoString(buf, quote_identifier(rte->ctename));
6295                                 break;
6296                         default:
6297                                 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
6298                                 break;
6299                 }
6300
6301                 if (rte->alias != NULL)
6302                 {
6303                         appendStringInfo(buf, " %s",
6304                                                          quote_identifier(rte->alias->aliasname));
6305                         gavealias = true;
6306                 }
6307                 else if (rte->rtekind == RTE_RELATION &&
6308                                  strcmp(rte->eref->aliasname, get_rel_name(rte->relid)) != 0)
6309                 {
6310                         /*
6311                          * Apparently the rel has been renamed since the rule was made.
6312                          * Emit a fake alias clause so that variable references will still
6313                          * work.  This is not a 100% solution but should work in most
6314                          * reasonable situations.
6315                          */
6316                         appendStringInfo(buf, " %s",
6317                                                          quote_identifier(rte->eref->aliasname));
6318                         gavealias = true;
6319                 }
6320                 else if (rte->rtekind == RTE_FUNCTION)
6321                 {
6322                         /*
6323                          * For a function RTE, always give an alias. This covers possible
6324                          * renaming of the function and/or instability of the
6325                          * FigureColname rules for things that aren't simple functions.
6326                          */
6327                         appendStringInfo(buf, " %s",
6328                                                          quote_identifier(rte->eref->aliasname));
6329                         gavealias = true;
6330                 }
6331
6332                 if (rte->rtekind == RTE_FUNCTION)
6333                 {
6334                         if (rte->funccoltypes != NIL)
6335                         {
6336                                 /* Function returning RECORD, reconstruct the columndefs */
6337                                 if (!gavealias)
6338                                         appendStringInfo(buf, " AS ");
6339                                 get_from_clause_coldeflist(rte->eref->colnames,
6340                                                                                    rte->funccoltypes,
6341                                                                                    rte->funccoltypmods,
6342                                                                                    context);
6343                         }
6344                         else
6345                         {
6346                                 /*
6347                                  * For a function RTE, always emit a complete column alias
6348                                  * list; this is to protect against possible instability of
6349                                  * the default column names (eg, from altering parameter
6350                                  * names).
6351                                  */
6352                                 get_from_clause_alias(rte->eref, rte, context);
6353                         }
6354                 }
6355                 else
6356                 {
6357                         /*
6358                          * For non-function RTEs, just report whatever the user originally
6359                          * gave as column aliases.
6360                          */
6361                         get_from_clause_alias(rte->alias, rte, context);
6362                 }
6363         }
6364         else if (IsA(jtnode, JoinExpr))
6365         {
6366                 JoinExpr   *j = (JoinExpr *) jtnode;
6367                 bool            need_paren_on_right;
6368
6369                 need_paren_on_right = PRETTY_PAREN(context) &&
6370                         !IsA(j->rarg, RangeTblRef) &&
6371                         !(IsA(j->rarg, JoinExpr) &&((JoinExpr *) j->rarg)->alias != NULL);
6372
6373                 if (!PRETTY_PAREN(context) || j->alias != NULL)
6374                         appendStringInfoChar(buf, '(');
6375
6376                 get_from_clause_item(j->larg, query, context);
6377
6378                 if (j->isNatural)
6379                 {
6380                         if (!PRETTY_INDENT(context))
6381                                 appendStringInfoChar(buf, ' ');
6382                         switch (j->jointype)
6383                         {
6384                                 case JOIN_INNER:
6385                                         appendContextKeyword(context, "NATURAL JOIN ",
6386                                                                                  -PRETTYINDENT_JOIN,
6387                                                                                  PRETTYINDENT_JOIN, 0);
6388                                         break;
6389                                 case JOIN_LEFT:
6390                                         appendContextKeyword(context, "NATURAL LEFT JOIN ",
6391                                                                                  -PRETTYINDENT_JOIN,
6392                                                                                  PRETTYINDENT_JOIN, 0);
6393                                         break;
6394                                 case JOIN_FULL:
6395                                         appendContextKeyword(context, "NATURAL FULL JOIN ",
6396                                                                                  -PRETTYINDENT_JOIN,
6397                                                                                  PRETTYINDENT_JOIN, 0);
6398                                         break;
6399                                 case JOIN_RIGHT:
6400                                         appendContextKeyword(context, "NATURAL RIGHT JOIN ",
6401                                                                                  -PRETTYINDENT_JOIN,
6402                                                                                  PRETTYINDENT_JOIN, 0);
6403                                         break;
6404                                 default:
6405                                         elog(ERROR, "unrecognized join type: %d",
6406                                                  (int) j->jointype);
6407                         }
6408                 }
6409                 else
6410                 {
6411                         switch (j->jointype)
6412                         {
6413                                 case JOIN_INNER:
6414                                         if (j->quals)
6415                                                 appendContextKeyword(context, " JOIN ",
6416                                                                                          -PRETTYINDENT_JOIN,
6417                                                                                          PRETTYINDENT_JOIN, 2);
6418                                         else
6419                                                 appendContextKeyword(context, " CROSS JOIN ",
6420                                                                                          -PRETTYINDENT_JOIN,
6421                                                                                          PRETTYINDENT_JOIN, 1);
6422                                         break;
6423                                 case JOIN_LEFT:
6424                                         appendContextKeyword(context, " LEFT JOIN ",
6425                                                                                  -PRETTYINDENT_JOIN,
6426                                                                                  PRETTYINDENT_JOIN, 2);
6427                                         break;
6428                                 case JOIN_FULL:
6429                                         appendContextKeyword(context, " FULL JOIN ",
6430                                                                                  -PRETTYINDENT_JOIN,
6431                                                                                  PRETTYINDENT_JOIN, 2);
6432                                         break;
6433                                 case JOIN_RIGHT:
6434                                         appendContextKeyword(context, " RIGHT JOIN ",
6435                                                                                  -PRETTYINDENT_JOIN,
6436                                                                                  PRETTYINDENT_JOIN, 2);
6437                                         break;
6438                                 default:
6439                                         elog(ERROR, "unrecognized join type: %d",
6440                                                  (int) j->jointype);
6441                         }
6442                 }
6443
6444                 if (need_paren_on_right)
6445                         appendStringInfoChar(buf, '(');
6446                 get_from_clause_item(j->rarg, query, context);
6447                 if (need_paren_on_right)
6448                         appendStringInfoChar(buf, ')');
6449
6450                 context->indentLevel -= PRETTYINDENT_JOIN_ON;
6451
6452                 if (!j->isNatural)
6453                 {
6454                         if (j->usingClause)
6455                         {
6456                                 ListCell   *col;
6457
6458                                 appendStringInfo(buf, " USING (");
6459                                 foreach(col, j->usingClause)
6460                                 {
6461                                         if (col != list_head(j->usingClause))
6462                                                 appendStringInfo(buf, ", ");
6463                                         appendStringInfoString(buf,
6464                                                                           quote_identifier(strVal(lfirst(col))));
6465                                 }
6466                                 appendStringInfoChar(buf, ')');
6467                         }
6468                         else if (j->quals)
6469                         {
6470                                 appendStringInfo(buf, " ON ");
6471                                 if (!PRETTY_PAREN(context))
6472                                         appendStringInfoChar(buf, '(');
6473                                 get_rule_expr(j->quals, context, false);
6474                                 if (!PRETTY_PAREN(context))
6475                                         appendStringInfoChar(buf, ')');
6476                         }
6477                 }
6478                 if (!PRETTY_PAREN(context) || j->alias != NULL)
6479                         appendStringInfoChar(buf, ')');
6480
6481                 /* Yes, it's correct to put alias after the right paren ... */
6482                 if (j->alias != NULL)
6483                 {
6484                         appendStringInfo(buf, " %s",
6485                                                          quote_identifier(j->alias->aliasname));
6486                         get_from_clause_alias(j->alias,
6487                                                                   rt_fetch(j->rtindex, query->rtable),
6488                                                                   context);
6489                 }
6490         }
6491         else
6492                 elog(ERROR, "unrecognized node type: %d",
6493                          (int) nodeTag(jtnode));
6494 }
6495
6496 /*
6497  * get_from_clause_alias - reproduce column alias list
6498  *
6499  * This is tricky because we must ignore dropped columns.
6500  */
6501 static void
6502 get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
6503                                           deparse_context *context)
6504 {
6505         StringInfo      buf = context->buf;
6506         ListCell   *col;
6507         AttrNumber      attnum;
6508         bool            first = true;
6509
6510         if (alias == NULL || alias->colnames == NIL)
6511                 return;                                 /* definitely nothing to do */
6512
6513         attnum = 0;
6514         foreach(col, alias->colnames)
6515         {
6516                 attnum++;
6517                 if (get_rte_attribute_is_dropped(rte, attnum))
6518                         continue;
6519                 if (first)
6520                 {
6521                         appendStringInfoChar(buf, '(');
6522                         first = false;
6523                 }
6524                 else
6525                         appendStringInfo(buf, ", ");
6526                 appendStringInfoString(buf,
6527                                                            quote_identifier(strVal(lfirst(col))));
6528         }
6529         if (!first)
6530                 appendStringInfoChar(buf, ')');
6531 }
6532
6533 /*
6534  * get_from_clause_coldeflist - reproduce FROM clause coldeflist
6535  *
6536  * The coldeflist is appended immediately (no space) to buf.  Caller is
6537  * responsible for ensuring that an alias or AS is present before it.
6538  */
6539 static void
6540 get_from_clause_coldeflist(List *names, List *types, List *typmods,
6541                                                    deparse_context *context)
6542 {
6543         StringInfo      buf = context->buf;
6544         ListCell   *l1;
6545         ListCell   *l2;
6546         ListCell   *l3;
6547         int                     i = 0;
6548
6549         appendStringInfoChar(buf, '(');
6550
6551         l2 = list_head(types);
6552         l3 = list_head(typmods);
6553         foreach(l1, names)
6554         {
6555                 char       *attname = strVal(lfirst(l1));
6556                 Oid                     atttypid;
6557                 int32           atttypmod;
6558
6559                 atttypid = lfirst_oid(l2);
6560                 l2 = lnext(l2);
6561                 atttypmod = lfirst_int(l3);
6562                 l3 = lnext(l3);
6563
6564                 if (i > 0)
6565                         appendStringInfo(buf, ", ");
6566                 appendStringInfo(buf, "%s %s",
6567                                                  quote_identifier(attname),
6568                                                  format_type_with_typemod(atttypid, atttypmod));
6569                 i++;
6570         }
6571
6572         appendStringInfoChar(buf, ')');
6573 }
6574
6575 /*
6576  * get_opclass_name                     - fetch name of an index operator class
6577  *
6578  * The opclass name is appended (after a space) to buf.
6579  *
6580  * Output is suppressed if the opclass is the default for the given
6581  * actual_datatype.  (If you don't want this behavior, just pass
6582  * InvalidOid for actual_datatype.)
6583  */
6584 static void
6585 get_opclass_name(Oid opclass, Oid actual_datatype,
6586                                  StringInfo buf)
6587 {
6588         HeapTuple       ht_opc;
6589         Form_pg_opclass opcrec;
6590         char       *opcname;
6591         char       *nspname;
6592
6593         ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
6594         if (!HeapTupleIsValid(ht_opc))
6595                 elog(ERROR, "cache lookup failed for opclass %u", opclass);
6596         opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
6597
6598         if (!OidIsValid(actual_datatype) ||
6599                 GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
6600         {
6601                 /* Okay, we need the opclass name.      Do we need to qualify it? */
6602                 opcname = NameStr(opcrec->opcname);
6603                 if (OpclassIsVisible(opclass))
6604                         appendStringInfo(buf, " %s", quote_identifier(opcname));
6605                 else
6606                 {
6607                         nspname = get_namespace_name(opcrec->opcnamespace);
6608                         appendStringInfo(buf, " %s.%s",
6609                                                          quote_identifier(nspname),
6610                                                          quote_identifier(opcname));
6611                 }
6612         }
6613         ReleaseSysCache(ht_opc);
6614 }
6615
6616 /*
6617  * processIndirection - take care of array and subfield assignment
6618  *
6619  * We strip any top-level FieldStore or assignment ArrayRef nodes that
6620  * appear in the input, and return the subexpression that's to be assigned.
6621  * If printit is true, we also print out the appropriate decoration for the
6622  * base column name (that the caller just printed).
6623  */
6624 static Node *
6625 processIndirection(Node *node, deparse_context *context, bool printit)
6626 {
6627         StringInfo      buf = context->buf;
6628
6629         for (;;)
6630         {
6631                 if (node == NULL)
6632                         break;
6633                 if (IsA(node, FieldStore))
6634                 {
6635                         FieldStore *fstore = (FieldStore *) node;
6636                         Oid                     typrelid;
6637                         char       *fieldname;
6638
6639                         /* lookup tuple type */
6640                         typrelid = get_typ_typrelid(fstore->resulttype);
6641                         if (!OidIsValid(typrelid))
6642                                 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
6643                                          format_type_be(fstore->resulttype));
6644
6645                         /*
6646                          * Print the field name.  There should only be one target field in
6647                          * stored rules.  There could be more than that in executable
6648                          * target lists, but this function cannot be used for that case.
6649                          */
6650                         Assert(list_length(fstore->fieldnums) == 1);
6651                         fieldname = get_relid_attribute_name(typrelid,
6652                                                                                         linitial_int(fstore->fieldnums));
6653                         if (printit)
6654                                 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
6655
6656                         /*
6657                          * We ignore arg since it should be an uninteresting reference to
6658                          * the target column or subcolumn.
6659                          */
6660                         node = (Node *) linitial(fstore->newvals);
6661                 }
6662                 else if (IsA(node, ArrayRef))
6663                 {
6664                         ArrayRef   *aref = (ArrayRef *) node;
6665
6666                         if (aref->refassgnexpr == NULL)
6667                                 break;
6668                         if (printit)
6669                                 printSubscripts(aref, context);
6670
6671                         /*
6672                          * We ignore refexpr since it should be an uninteresting reference
6673                          * to the target column or subcolumn.
6674                          */
6675                         node = (Node *) aref->refassgnexpr;
6676                 }
6677                 else
6678                         break;
6679         }
6680
6681         return node;
6682 }
6683
6684 static void
6685 printSubscripts(ArrayRef *aref, deparse_context *context)
6686 {
6687         StringInfo      buf = context->buf;
6688         ListCell   *lowlist_item;
6689         ListCell   *uplist_item;
6690
6691         lowlist_item = list_head(aref->reflowerindexpr);        /* could be NULL */
6692         foreach(uplist_item, aref->refupperindexpr)
6693         {
6694                 appendStringInfoChar(buf, '[');
6695                 if (lowlist_item)
6696                 {
6697                         get_rule_expr((Node *) lfirst(lowlist_item), context, false);
6698                         appendStringInfoChar(buf, ':');
6699                         lowlist_item = lnext(lowlist_item);
6700                 }
6701                 get_rule_expr((Node *) lfirst(uplist_item), context, false);
6702                 appendStringInfoChar(buf, ']');
6703         }
6704 }
6705
6706 /*
6707  * quote_identifier                     - Quote an identifier only if needed
6708  *
6709  * When quotes are needed, we palloc the required space; slightly
6710  * space-wasteful but well worth it for notational simplicity.
6711  */
6712 const char *
6713 quote_identifier(const char *ident)
6714 {
6715         /*
6716          * Can avoid quoting if ident starts with a lowercase letter or underscore
6717          * and contains only lowercase letters, digits, and underscores, *and* is
6718          * not any SQL keyword.  Otherwise, supply quotes.
6719          */
6720         int                     nquotes = 0;
6721         bool            safe;
6722         const char *ptr;
6723         char       *result;
6724         char       *optr;
6725
6726         /*
6727          * would like to use <ctype.h> macros here, but they might yield unwanted
6728          * locale-specific results...
6729          */
6730         safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
6731
6732         for (ptr = ident; *ptr; ptr++)
6733         {
6734                 char            ch = *ptr;
6735
6736                 if ((ch >= 'a' && ch <= 'z') ||
6737                         (ch >= '0' && ch <= '9') ||
6738                         (ch == '_'))
6739                 {
6740                         /* okay */
6741                 }
6742                 else
6743                 {
6744                         safe = false;
6745                         if (ch == '"')
6746                                 nquotes++;
6747                 }
6748         }
6749
6750         if (quote_all_identifiers)
6751                 safe = false;
6752
6753         if (safe)
6754         {
6755                 /*
6756                  * Check for keyword.  We quote keywords except for unreserved ones.
6757                  * (In some cases we could avoid quoting a col_name or type_func_name
6758                  * keyword, but it seems much harder than it's worth to tell that.)
6759                  *
6760                  * Note: ScanKeywordLookup() does case-insensitive comparison, but
6761                  * that's fine, since we already know we have all-lower-case.
6762                  */
6763                 const ScanKeyword *keyword = ScanKeywordLookup(ident,
6764                                                                                                            ScanKeywords,
6765                                                                                                            NumScanKeywords);
6766
6767                 if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
6768                         safe = false;
6769         }
6770
6771         if (safe)
6772                 return ident;                   /* no change needed */
6773
6774         result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
6775
6776         optr = result;
6777         *optr++ = '"';
6778         for (ptr = ident; *ptr; ptr++)
6779         {
6780                 char            ch = *ptr;
6781
6782                 if (ch == '"')
6783                         *optr++ = '"';
6784                 *optr++ = ch;
6785         }
6786         *optr++ = '"';
6787         *optr = '\0';
6788
6789         return result;
6790 }
6791
6792 /*
6793  * quote_qualified_identifier   - Quote a possibly-qualified identifier
6794  *
6795  * Return a name of the form qualifier.ident, or just ident if qualifier
6796  * is NULL, quoting each component if necessary.  The result is palloc'd.
6797  */
6798 char *
6799 quote_qualified_identifier(const char *qualifier,
6800                                                    const char *ident)
6801 {
6802         StringInfoData buf;
6803
6804         initStringInfo(&buf);
6805         if (qualifier)
6806                 appendStringInfo(&buf, "%s.", quote_identifier(qualifier));
6807         appendStringInfoString(&buf, quote_identifier(ident));
6808         return buf.data;
6809 }
6810
6811 /*
6812  * generate_relation_name
6813  *              Compute the name to display for a relation specified by OID
6814  *
6815  * The result includes all necessary quoting and schema-prefixing.
6816  *
6817  * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
6818  * We will forcibly qualify the relation name if it equals any CTE name
6819  * visible in the namespace list.
6820  */
6821 static char *
6822 generate_relation_name(Oid relid, List *namespaces)
6823 {
6824         HeapTuple       tp;
6825         Form_pg_class reltup;
6826         bool            need_qual;
6827         ListCell   *nslist;
6828         char       *relname;
6829         char       *nspname;
6830         char       *result;
6831
6832         tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
6833         if (!HeapTupleIsValid(tp))
6834                 elog(ERROR, "cache lookup failed for relation %u", relid);
6835         reltup = (Form_pg_class) GETSTRUCT(tp);
6836         relname = NameStr(reltup->relname);
6837
6838         /* Check for conflicting CTE name */
6839         need_qual = false;
6840         foreach(nslist, namespaces)
6841         {
6842                 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
6843                 ListCell   *ctlist;
6844
6845                 foreach(ctlist, dpns->ctes)
6846                 {
6847                         CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
6848
6849                         if (strcmp(cte->ctename, relname) == 0)
6850                         {
6851                                 need_qual = true;
6852                                 break;
6853                         }
6854                 }
6855                 if (need_qual)
6856                         break;
6857         }
6858
6859         /* Otherwise, qualify the name if not visible in search path */
6860         if (!need_qual)
6861                 need_qual = !RelationIsVisible(relid);
6862
6863         if (need_qual)
6864                 nspname = get_namespace_name(reltup->relnamespace);
6865         else
6866                 nspname = NULL;
6867
6868         result = quote_qualified_identifier(nspname, relname);
6869
6870         ReleaseSysCache(tp);
6871
6872         return result;
6873 }
6874
6875 /*
6876  * generate_function_name
6877  *              Compute the name to display for a function specified by OID,
6878  *              given that it is being called with the specified actual arg names and
6879  *              types.  (Those matter because of ambiguous-function resolution rules.)
6880  *
6881  * The result includes all necessary quoting and schema-prefixing.      We can
6882  * also pass back an indication of whether the function is variadic.
6883  */
6884 static char *
6885 generate_function_name(Oid funcid, int nargs, List *argnames,
6886                                            Oid *argtypes, bool *is_variadic)
6887 {
6888         HeapTuple       proctup;
6889         Form_pg_proc procform;
6890         char       *proname;
6891         char       *nspname;
6892         char       *result;
6893         FuncDetailCode p_result;
6894         Oid                     p_funcid;
6895         Oid                     p_rettype;
6896         bool            p_retset;
6897         int                     p_nvargs;
6898         Oid                *p_true_typeids;
6899
6900         proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
6901         if (!HeapTupleIsValid(proctup))
6902                 elog(ERROR, "cache lookup failed for function %u", funcid);
6903         procform = (Form_pg_proc) GETSTRUCT(proctup);
6904         proname = NameStr(procform->proname);
6905
6906         /*
6907          * The idea here is to schema-qualify only if the parser would fail to
6908          * resolve the correct function given the unqualified func name with the
6909          * specified argtypes.  If the function is variadic, we should presume
6910          * that VARIADIC will be included in the call.
6911          */
6912         p_result = func_get_detail(list_make1(makeString(proname)),
6913                                                            NIL, argnames, nargs, argtypes,
6914                                                            !OidIsValid(procform->provariadic), true,
6915                                                            &p_funcid, &p_rettype,
6916                                                            &p_retset, &p_nvargs, &p_true_typeids, NULL);
6917         if ((p_result == FUNCDETAIL_NORMAL ||
6918                  p_result == FUNCDETAIL_AGGREGATE ||
6919                  p_result == FUNCDETAIL_WINDOWFUNC) &&
6920                 p_funcid == funcid)
6921                 nspname = NULL;
6922         else
6923                 nspname = get_namespace_name(procform->pronamespace);
6924
6925         result = quote_qualified_identifier(nspname, proname);
6926
6927         /* Check variadic-ness if caller cares */
6928         if (is_variadic)
6929         {
6930                 /* "any" variadics are not treated as variadics for listing */
6931                 if (OidIsValid(procform->provariadic) &&
6932                         procform->provariadic != ANYOID)
6933                         *is_variadic = true;
6934                 else
6935                         *is_variadic = false;
6936         }
6937
6938         ReleaseSysCache(proctup);
6939
6940         return result;
6941 }
6942
6943 /*
6944  * generate_operator_name
6945  *              Compute the name to display for an operator specified by OID,
6946  *              given that it is being called with the specified actual arg types.
6947  *              (Arg types matter because of ambiguous-operator resolution rules.
6948  *              Pass InvalidOid for unused arg of a unary operator.)
6949  *
6950  * The result includes all necessary quoting and schema-prefixing,
6951  * plus the OPERATOR() decoration needed to use a qualified operator name
6952  * in an expression.
6953  */
6954 static char *
6955 generate_operator_name(Oid operid, Oid arg1, Oid arg2)
6956 {
6957         StringInfoData buf;
6958         HeapTuple       opertup;
6959         Form_pg_operator operform;
6960         char       *oprname;
6961         char       *nspname;
6962         Operator        p_result;
6963
6964         initStringInfo(&buf);
6965
6966         opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operid));
6967         if (!HeapTupleIsValid(opertup))
6968                 elog(ERROR, "cache lookup failed for operator %u", operid);
6969         operform = (Form_pg_operator) GETSTRUCT(opertup);
6970         oprname = NameStr(operform->oprname);
6971
6972         /*
6973          * The idea here is to schema-qualify only if the parser would fail to
6974          * resolve the correct operator given the unqualified op name with the
6975          * specified argtypes.
6976          */
6977         switch (operform->oprkind)
6978         {
6979                 case 'b':
6980                         p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
6981                                                         true, -1);
6982                         break;
6983                 case 'l':
6984                         p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
6985                                                                  true, -1);
6986                         break;
6987                 case 'r':
6988                         p_result = right_oper(NULL, list_make1(makeString(oprname)), arg1,
6989                                                                   true, -1);
6990                         break;
6991                 default:
6992                         elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
6993                         p_result = NULL;        /* keep compiler quiet */
6994                         break;
6995         }
6996
6997         if (p_result != NULL && oprid(p_result) == operid)
6998                 nspname = NULL;
6999         else
7000         {
7001                 nspname = get_namespace_name(operform->oprnamespace);
7002                 appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
7003         }
7004
7005         appendStringInfoString(&buf, oprname);
7006
7007         if (nspname)
7008                 appendStringInfoChar(&buf, ')');
7009
7010         if (p_result != NULL)
7011                 ReleaseSysCache(p_result);
7012
7013         ReleaseSysCache(opertup);
7014
7015         return buf.data;
7016 }
7017
7018 /*
7019  * Given a C string, produce a TEXT datum.
7020  *
7021  * We assume that the input was palloc'd and may be freed.
7022  */
7023 static text *
7024 string_to_text(char *str)
7025 {
7026         text       *result;
7027
7028         result = cstring_to_text(str);
7029         pfree(str);
7030         return result;
7031 }
7032
7033 /*
7034  * Generate a C string representing a relation's reloptions, or NULL if none.
7035  */
7036 static char *
7037 flatten_reloptions(Oid relid)
7038 {
7039         char       *result = NULL;
7040         HeapTuple       tuple;
7041         Datum           reloptions;
7042         bool            isnull;
7043
7044         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
7045         if (!HeapTupleIsValid(tuple))
7046                 elog(ERROR, "cache lookup failed for relation %u", relid);
7047
7048         reloptions = SysCacheGetAttr(RELOID, tuple,
7049                                                                  Anum_pg_class_reloptions, &isnull);
7050         if (!isnull)
7051         {
7052                 Datum           sep,
7053                                         txt;
7054
7055                 /*
7056                  * We want to use array_to_text(reloptions, ', ') --- but
7057                  * DirectFunctionCall2(array_to_text) does not work, because
7058                  * array_to_text() relies on flinfo to be valid.  So use
7059                  * OidFunctionCall2.
7060                  */
7061                 sep = CStringGetTextDatum(", ");
7062                 txt = OidFunctionCall2(F_ARRAY_TO_TEXT, reloptions, sep);
7063                 result = TextDatumGetCString(txt);
7064         }
7065
7066         ReleaseSysCache(tuple);
7067
7068         return result;
7069 }