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