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