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