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