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