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