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