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