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