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