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