]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/ruleutils.c
1a2fe54d7ace4c19861fd9b4a7f1de1a849c2341
[postgresql] / src / backend / utils / adt / ruleutils.c
1 /**********************************************************************
2  * ruleutils.c  - Functions to convert stored expressions/querytrees
3  *                              back to source text
4  *
5  * IDENTIFICATION
6  *        $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.173 2004/06/18 06:13:49 tgl Exp $
7  *
8  *        This software is copyrighted by Jan Wieck - Hamburg.
9  *
10  *        The author hereby grants permission  to  use,  copy,  modify,
11  *        distribute,  and      license this software and its documentation
12  *        for any purpose, provided that existing copyright notices are
13  *        retained      in      all  copies  and  that  this notice is included
14  *        verbatim in any distributions. No written agreement, license,
15  *        or  royalty  fee      is required for any of the authorized uses.
16  *        Modifications to this software may be  copyrighted  by  their
17  *        author  and  need  not  follow  the licensing terms described
18  *        here, provided that the new terms are  clearly  indicated  on
19  *        the first page of each file where they apply.
20  *
21  *        IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
22  *        PARTY  FOR  DIRECT,   INDIRECT,       SPECIAL,   INCIDENTAL,   OR
23  *        CONSEQUENTIAL   DAMAGES  ARISING      OUT  OF  THE  USE  OF  THIS
24  *        SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
25  *        IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
26  *        DAMAGE.
27  *
28  *        THE  AUTHOR  AND      DISTRIBUTORS  SPECIFICALLY       DISCLAIM       ANY
29  *        WARRANTIES,  INCLUDING,  BUT  NOT  LIMITED  TO,  THE  IMPLIED
30  *        WARRANTIES  OF  MERCHANTABILITY,      FITNESS  FOR  A  PARTICULAR
31  *        PURPOSE,      AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON
32  *        AN "AS IS" BASIS, AND THE AUTHOR      AND  DISTRIBUTORS  HAVE  NO
33  *        OBLIGATION   TO       PROVIDE   MAINTENANCE,   SUPPORT,  UPDATES,
34  *        ENHANCEMENTS, OR MODIFICATIONS.
35  *
36  **********************************************************************/
37
38 #include "postgres.h"
39
40 #include <unistd.h>
41 #include <fcntl.h>
42
43 #include "access/genam.h"
44 #include "catalog/catname.h"
45 #include "catalog/heap.h"
46 #include "catalog/index.h"
47 #include "catalog/indexing.h"
48 #include "catalog/namespace.h"
49 #include "catalog/pg_cast.h"
50 #include "catalog/pg_constraint.h"
51 #include "catalog/pg_index.h"
52 #include "catalog/pg_opclass.h"
53 #include "catalog/pg_operator.h"
54 #include "catalog/pg_shadow.h"
55 #include "catalog/pg_trigger.h"
56 #include "commands/tablespace.h"
57 #include "executor/spi.h"
58 #include "lib/stringinfo.h"
59 #include "nodes/makefuncs.h"
60 #include "optimizer/clauses.h"
61 #include "optimizer/tlist.h"
62 #include "parser/keywords.h"
63 #include "parser/parse_expr.h"
64 #include "parser/parse_func.h"
65 #include "parser/parse_oper.h"
66 #include "parser/parse_type.h"
67 #include "parser/parsetree.h"
68 #include "rewrite/rewriteManip.h"
69 #include "rewrite/rewriteSupport.h"
70 #include "utils/array.h"
71 #include "utils/fmgroids.h"
72 #include "utils/lsyscache.h"
73 #include "utils/typcache.h"
74
75
76 /* ----------
77  * Pretty formatting constants
78  * ----------
79  */
80
81 /* Indent counts */
82 #define PRETTYINDENT_STD                8
83 #define PRETTYINDENT_JOIN          13
84 #define PRETTYINDENT_JOIN_ON    (PRETTYINDENT_JOIN-PRETTYINDENT_STD)
85 #define PRETTYINDENT_VAR                4
86
87 /* Pretty flags */
88 #define PRETTYFLAG_PAREN                1
89 #define PRETTYFLAG_INDENT               2
90
91 /* macro to test if pretty action needed */
92 #define PRETTY_PAREN(context)   ((context)->prettyFlags & PRETTYFLAG_PAREN)
93 #define PRETTY_INDENT(context)  ((context)->prettyFlags & PRETTYFLAG_INDENT)
94
95
96 /* ----------
97  * Local data types
98  * ----------
99  */
100
101 /* Context info needed for invoking a recursive querytree display routine */
102 typedef struct
103 {
104         StringInfo      buf;                    /* output buffer to append to */
105         List       *namespaces;         /* List of deparse_namespace nodes */
106         int                     prettyFlags;    /* enabling of pretty-print functions */
107         int                     indentLevel;    /* current indent level for prettyprint */
108         bool            varprefix;              /* TRUE to print prefixes on Vars */
109 } deparse_context;
110
111 /*
112  * Each level of query context around a subtree needs a level of Var namespace.
113  * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
114  * the current context's namespaces list.
115  *
116  * The rangetable is the list of actual RTEs from the query tree.
117  *
118  * For deparsing plan trees, we allow two special RTE entries that are not
119  * part of the rtable list (mainly because they don't have consecutively
120  * allocated varnos).
121  */
122 typedef struct
123 {
124         List       *rtable;                     /* List of RangeTblEntry nodes */
125         int                     outer_varno;    /* varno for outer_rte */
126         RangeTblEntry *outer_rte;       /* special RangeTblEntry, or NULL */
127         int                     inner_varno;    /* varno for inner_rte */
128         RangeTblEntry *inner_rte;       /* special RangeTblEntry, or NULL */
129 } deparse_namespace;
130
131
132 /* ----------
133  * Global data
134  * ----------
135  */
136 static void *plan_getrulebyoid = NULL;
137 static char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
138 static void *plan_getviewrule = NULL;
139 static char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
140
141
142 /* ----------
143  * Local functions
144  *
145  * Most of these functions used to use fixed-size buffers to build their
146  * results.  Now, they take an (already initialized) StringInfo object
147  * as a parameter, and append their text output to its contents.
148  * ----------
149  */
150 static char *deparse_expression_pretty(Node *expr, List *dpcontext,
151                                                   bool forceprefix, bool showimplicit,
152                                                   int prettyFlags, int startIndent);
153 static char *pg_get_viewdef_worker(Oid viewoid, int prettyFlags);
154 static void decompile_column_index_array(Datum column_index_array, Oid relId,
155                                                          StringInfo buf);
156 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
157 static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
158                                                                         int prettyFlags);
159 static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
160                                                                                  int prettyFlags);
161 static char *pg_get_expr_worker(text *expr, Oid relid, char *relname,
162                                                                 int prettyFlags);
163 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
164                          int prettyFlags);
165 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
166                          int prettyFlags);
167 static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
168                           TupleDesc resultDesc, int prettyFlags, int startIndent);
169 static void get_select_query_def(Query *query, deparse_context *context,
170                                          TupleDesc resultDesc);
171 static void get_insert_query_def(Query *query, deparse_context *context);
172 static void get_update_query_def(Query *query, deparse_context *context);
173 static void get_delete_query_def(Query *query, deparse_context *context);
174 static void get_utility_query_def(Query *query, deparse_context *context);
175 static void get_basic_select_query(Query *query, deparse_context *context,
176                                            TupleDesc resultDesc);
177 static void get_setop_query(Node *setOp, Query *query,
178                                 deparse_context *context,
179                                 TupleDesc resultDesc);
180 static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist,
181                                                  bool force_colno,
182                                                  deparse_context *context);
183 static void get_names_for_var(Var *var, deparse_context *context,
184                                   char **schemaname, char **refname, char **attname);
185 static RangeTblEntry *find_rte_by_refname(const char *refname,
186                                         deparse_context *context);
187 static const char *get_simple_binary_op_name(OpExpr *expr);
188 static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
189 static void appendStringInfoSpaces(StringInfo buf, int count);
190 static void appendContextKeyword(deparse_context *context, const char *str,
191                                          int indentBefore, int indentAfter, int indentPlus);
192 static void get_rule_expr(Node *node, deparse_context *context,
193                           bool showimplicit);
194 static void get_oper_expr(OpExpr *expr, deparse_context *context);
195 static void get_func_expr(FuncExpr *expr, deparse_context *context,
196                           bool showimplicit);
197 static void get_agg_expr(Aggref *aggref, deparse_context *context);
198 static void get_const_expr(Const *constval, deparse_context *context);
199 static void get_sublink_expr(SubLink *sublink, deparse_context *context);
200 static void get_from_clause(Query *query, deparse_context *context);
201 static void get_from_clause_item(Node *jtnode, Query *query,
202                                          deparse_context *context);
203 static void get_from_clause_coldeflist(List *coldeflist,
204                                                    deparse_context *context);
205 static void get_opclass_name(Oid opclass, Oid actual_datatype,
206                                  StringInfo buf);
207 static Node *processIndirection(Node *node, deparse_context *context);
208 static void printSubscripts(ArrayRef *aref, deparse_context *context);
209 static char *generate_relation_name(Oid relid);
210 static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes);
211 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
212 static void print_operator_name(StringInfo buf, List *opname);
213 static text *string_to_text(char *str);
214
215 #define only_marker(rte)  ((rte)->inh ? "" : "ONLY ")
216
217
218 /* ----------
219  * get_ruledef                  - Do it all and return a text
220  *                                that could be used as a statement
221  *                                to recreate the rule
222  * ----------
223  */
224 Datum
225 pg_get_ruledef(PG_FUNCTION_ARGS)
226 {
227         Oid                     ruleoid = PG_GETARG_OID(0);
228
229         PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, 0)));
230 }
231
232
233 Datum
234 pg_get_ruledef_ext(PG_FUNCTION_ARGS)
235 {
236         Oid                     ruleoid = PG_GETARG_OID(0);
237         bool            pretty = PG_GETARG_BOOL(1);
238         int                     prettyFlags;
239
240         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
241         PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, prettyFlags)));
242 }
243
244
245 static char *
246 pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
247 {
248         Datum           args[1];
249         char            nulls[1];
250         int                     spirc;
251         HeapTuple       ruletup;
252         TupleDesc       rulettc;
253         StringInfoData buf;
254
255         /*
256          * Do this first so that string is alloc'd in outer context not SPI's.
257          */
258         initStringInfo(&buf);
259
260         /*
261          * Connect to SPI manager
262          */
263         if (SPI_connect() != SPI_OK_CONNECT)
264                 elog(ERROR, "SPI_connect failed");
265
266         /*
267          * On the first call prepare the plan to lookup pg_rewrite. We read
268          * pg_rewrite over the SPI manager instead of using the syscache to be
269          * checked for read access on pg_rewrite.
270          */
271         if (plan_getrulebyoid == NULL)
272         {
273                 Oid                     argtypes[1];
274                 void       *plan;
275
276                 argtypes[0] = OIDOID;
277                 plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
278                 if (plan == NULL)
279                         elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
280                 plan_getrulebyoid = SPI_saveplan(plan);
281         }
282
283         /*
284          * Get the pg_rewrite tuple for this rule
285          */
286         args[0] = ObjectIdGetDatum(ruleoid);
287         nulls[0] = ' ';
288         spirc = SPI_execp(plan_getrulebyoid, args, nulls, 1);
289         if (spirc != SPI_OK_SELECT)
290                 elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
291         if (SPI_processed != 1)
292                 appendStringInfo(&buf, "-");
293         else
294         {
295                 /*
296                  * Get the rules definition and put it into executors memory
297                  */
298                 ruletup = SPI_tuptable->vals[0];
299                 rulettc = SPI_tuptable->tupdesc;
300                 make_ruledef(&buf, ruletup, rulettc, prettyFlags);
301         }
302
303         /*
304          * Disconnect from SPI manager
305          */
306         if (SPI_finish() != SPI_OK_FINISH)
307                 elog(ERROR, "SPI_finish failed");
308
309         return buf.data;
310 }
311
312
313 /* ----------
314  * get_viewdef                  - Mainly the same thing, but we
315  *                                only return the SELECT part of a view
316  * ----------
317  */
318 Datum
319 pg_get_viewdef(PG_FUNCTION_ARGS)
320 {
321         /* By OID */
322         Oid                     viewoid = PG_GETARG_OID(0);
323
324         PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, 0)));
325 }
326
327
328 Datum
329 pg_get_viewdef_ext(PG_FUNCTION_ARGS)
330 {
331         /* By OID */
332         Oid                     viewoid = PG_GETARG_OID(0);
333         bool            pretty = PG_GETARG_BOOL(1);
334         int                     prettyFlags;
335
336         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
337         PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags)));
338 }
339
340 Datum
341 pg_get_viewdef_name(PG_FUNCTION_ARGS)
342 {
343         /* By qualified name */
344         text       *viewname = PG_GETARG_TEXT_P(0);
345         RangeVar   *viewrel;
346         Oid                     viewoid;
347
348         viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname,
349                                                                                                                  "get_viewdef"));
350         viewoid = RangeVarGetRelid(viewrel, false);
351
352         PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, 0)));
353 }
354
355
356 Datum
357 pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
358 {
359         /* By qualified name */
360         text       *viewname = PG_GETARG_TEXT_P(0);
361         bool            pretty = PG_GETARG_BOOL(1);
362         int                     prettyFlags;
363         RangeVar   *viewrel;
364         Oid                     viewoid;
365
366         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
367         viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname,
368                                                                                                                  "get_viewdef"));
369         viewoid = RangeVarGetRelid(viewrel, false);
370
371         PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags)));
372 }
373
374 /*
375  * Common code for by-OID and by-name variants of pg_get_viewdef
376  */
377 static char *
378 pg_get_viewdef_worker(Oid viewoid, int prettyFlags)
379 {
380         Datum           args[2];
381         char            nulls[2];
382         int                     spirc;
383         HeapTuple       ruletup;
384         TupleDesc       rulettc;
385         StringInfoData buf;
386
387         /*
388          * Do this first so that string is alloc'd in outer context not SPI's.
389          */
390         initStringInfo(&buf);
391
392         /*
393          * Connect to SPI manager
394          */
395         if (SPI_connect() != SPI_OK_CONNECT)
396                 elog(ERROR, "SPI_connect failed");
397
398         /*
399          * On the first call prepare the plan to lookup pg_rewrite. We read
400          * pg_rewrite over the SPI manager instead of using the syscache to be
401          * checked for read access on pg_rewrite.
402          */
403         if (plan_getviewrule == NULL)
404         {
405                 Oid                     argtypes[2];
406                 void       *plan;
407
408                 argtypes[0] = OIDOID;
409                 argtypes[1] = NAMEOID;
410                 plan = SPI_prepare(query_getviewrule, 2, argtypes);
411                 if (plan == NULL)
412                         elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
413                 plan_getviewrule = SPI_saveplan(plan);
414         }
415
416         /*
417          * Get the pg_rewrite tuple for the view's SELECT rule
418          */
419         args[0] = ObjectIdGetDatum(viewoid);
420         args[1] = PointerGetDatum(ViewSelectRuleName);
421         nulls[0] = ' ';
422         nulls[1] = ' ';
423         spirc = SPI_execp(plan_getviewrule, args, nulls, 2);
424         if (spirc != SPI_OK_SELECT)
425                 elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
426         if (SPI_processed != 1)
427                 appendStringInfo(&buf, "Not a view");
428         else
429         {
430                 /*
431                  * Get the rules definition and put it into executors memory
432                  */
433                 ruletup = SPI_tuptable->vals[0];
434                 rulettc = SPI_tuptable->tupdesc;
435                 make_viewdef(&buf, ruletup, rulettc, prettyFlags);
436         }
437
438         /*
439          * Disconnect from SPI manager
440          */
441         if (SPI_finish() != SPI_OK_FINISH)
442                 elog(ERROR, "SPI_finish failed");
443
444         return buf.data;
445 }
446
447 /* ----------
448  * get_triggerdef                       - Get the definition of a trigger
449  * ----------
450  */
451 Datum
452 pg_get_triggerdef(PG_FUNCTION_ARGS)
453 {
454         Oid                     trigid = PG_GETARG_OID(0);
455         HeapTuple       ht_trig;
456         Form_pg_trigger trigrec;
457         StringInfoData buf;
458         Relation        tgrel;
459         ScanKeyData skey[1];
460         SysScanDesc tgscan;
461         int                     findx = 0;
462         char       *tgname;
463
464         /*
465          * Fetch the pg_trigger tuple by the Oid of the trigger
466          */
467         tgrel = heap_openr(TriggerRelationName, AccessShareLock);
468
469         ScanKeyInit(&skey[0],
470                                 ObjectIdAttributeNumber,
471                                 BTEqualStrategyNumber, F_OIDEQ,
472                                 ObjectIdGetDatum(trigid));
473
474         tgscan = systable_beginscan(tgrel, TriggerOidIndex, true,
475                                                                 SnapshotNow, 1, skey);
476
477         ht_trig = systable_getnext(tgscan);
478
479         if (!HeapTupleIsValid(ht_trig))
480                 elog(ERROR, "could not find tuple for trigger %u", trigid);
481
482         trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
483
484         /*
485          * Start the trigger definition. Note that the trigger's name should
486          * never be schema-qualified, but the trigger rel's name may be.
487          */
488         initStringInfo(&buf);
489
490         tgname = NameStr(trigrec->tgname);
491         appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
492                                          trigrec->tgisconstraint ? "CONSTRAINT " : "",
493                                          quote_identifier(tgname));
494
495         if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
496                 appendStringInfo(&buf, "BEFORE");
497         else
498                 appendStringInfo(&buf, "AFTER");
499         if (TRIGGER_FOR_INSERT(trigrec->tgtype))
500         {
501                 appendStringInfo(&buf, " INSERT");
502                 findx++;
503         }
504         if (TRIGGER_FOR_DELETE(trigrec->tgtype))
505         {
506                 if (findx > 0)
507                         appendStringInfo(&buf, " OR DELETE");
508                 else
509                         appendStringInfo(&buf, " DELETE");
510                 findx++;
511         }
512         if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
513         {
514                 if (findx > 0)
515                         appendStringInfo(&buf, " OR UPDATE");
516                 else
517                         appendStringInfo(&buf, " UPDATE");
518         }
519         appendStringInfo(&buf, " ON %s ",
520                                          generate_relation_name(trigrec->tgrelid));
521
522         if (trigrec->tgisconstraint)
523         {
524                 if (trigrec->tgconstrrelid != InvalidOid)
525                         appendStringInfo(&buf, "FROM %s ",
526                                                  generate_relation_name(trigrec->tgconstrrelid));
527                 if (!trigrec->tgdeferrable)
528                         appendStringInfo(&buf, "NOT ");
529                 appendStringInfo(&buf, "DEFERRABLE INITIALLY ");
530                 if (trigrec->tginitdeferred)
531                         appendStringInfo(&buf, "DEFERRED ");
532                 else
533                         appendStringInfo(&buf, "IMMEDIATE ");
534
535         }
536
537         if (TRIGGER_FOR_ROW(trigrec->tgtype))
538                 appendStringInfo(&buf, "FOR EACH ROW ");
539         else
540                 appendStringInfo(&buf, "FOR EACH STATEMENT ");
541
542         appendStringInfo(&buf, "EXECUTE PROCEDURE %s(",
543                                          generate_function_name(trigrec->tgfoid, 0, NULL));
544
545         if (trigrec->tgnargs > 0)
546         {
547                 bytea      *val;
548                 bool            isnull;
549                 char       *p;
550                 int                     i;
551
552                 val = (bytea *) fastgetattr(ht_trig,
553                                                                         Anum_pg_trigger_tgargs,
554                                                                         tgrel->rd_att, &isnull);
555                 if (isnull)
556                         elog(ERROR, "tgargs is null for trigger %u", trigid);
557                 p = (char *) VARDATA(val);
558                 for (i = 0; i < trigrec->tgnargs; i++)
559                 {
560                         if (i > 0)
561                                 appendStringInfo(&buf, ", ");
562                         appendStringInfoChar(&buf, '\'');
563                         while (*p)
564                         {
565                                 /* escape quotes and backslashes */
566                                 if (*p == '\'' || *p == '\\')
567                                         appendStringInfoChar(&buf, '\\');
568                                 appendStringInfoChar(&buf, *p++);
569                         }
570                         p++;
571                         appendStringInfoChar(&buf, '\'');
572                 }
573         }
574
575         /* We deliberately do not put semi-colon at end */
576         appendStringInfo(&buf, ")");
577
578         /* Clean up */
579         systable_endscan(tgscan);
580
581         heap_close(tgrel, AccessShareLock);
582
583         PG_RETURN_TEXT_P(string_to_text(buf.data));
584 }
585
586 /* ----------
587  * get_indexdef                 - Get the definition of an index
588  *
589  * In the extended version, there is a colno argument as well as pretty bool.
590  *      if colno == 0, we want a complete index definition.
591  *      if colno > 0, we only want the Nth index key's variable or expression.
592  * ----------
593  */
594 Datum
595 pg_get_indexdef(PG_FUNCTION_ARGS)
596 {
597         Oid                     indexrelid = PG_GETARG_OID(0);
598
599         PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, 0, 0)));
600 }
601
602 Datum
603 pg_get_indexdef_ext(PG_FUNCTION_ARGS)
604 {
605         Oid                     indexrelid = PG_GETARG_OID(0);
606         int32           colno = PG_GETARG_INT32(1);
607         bool            pretty = PG_GETARG_BOOL(2);
608         int                     prettyFlags;
609
610         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
611         PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, colno, prettyFlags)));
612 }
613
614 /* Internal version that returns a palloc'd C string */
615 char *
616 pg_get_indexdef_string(Oid indexrelid)
617 {
618         return pg_get_indexdef_worker(indexrelid, 0, 0);
619 }
620
621 static char *
622 pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
623 {
624         HeapTuple       ht_idx;
625         HeapTuple       ht_idxrel;
626         HeapTuple       ht_am;
627         Form_pg_index idxrec;
628         Form_pg_class idxrelrec;
629         Form_pg_am      amrec;
630         List       *indexprs;
631         ListCell   *indexpr_item;
632         List       *context;
633         Oid                     indrelid;
634         int                     keyno;
635         Oid                     keycoltype;
636         StringInfoData buf;
637         char       *str;
638         char       *sep;
639
640         /*
641          * Fetch the pg_index tuple by the Oid of the index
642          */
643         ht_idx = SearchSysCache(INDEXRELID,
644                                                         ObjectIdGetDatum(indexrelid),
645                                                         0, 0, 0);
646         if (!HeapTupleIsValid(ht_idx))
647                 elog(ERROR, "cache lookup failed for index %u", indexrelid);
648         idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
649
650         indrelid = idxrec->indrelid;
651         Assert(indexrelid == idxrec->indexrelid);
652
653         /*
654          * Fetch the pg_class tuple of the index relation
655          */
656         ht_idxrel = SearchSysCache(RELOID,
657                                                            ObjectIdGetDatum(indexrelid),
658                                                            0, 0, 0);
659         if (!HeapTupleIsValid(ht_idxrel))
660                 elog(ERROR, "cache lookup failed for relation %u", indexrelid);
661         idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
662
663         /*
664          * Fetch the pg_am tuple of the index' access method
665          */
666         ht_am = SearchSysCache(AMOID,
667                                                    ObjectIdGetDatum(idxrelrec->relam),
668                                                    0, 0, 0);
669         if (!HeapTupleIsValid(ht_am))
670                 elog(ERROR, "cache lookup failed for access method %u",
671                          idxrelrec->relam);
672         amrec = (Form_pg_am) GETSTRUCT(ht_am);
673
674         /*
675          * Get the index expressions, if any.  (NOTE: we do not use the
676          * relcache versions of the expressions and predicate, because we want
677          * to display non-const-folded expressions.)
678          */
679         if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
680         {
681                 Datum           exprsDatum;
682                 bool            isnull;
683                 char       *exprsString;
684
685                 exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
686                                                                          Anum_pg_index_indexprs, &isnull);
687                 Assert(!isnull);
688                 exprsString = DatumGetCString(DirectFunctionCall1(textout,
689                                                                                                                   exprsDatum));
690                 indexprs = (List *) stringToNode(exprsString);
691                 pfree(exprsString);
692         }
693         else
694                 indexprs = NIL;
695
696         indexpr_item = list_head(indexprs);
697
698         context = deparse_context_for(get_rel_name(indrelid), indrelid);
699
700         /*
701          * Start the index definition.  Note that the index's name should
702          * never be schema-qualified, but the indexed rel's name may be.
703          */
704         initStringInfo(&buf);
705
706         if (!colno)
707                 appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
708                                                  idxrec->indisunique ? "UNIQUE " : "",
709                                                  quote_identifier(NameStr(idxrelrec->relname)),
710                                                  generate_relation_name(indrelid),
711                                                  quote_identifier(NameStr(amrec->amname)));
712
713         /*
714          * Report the indexed attributes
715          */
716         sep = "";
717         for (keyno = 0; keyno < idxrec->indnatts; keyno++)
718         {
719                 AttrNumber      attnum = idxrec->indkey[keyno];
720
721                 if (!colno)
722                         appendStringInfo(&buf, sep);
723                 sep = ", ";
724
725                 if (attnum != 0)
726                 {
727                         /* Simple index column */
728                         char       *attname;
729
730                         attname = get_relid_attribute_name(indrelid, attnum);
731                         if (!colno || colno == keyno + 1)
732                                 appendStringInfoString(&buf, quote_identifier(attname));
733                         keycoltype = get_atttype(indrelid, attnum);
734                 }
735                 else
736                 {
737                         /* expressional index */
738                         Node       *indexkey;
739
740                         if (indexpr_item == NULL)
741                                 elog(ERROR, "too few entries in indexprs list");
742                         indexkey = (Node *) lfirst(indexpr_item);
743                         indexpr_item = lnext(indexpr_item);
744                         /* Deparse */
745                         str = deparse_expression_pretty(indexkey, context, false, false,
746                                                                                         prettyFlags, 0);
747                         if (!colno || colno == keyno + 1)
748                         {
749                                 /* Need parens if it's not a bare function call */
750                                 if (indexkey && IsA(indexkey, FuncExpr) &&
751                                         ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
752                                         appendStringInfoString(&buf, str);
753                                 else
754                                         appendStringInfo(&buf, "(%s)", str);
755                         }
756                         keycoltype = exprType(indexkey);
757                 }
758
759                 /*
760                  * Add the operator class name
761                  */
762                 if (!colno)
763                         get_opclass_name(idxrec->indclass[keyno], keycoltype,
764                                                          &buf);
765         }
766
767         if (!colno)
768         {
769                 appendStringInfoChar(&buf, ')');
770
771                 /*
772                  * If the index is in a different tablespace from its parent,
773                  * tell about that
774                  */
775                 if (OidIsValid(idxrelrec->reltablespace) &&
776                         idxrelrec->reltablespace != get_rel_tablespace(indrelid))
777                 {
778                         char    *spcname = get_tablespace_name(idxrelrec->reltablespace);
779
780                         if (spcname)            /* just paranoia... */
781                         {
782                                 appendStringInfo(&buf, " TABLESPACE %s",
783                                                                  quote_identifier(spcname));
784                                 pfree(spcname);
785                         }
786                 }
787
788                 /*
789                  * If it's a partial index, decompile and append the predicate
790                  */
791                 if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
792                 {
793                         Node       *node;
794                         Datum           predDatum;
795                         bool            isnull;
796                         char       *predString;
797
798                         /* Convert text string to node tree */
799                         predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
800                                                                                 Anum_pg_index_indpred, &isnull);
801                         Assert(!isnull);
802                         predString = DatumGetCString(DirectFunctionCall1(textout,
803                                                                                                                          predDatum));
804                         node = (Node *) stringToNode(predString);
805                         pfree(predString);
806
807                         /* Deparse */
808                         str = deparse_expression_pretty(node, context, false, false,
809                                                                                         prettyFlags, 0);
810                         appendStringInfo(&buf, " WHERE %s", str);
811                 }
812         }
813
814         /* Clean up */
815         ReleaseSysCache(ht_idx);
816         ReleaseSysCache(ht_idxrel);
817         ReleaseSysCache(ht_am);
818
819         return buf.data;
820 }
821
822
823 /*
824  * pg_get_constraintdef
825  *
826  * Returns the definition for the constraint, ie, everything that needs to
827  * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
828  */
829 Datum
830 pg_get_constraintdef(PG_FUNCTION_ARGS)
831 {
832         Oid                     constraintId = PG_GETARG_OID(0);
833
834         PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,
835                                                                                                                                 false, 0)));
836 }
837
838 Datum
839 pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
840 {
841         Oid                     constraintId = PG_GETARG_OID(0);
842         bool            pretty = PG_GETARG_BOOL(1);
843         int                     prettyFlags;
844
845         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
846         PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,
847                                                                                                                                 false, prettyFlags)));
848 }
849
850 /* Internal version that returns a palloc'd C string */
851 char *
852 pg_get_constraintdef_string(Oid constraintId)
853 {
854         return pg_get_constraintdef_worker(constraintId, true, 0);
855 }
856
857 static char *
858 pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
859                                                         int prettyFlags)
860 {
861         StringInfoData buf;
862         Relation        conDesc;
863         SysScanDesc conscan;
864         ScanKeyData skey[1];
865         HeapTuple       tup;
866         Form_pg_constraint conForm;
867
868         /*
869          * Fetch the pg_constraint row.  There's no syscache for pg_constraint
870          * so we must do it the hard way.
871          */
872         conDesc = heap_openr(ConstraintRelationName, AccessShareLock);
873
874         ScanKeyInit(&skey[0],
875                                 ObjectIdAttributeNumber,
876                                 BTEqualStrategyNumber, F_OIDEQ,
877                                 ObjectIdGetDatum(constraintId));
878
879         conscan = systable_beginscan(conDesc, ConstraintOidIndex, true,
880                                                                  SnapshotNow, 1, skey);
881
882         tup = systable_getnext(conscan);
883         if (!HeapTupleIsValid(tup))
884                 elog(ERROR, "could not find tuple for constraint %u", constraintId);
885         conForm = (Form_pg_constraint) GETSTRUCT(tup);
886
887         initStringInfo(&buf);
888
889         if (fullCommand && OidIsValid(conForm->conrelid))
890         {
891                 appendStringInfo(&buf, "ALTER TABLE ONLY %s ADD CONSTRAINT %s ",
892                                                  generate_relation_name(conForm->conrelid),
893                                                  quote_identifier(NameStr(conForm->conname)));
894         }
895
896         switch (conForm->contype)
897         {
898                 case CONSTRAINT_FOREIGN:
899                         {
900                                 Datum           val;
901                                 bool            isnull;
902                                 const char *string;
903
904                                 /* Start off the constraint definition */
905                                 appendStringInfo(&buf, "FOREIGN KEY (");
906
907                                 /* Fetch and build referencing-column list */
908                                 val = heap_getattr(tup, Anum_pg_constraint_conkey,
909                                                                    RelationGetDescr(conDesc), &isnull);
910                                 if (isnull)
911                                         elog(ERROR, "null conkey for constraint %u",
912                                                  constraintId);
913
914                                 decompile_column_index_array(val, conForm->conrelid, &buf);
915
916                                 /* add foreign relation name */
917                                 appendStringInfo(&buf, ") REFERENCES %s(",
918                                                          generate_relation_name(conForm->confrelid));
919
920                                 /* Fetch and build referenced-column list */
921                                 val = heap_getattr(tup, Anum_pg_constraint_confkey,
922                                                                    RelationGetDescr(conDesc), &isnull);
923                                 if (isnull)
924                                         elog(ERROR, "null confkey for constraint %u",
925                                                  constraintId);
926
927                                 decompile_column_index_array(val, conForm->confrelid, &buf);
928
929                                 appendStringInfo(&buf, ")");
930
931                                 /* Add match type */
932                                 switch (conForm->confmatchtype)
933                                 {
934                                         case FKCONSTR_MATCH_FULL:
935                                                 string = " MATCH FULL";
936                                                 break;
937                                         case FKCONSTR_MATCH_PARTIAL:
938                                                 string = " MATCH PARTIAL";
939                                                 break;
940                                         case FKCONSTR_MATCH_UNSPECIFIED:
941                                                 string = "";
942                                                 break;
943                                         default:
944                                                 elog(ERROR, "unrecognized confmatchtype: %d",
945                                                          conForm->confmatchtype);
946                                                 string = "";    /* keep compiler quiet */
947                                                 break;
948                                 }
949                                 appendStringInfoString(&buf, string);
950
951                                 /* Add ON UPDATE and ON DELETE clauses, if needed */
952                                 switch (conForm->confupdtype)
953                                 {
954                                         case FKCONSTR_ACTION_NOACTION:
955                                                 string = NULL;  /* suppress default */
956                                                 break;
957                                         case FKCONSTR_ACTION_RESTRICT:
958                                                 string = "RESTRICT";
959                                                 break;
960                                         case FKCONSTR_ACTION_CASCADE:
961                                                 string = "CASCADE";
962                                                 break;
963                                         case FKCONSTR_ACTION_SETNULL:
964                                                 string = "SET NULL";
965                                                 break;
966                                         case FKCONSTR_ACTION_SETDEFAULT:
967                                                 string = "SET DEFAULT";
968                                                 break;
969                                         default:
970                                                 elog(ERROR, "unrecognized confupdtype: %d",
971                                                          conForm->confupdtype);
972                                                 string = NULL;  /* keep compiler quiet */
973                                                 break;
974                                 }
975                                 if (string)
976                                         appendStringInfo(&buf, " ON UPDATE %s", string);
977
978                                 switch (conForm->confdeltype)
979                                 {
980                                         case FKCONSTR_ACTION_NOACTION:
981                                                 string = NULL;  /* suppress default */
982                                                 break;
983                                         case FKCONSTR_ACTION_RESTRICT:
984                                                 string = "RESTRICT";
985                                                 break;
986                                         case FKCONSTR_ACTION_CASCADE:
987                                                 string = "CASCADE";
988                                                 break;
989                                         case FKCONSTR_ACTION_SETNULL:
990                                                 string = "SET NULL";
991                                                 break;
992                                         case FKCONSTR_ACTION_SETDEFAULT:
993                                                 string = "SET DEFAULT";
994                                                 break;
995                                         default:
996                                                 elog(ERROR, "unrecognized confdeltype: %d",
997                                                          conForm->confdeltype);
998                                                 string = NULL;  /* keep compiler quiet */
999                                                 break;
1000                                 }
1001                                 if (string)
1002                                         appendStringInfo(&buf, " ON DELETE %s", string);
1003
1004                                 if (conForm->condeferrable)
1005                                         appendStringInfo(&buf, " DEFERRABLE");
1006                                 if (conForm->condeferred)
1007                                         appendStringInfo(&buf, " INITIALLY DEFERRED");
1008
1009                                 break;
1010                         }
1011                 case CONSTRAINT_PRIMARY:
1012                 case CONSTRAINT_UNIQUE:
1013                         {
1014                                 Datum           val;
1015                                 bool            isnull;
1016
1017                                 /* Start off the constraint definition */
1018                                 if (conForm->contype == CONSTRAINT_PRIMARY)
1019                                         appendStringInfo(&buf, "PRIMARY KEY (");
1020                                 else
1021                                         appendStringInfo(&buf, "UNIQUE (");
1022
1023                                 /* Fetch and build target column list */
1024                                 val = heap_getattr(tup, Anum_pg_constraint_conkey,
1025                                                                    RelationGetDescr(conDesc), &isnull);
1026                                 if (isnull)
1027                                         elog(ERROR, "null conkey for constraint %u",
1028                                                  constraintId);
1029
1030                                 decompile_column_index_array(val, conForm->conrelid, &buf);
1031
1032                                 appendStringInfo(&buf, ")");
1033
1034                                 break;
1035                         }
1036                 case CONSTRAINT_CHECK:
1037                         {
1038                                 Datum           val;
1039                                 bool            isnull;
1040                                 char       *conbin;
1041                                 char       *consrc;
1042                                 Node       *expr;
1043                                 List       *context;
1044
1045                                 /* Fetch constraint expression in parsetree form */
1046                                 val = heap_getattr(tup, Anum_pg_constraint_conbin,
1047                                                                    RelationGetDescr(conDesc), &isnull);
1048                                 if (isnull)
1049                                         elog(ERROR, "null conbin for constraint %u",
1050                                                  constraintId);
1051
1052                                 conbin = DatumGetCString(DirectFunctionCall1(textout, val));
1053                                 expr = stringToNode(conbin);
1054
1055                                 /* Set up deparsing context for Var nodes in constraint */
1056                                 if (conForm->conrelid != InvalidOid)
1057                                 {
1058                                         /* relation constraint */
1059                                         context = deparse_context_for(get_rel_name(conForm->conrelid),
1060                                                                                                   conForm->conrelid);
1061                                 }
1062                                 else
1063                                 {
1064                                         /* domain constraint --- can't have Vars */
1065                                         context = NIL;
1066                                 }
1067
1068                                 consrc = deparse_expression_pretty(expr, context, false, false,
1069                                                                                                    prettyFlags, 0);
1070
1071                                 /*
1072                                  * Now emit the constraint definition.  There are cases where
1073                                  * the constraint expression will be fully parenthesized and
1074                                  * we don't need the outer parens ... but there are other
1075                                  * cases where we do need 'em.  Be conservative for now.
1076                                  *
1077                                  * Note that simply checking for leading '(' and trailing ')'
1078                                  * would NOT be good enough, consider "(x > 0) AND (y > 0)".
1079                                  */
1080                                 appendStringInfo(&buf, "CHECK (%s)", consrc);
1081
1082                                 break;
1083                         }
1084                 default:
1085                         elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
1086                         break;
1087         }
1088
1089         /* Cleanup */
1090         systable_endscan(conscan);
1091         heap_close(conDesc, AccessShareLock);
1092
1093         return buf.data;
1094 }
1095
1096
1097 /*
1098  * Convert an int16[] Datum into a comma-separated list of column names
1099  * for the indicated relation; append the list to buf.
1100  */
1101 static void
1102 decompile_column_index_array(Datum column_index_array, Oid relId,
1103                                                          StringInfo buf)
1104 {
1105         Datum      *keys;
1106         int                     nKeys;
1107         int                     j;
1108
1109         /* Extract data from array of int16 */
1110         deconstruct_array(DatumGetArrayTypeP(column_index_array),
1111                                           INT2OID, 2, true, 's',
1112                                           &keys, &nKeys);
1113
1114         for (j = 0; j < nKeys; j++)
1115         {
1116                 char       *colName;
1117
1118                 colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j]));
1119
1120                 if (j == 0)
1121                         appendStringInfoString(buf, quote_identifier(colName));
1122                 else
1123                         appendStringInfo(buf, ", %s", quote_identifier(colName));
1124         }
1125 }
1126
1127
1128 /* ----------
1129  * get_expr                     - Decompile an expression tree
1130  *
1131  * Input: an expression tree in nodeToString form, and a relation OID
1132  *
1133  * Output: reverse-listed expression
1134  *
1135  * Currently, the expression can only refer to a single relation, namely
1136  * the one specified by the second parameter.  This is sufficient for
1137  * partial indexes, column default expressions, etc.
1138  * ----------
1139  */
1140 Datum
1141 pg_get_expr(PG_FUNCTION_ARGS)
1142 {
1143         text       *expr = PG_GETARG_TEXT_P(0);
1144         Oid                     relid = PG_GETARG_OID(1);
1145         char       *relname;
1146
1147         /* Get the name for the relation */
1148         relname = get_rel_name(relid);
1149         if (relname == NULL)
1150                 PG_RETURN_NULL();               /* should we raise an error? */
1151
1152         PG_RETURN_TEXT_P(string_to_text(pg_get_expr_worker(expr, relid, relname, 0)));
1153 }
1154
1155 Datum
1156 pg_get_expr_ext(PG_FUNCTION_ARGS)
1157 {
1158         text       *expr = PG_GETARG_TEXT_P(0);
1159         Oid                     relid = PG_GETARG_OID(1);
1160         bool            pretty = PG_GETARG_BOOL(2);
1161         int                     prettyFlags;
1162         char       *relname;
1163
1164         prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
1165
1166         /* Get the name for the relation */
1167         relname = get_rel_name(relid);
1168         if (relname == NULL)
1169                 PG_RETURN_NULL();               /* should we raise an error? */
1170
1171         PG_RETURN_TEXT_P(string_to_text(pg_get_expr_worker(expr, relid, relname, prettyFlags)));
1172 }
1173
1174 static char *
1175 pg_get_expr_worker(text *expr, Oid relid, char *relname, int prettyFlags)
1176 {
1177         Node       *node;
1178         List       *context;
1179         char       *exprstr;
1180         char       *str;
1181
1182         /* Convert input TEXT object to C string */
1183         exprstr = DatumGetCString(DirectFunctionCall1(textout,
1184                                                                                                   PointerGetDatum(expr)));
1185
1186         /* Convert expression to node tree */
1187         node = (Node *) stringToNode(exprstr);
1188
1189         /* Deparse */
1190         context = deparse_context_for(relname, relid);
1191         str = deparse_expression_pretty(node, context, false, false,
1192                                                                         prettyFlags, 0);
1193
1194         return str;
1195 }
1196
1197
1198 /* ----------
1199  * get_userbyid                 - Get a user name by usesysid and
1200  *                                fallback to 'unknown (UID=n)'
1201  * ----------
1202  */
1203 Datum
1204 pg_get_userbyid(PG_FUNCTION_ARGS)
1205 {
1206         int32           uid = PG_GETARG_INT32(0);
1207         Name            result;
1208         HeapTuple       usertup;
1209         Form_pg_shadow user_rec;
1210
1211         /*
1212          * Allocate space for the result
1213          */
1214         result = (Name) palloc(NAMEDATALEN);
1215         memset(NameStr(*result), 0, NAMEDATALEN);
1216
1217         /*
1218          * Get the pg_shadow entry and print the result
1219          */
1220         usertup = SearchSysCache(SHADOWSYSID,
1221                                                          ObjectIdGetDatum(uid),
1222                                                          0, 0, 0);
1223         if (HeapTupleIsValid(usertup))
1224         {
1225                 user_rec = (Form_pg_shadow) GETSTRUCT(usertup);
1226                 StrNCpy(NameStr(*result), NameStr(user_rec->usename), NAMEDATALEN);
1227                 ReleaseSysCache(usertup);
1228         }
1229         else
1230                 sprintf(NameStr(*result), "unknown (UID=%d)", uid);
1231
1232         PG_RETURN_NAME(result);
1233 }
1234
1235 /* ----------
1236  * deparse_expression                   - General utility for deparsing expressions
1237  *
1238  * calls deparse_expression_pretty with all prettyPrinting disabled
1239  */
1240 char *
1241 deparse_expression(Node *expr, List *dpcontext,
1242                                    bool forceprefix, bool showimplicit)
1243 {
1244         return deparse_expression_pretty(expr, dpcontext, forceprefix,
1245                                                                          showimplicit, 0, 0);
1246 }
1247
1248 /* ----------
1249  * deparse_expression_pretty    - General utility for deparsing expressions
1250  *
1251  * expr is the node tree to be deparsed.  It must be a transformed expression
1252  * tree (ie, not the raw output of gram.y).
1253  *
1254  * dpcontext is a list of deparse_namespace nodes representing the context
1255  * for interpreting Vars in the node tree.
1256  *
1257  * forceprefix is TRUE to force all Vars to be prefixed with their table names.
1258  *
1259  * showimplicit is TRUE to force all implicit casts to be shown explicitly.
1260  *
1261  * tries to pretty up the output according to prettyFlags and startIndent.
1262  *
1263  * The result is a palloc'd string.
1264  * ----------
1265  */
1266 static char *
1267 deparse_expression_pretty(Node *expr, List *dpcontext,
1268                                                   bool forceprefix, bool showimplicit,
1269                                                   int prettyFlags, int startIndent)
1270 {
1271         StringInfoData buf;
1272         deparse_context context;
1273
1274         initStringInfo(&buf);
1275         context.buf = &buf;
1276         context.namespaces = dpcontext;
1277         context.varprefix = forceprefix;
1278         context.prettyFlags = prettyFlags;
1279         context.indentLevel = startIndent;
1280
1281         get_rule_expr(expr, &context, showimplicit);
1282
1283         return buf.data;
1284 }
1285
1286 /* ----------
1287  * deparse_context_for                  - Build deparse context for a single relation
1288  *
1289  * Given the reference name (alias) and OID of a relation, build deparsing
1290  * context for an expression referencing only that relation (as varno 1,
1291  * varlevelsup 0).      This is sufficient for many uses of deparse_expression.
1292  * ----------
1293  */
1294 List *
1295 deparse_context_for(const char *aliasname, Oid relid)
1296 {
1297         deparse_namespace *dpns;
1298         RangeTblEntry *rte;
1299
1300         dpns = (deparse_namespace *) palloc(sizeof(deparse_namespace));
1301
1302         /* Build a minimal RTE for the rel */
1303         rte = makeNode(RangeTblEntry);
1304         rte->rtekind = RTE_RELATION;
1305         rte->relid = relid;
1306         rte->eref = makeAlias(aliasname, NIL);
1307         rte->inh = false;
1308         rte->inFromCl = true;
1309
1310         /* Build one-element rtable */
1311         dpns->rtable = list_make1(rte);
1312         dpns->outer_varno = dpns->inner_varno = 0;
1313         dpns->outer_rte = dpns->inner_rte = NULL;
1314
1315         /* Return a one-deep namespace stack */
1316         return list_make1(dpns);
1317 }
1318
1319 /*
1320  * deparse_context_for_plan             - Build deparse context for a plan node
1321  *
1322  * We assume we are dealing with an upper-level plan node having either
1323  * one or two referenceable children (pass innercontext = NULL if only one).
1324  * The passed-in Nodes should be made using deparse_context_for_subplan
1325  * and/or deparse_context_for_relation.  The resulting context will work
1326  * for deparsing quals, tlists, etc of the plan node.
1327  *
1328  * An rtable list can also be passed in case plain Vars might be seen.
1329  * This is not needed for true upper-level expressions, but is helpful for
1330  * Sort nodes and similar cases with slightly bogus targetlists.
1331  */
1332 List *
1333 deparse_context_for_plan(int outer_varno, Node *outercontext,
1334                                                  int inner_varno, Node *innercontext,
1335                                                  List *rtable)
1336 {
1337         deparse_namespace *dpns;
1338
1339         dpns = (deparse_namespace *) palloc(sizeof(deparse_namespace));
1340
1341         dpns->rtable = rtable;
1342         dpns->outer_varno = outer_varno;
1343         dpns->outer_rte = (RangeTblEntry *) outercontext;
1344         dpns->inner_varno = inner_varno;
1345         dpns->inner_rte = (RangeTblEntry *) innercontext;
1346
1347         /* Return a one-deep namespace stack */
1348         return list_make1(dpns);
1349 }
1350
1351 /*
1352  * deparse_context_for_rte              - Build deparse context for 1 relation
1353  *
1354  * Helper routine to build one of the inputs for deparse_context_for_plan.
1355  *
1356  * The returned node is actually the given RangeTblEntry, but we declare it
1357  * as just Node to discourage callers from assuming anything.
1358  */
1359 Node *
1360 deparse_context_for_rte(RangeTblEntry *rte)
1361 {
1362         return (Node *) rte;
1363 }
1364
1365 /*
1366  * deparse_context_for_subplan  - Build deparse context for a plan node
1367  *
1368  * Helper routine to build one of the inputs for deparse_context_for_plan.
1369  * Pass the tlist of the subplan node, plus the query rangetable.
1370  *
1371  * The returned node is actually a RangeTblEntry, but we declare it as just
1372  * Node to discourage callers from assuming anything.
1373  */
1374 Node *
1375 deparse_context_for_subplan(const char *name, List *tlist,
1376                                                         List *rtable)
1377 {
1378         RangeTblEntry *rte = makeNode(RangeTblEntry);
1379         List       *attrs = NIL;
1380         int                     nattrs = 0;
1381         int                     rtablelength = list_length(rtable);
1382         ListCell   *tl;
1383         char            buf[32];
1384
1385         foreach(tl, tlist)
1386         {
1387                 TargetEntry *tle = lfirst(tl);
1388                 Resdom     *resdom = tle->resdom;
1389
1390                 nattrs++;
1391                 Assert(resdom->resno == nattrs);
1392                 if (resdom->resname)
1393                 {
1394                         attrs = lappend(attrs, makeString(resdom->resname));
1395                         continue;
1396                 }
1397                 if (tle->expr && IsA(tle->expr, Var))
1398                 {
1399                         Var                *var = (Var *) tle->expr;
1400
1401                         /* varno/varattno won't be any good, but varnoold might be */
1402                         if (var->varnoold > 0 && var->varnoold <= rtablelength)
1403                         {
1404                                 RangeTblEntry *varrte = rt_fetch(var->varnoold, rtable);
1405                                 char       *varname;
1406
1407                                 varname = get_rte_attribute_name(varrte, var->varoattno);
1408                                 attrs = lappend(attrs, makeString(varname));
1409                                 continue;
1410                         }
1411                 }
1412                 /* Fallback if can't get name */
1413                 snprintf(buf, sizeof(buf), "?column%d?", resdom->resno);
1414                 attrs = lappend(attrs, makeString(pstrdup(buf)));
1415         }
1416
1417         rte->rtekind = RTE_SPECIAL; /* XXX */
1418         rte->relid = InvalidOid;
1419         rte->eref = makeAlias(name, attrs);
1420         rte->inh = false;
1421         rte->inFromCl = true;
1422
1423         return (Node *) rte;
1424 }
1425
1426 /* ----------
1427  * make_ruledef                 - reconstruct the CREATE RULE command
1428  *                                for a given pg_rewrite tuple
1429  * ----------
1430  */
1431 static void
1432 make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
1433                          int prettyFlags)
1434 {
1435         char       *rulename;
1436         char            ev_type;
1437         Oid                     ev_class;
1438         int2            ev_attr;
1439         bool            is_instead;
1440         char       *ev_qual;
1441         char       *ev_action;
1442         List       *actions = NIL;
1443         int                     fno;
1444         Datum           dat;
1445         bool            isnull;
1446
1447         /*
1448          * Get the attribute values from the rules tuple
1449          */
1450         fno = SPI_fnumber(rulettc, "rulename");
1451         dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
1452         Assert(!isnull);
1453         rulename = NameStr(*(DatumGetName(dat)));
1454
1455         fno = SPI_fnumber(rulettc, "ev_type");
1456         dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
1457         Assert(!isnull);
1458         ev_type = DatumGetChar(dat);
1459
1460         fno = SPI_fnumber(rulettc, "ev_class");
1461         dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
1462         Assert(!isnull);
1463         ev_class = DatumGetObjectId(dat);
1464
1465         fno = SPI_fnumber(rulettc, "ev_attr");
1466         dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
1467         Assert(!isnull);
1468         ev_attr = DatumGetInt16(dat);
1469
1470         fno = SPI_fnumber(rulettc, "is_instead");
1471         dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
1472         Assert(!isnull);
1473         is_instead = DatumGetBool(dat);
1474
1475         /* these could be nulls */
1476         fno = SPI_fnumber(rulettc, "ev_qual");
1477         ev_qual = SPI_getvalue(ruletup, rulettc, fno);
1478
1479         fno = SPI_fnumber(rulettc, "ev_action");
1480         ev_action = SPI_getvalue(ruletup, rulettc, fno);
1481         if (ev_action != NULL)
1482                 actions = (List *) stringToNode(ev_action);
1483
1484         /*
1485          * Build the rules definition text
1486          */
1487         appendStringInfo(buf, "CREATE RULE %s AS",
1488                                          quote_identifier(rulename));
1489
1490         if (prettyFlags & PRETTYFLAG_INDENT)
1491                 appendStringInfoString(buf, "\n    ON ");
1492         else
1493                 appendStringInfoString(buf, " ON ");
1494
1495         /* The event the rule is fired for */
1496         switch (ev_type)
1497         {
1498                 case '1':
1499                         appendStringInfo(buf, "SELECT");
1500                         break;
1501
1502                 case '2':
1503                         appendStringInfo(buf, "UPDATE");
1504                         break;
1505
1506                 case '3':
1507                         appendStringInfo(buf, "INSERT");
1508                         break;
1509
1510                 case '4':
1511                         appendStringInfo(buf, "DELETE");
1512                         break;
1513
1514                 default:
1515                         ereport(ERROR,
1516                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1517                                          errmsg("rule \"%s\" has unsupported event type %d",
1518                                                         rulename, ev_type)));
1519                         break;
1520         }
1521
1522         /* The relation the rule is fired on */
1523         appendStringInfo(buf, " TO %s", generate_relation_name(ev_class));
1524         if (ev_attr > 0)
1525                 appendStringInfo(buf, ".%s",
1526                                           quote_identifier(get_relid_attribute_name(ev_class,
1527                                                                                                                           ev_attr)));
1528
1529         /* If the rule has an event qualification, add it */
1530         if (ev_qual == NULL)
1531                 ev_qual = "";
1532         if (strlen(ev_qual) > 0 && strcmp(ev_qual, "<>") != 0)
1533         {
1534                 Node       *qual;
1535                 Query      *query;
1536                 deparse_context context;
1537                 deparse_namespace dpns;
1538
1539                 if (prettyFlags & PRETTYFLAG_INDENT)
1540                         appendStringInfoString(buf, "\n  ");
1541                 appendStringInfo(buf, " WHERE ");
1542
1543                 qual = stringToNode(ev_qual);
1544
1545                 /*
1546                  * We need to make a context for recognizing any Vars in the qual
1547                  * (which can only be references to OLD and NEW).  Use the rtable
1548                  * of the first query in the action list for this purpose.
1549                  */
1550                 query = (Query *) linitial(actions);
1551
1552                 /*
1553                  * If the action is INSERT...SELECT, OLD/NEW have been pushed down
1554                  * into the SELECT, and that's what we need to look at. (Ugly
1555                  * kluge ... try to fix this when we redesign querytrees.)
1556                  */
1557                 query = getInsertSelectQuery(query, NULL);
1558
1559                 context.buf = buf;
1560                 context.namespaces = list_make1(&dpns);
1561                 context.varprefix = (list_length(query->rtable) != 1);
1562                 context.prettyFlags = prettyFlags;
1563                 context.indentLevel = PRETTYINDENT_STD;
1564                 dpns.rtable = query->rtable;
1565                 dpns.outer_varno = dpns.inner_varno = 0;
1566                 dpns.outer_rte = dpns.inner_rte = NULL;
1567
1568                 get_rule_expr(qual, &context, false);
1569         }
1570
1571         appendStringInfo(buf, " DO ");
1572
1573         /* The INSTEAD keyword (if so) */
1574         if (is_instead)
1575                 appendStringInfo(buf, "INSTEAD ");
1576
1577         /* Finally the rules actions */
1578         if (list_length(actions) > 1)
1579         {
1580                 ListCell   *action;
1581                 Query      *query;
1582
1583                 appendStringInfo(buf, "(");
1584                 foreach(action, actions)
1585                 {
1586                         query = (Query *) lfirst(action);
1587                         get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
1588                         if (prettyFlags)
1589                                 appendStringInfo(buf, ";\n");
1590                         else
1591                                 appendStringInfo(buf, "; ");
1592                 }
1593                 appendStringInfo(buf, ");");
1594         }
1595         else if (list_length(actions) == 0)
1596         {
1597                 appendStringInfo(buf, "NOTHING;");
1598         }
1599         else
1600         {
1601                 Query      *query;
1602
1603                 query = (Query *) linitial(actions);
1604                 get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
1605                 appendStringInfo(buf, ";");
1606         }
1607 }
1608
1609
1610 /* ----------
1611  * make_viewdef                 - reconstruct the SELECT part of a
1612  *                                view rewrite rule
1613  * ----------
1614  */
1615 static void
1616 make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
1617                          int prettyFlags)
1618 {
1619         Query      *query;
1620         char            ev_type;
1621         Oid                     ev_class;
1622         int2            ev_attr;
1623         bool            is_instead;
1624         char       *ev_qual;
1625         char       *ev_action;
1626         List       *actions = NIL;
1627         Relation        ev_relation;
1628         int                     fno;
1629         bool            isnull;
1630
1631         /*
1632          * Get the attribute values from the rules tuple
1633          */
1634         fno = SPI_fnumber(rulettc, "ev_type");
1635         ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
1636
1637         fno = SPI_fnumber(rulettc, "ev_class");
1638         ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull);
1639
1640         fno = SPI_fnumber(rulettc, "ev_attr");
1641         ev_attr = (int2) SPI_getbinval(ruletup, rulettc, fno, &isnull);
1642
1643         fno = SPI_fnumber(rulettc, "is_instead");
1644         is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);
1645
1646         fno = SPI_fnumber(rulettc, "ev_qual");
1647         ev_qual = SPI_getvalue(ruletup, rulettc, fno);
1648
1649         fno = SPI_fnumber(rulettc, "ev_action");
1650         ev_action = SPI_getvalue(ruletup, rulettc, fno);
1651         if (ev_action != NULL)
1652                 actions = (List *) stringToNode(ev_action);
1653
1654         if (list_length(actions) != 1)
1655         {
1656                 appendStringInfo(buf, "Not a view");
1657                 return;
1658         }
1659
1660         query = (Query *) linitial(actions);
1661
1662         if (ev_type != '1' || ev_attr >= 0 || !is_instead ||
1663                 strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
1664         {
1665                 appendStringInfo(buf, "Not a view");
1666                 return;
1667         }
1668
1669         ev_relation = heap_open(ev_class, AccessShareLock);
1670
1671         get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),
1672                                   prettyFlags, 0);
1673         appendStringInfo(buf, ";");
1674
1675         heap_close(ev_relation, AccessShareLock);
1676 }
1677
1678
1679 /* ----------
1680  * get_query_def                        - Parse back one query parsetree
1681  *
1682  * If resultDesc is not NULL, then it is the output tuple descriptor for
1683  * the view represented by a SELECT query.
1684  * ----------
1685  */
1686 static void
1687 get_query_def(Query *query, StringInfo buf, List *parentnamespace,
1688                           TupleDesc resultDesc, int prettyFlags, int startIndent)
1689 {
1690         deparse_context context;
1691         deparse_namespace dpns;
1692
1693         context.buf = buf;
1694         context.namespaces = lcons(&dpns, list_copy(parentnamespace));
1695         context.varprefix = (parentnamespace != NIL ||
1696                                                  list_length(query->rtable) != 1);
1697         context.prettyFlags = prettyFlags;
1698         context.indentLevel = startIndent;
1699
1700         dpns.rtable = query->rtable;
1701         dpns.outer_varno = dpns.inner_varno = 0;
1702         dpns.outer_rte = dpns.inner_rte = NULL;
1703
1704         switch (query->commandType)
1705         {
1706                 case CMD_SELECT:
1707                         get_select_query_def(query, &context, resultDesc);
1708                         break;
1709
1710                 case CMD_UPDATE:
1711                         get_update_query_def(query, &context);
1712                         break;
1713
1714                 case CMD_INSERT:
1715                         get_insert_query_def(query, &context);
1716                         break;
1717
1718                 case CMD_DELETE:
1719                         get_delete_query_def(query, &context);
1720                         break;
1721
1722                 case CMD_NOTHING:
1723                         appendStringInfo(buf, "NOTHING");
1724                         break;
1725
1726                 case CMD_UTILITY:
1727                         get_utility_query_def(query, &context);
1728                         break;
1729
1730                 default:
1731                         elog(ERROR, "unrecognized query command type: %d",
1732                                  query->commandType);
1733                         break;
1734         }
1735 }
1736
1737
1738 /* ----------
1739  * get_select_query_def                 - Parse back a SELECT parsetree
1740  * ----------
1741  */
1742 static void
1743 get_select_query_def(Query *query, deparse_context *context,
1744                                          TupleDesc resultDesc)
1745 {
1746         StringInfo      buf = context->buf;
1747         bool            force_colno;
1748         char       *sep;
1749         ListCell   *l;
1750
1751         /*
1752          * If the Query node has a setOperations tree, then it's the top level
1753          * of a UNION/INTERSECT/EXCEPT query; only the ORDER BY and LIMIT
1754          * fields are interesting in the top query itself.
1755          */
1756         if (query->setOperations)
1757         {
1758                 get_setop_query(query->setOperations, query, context, resultDesc);
1759                 /* ORDER BY clauses must be simple in this case */
1760                 force_colno = true;
1761         }
1762         else
1763         {
1764                 get_basic_select_query(query, context, resultDesc);
1765                 force_colno = false;
1766         }
1767
1768         /* Add the ORDER BY clause if given */
1769         if (query->sortClause != NIL)
1770         {
1771                 appendContextKeyword(context, " ORDER BY ",
1772                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
1773                 sep = "";
1774                 foreach(l, query->sortClause)
1775                 {
1776                         SortClause *srt = (SortClause *) lfirst(l);
1777                         Node       *sortexpr;
1778                         Oid                     sortcoltype;
1779                         TypeCacheEntry *typentry;
1780
1781                         appendStringInfo(buf, sep);
1782                         sortexpr = get_rule_sortgroupclause(srt, query->targetList,
1783                                                                                                 force_colno, context);
1784                         sortcoltype = exprType(sortexpr);
1785                         /* See whether operator is default < or > for datatype */
1786                         typentry = lookup_type_cache(sortcoltype,
1787                                                                                  TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
1788                         if (srt->sortop == typentry->lt_opr)
1789                                 /* ASC is default, so emit nothing */ ;
1790                         else if (srt->sortop == typentry->gt_opr)
1791                                 appendStringInfo(buf, " DESC");
1792                         else
1793                                 appendStringInfo(buf, " USING %s",
1794                                                                  generate_operator_name(srt->sortop,
1795                                                                                                                 sortcoltype,
1796                                                                                                                 sortcoltype));
1797                         sep = ", ";
1798                 }
1799         }
1800
1801         /* Add the LIMIT clause if given */
1802         if (query->limitOffset != NULL)
1803         {
1804                 appendContextKeyword(context, " OFFSET ",
1805                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
1806                 get_rule_expr(query->limitOffset, context, false);
1807         }
1808         if (query->limitCount != NULL)
1809         {
1810                 appendContextKeyword(context, " LIMIT ",
1811                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
1812                 if (IsA(query->limitCount, Const) &&
1813                         ((Const *) query->limitCount)->constisnull)
1814                         appendStringInfo(buf, "ALL");
1815                 else
1816                         get_rule_expr(query->limitCount, context, false);
1817         }
1818 }
1819
1820 static void
1821 get_basic_select_query(Query *query, deparse_context *context,
1822                                            TupleDesc resultDesc)
1823 {
1824         StringInfo      buf = context->buf;
1825         char       *sep;
1826         ListCell   *l;
1827         int                     colno;
1828
1829         /*
1830          * Build up the query string - first we say SELECT
1831          */
1832         if (PRETTY_INDENT(context))
1833         {
1834                 context->indentLevel += PRETTYINDENT_STD;
1835                 appendStringInfoChar(buf, ' ');
1836         }
1837         appendStringInfo(buf, "SELECT");
1838
1839         /* Add the DISTINCT clause if given */
1840         if (query->distinctClause != NIL)
1841         {
1842                 if (has_distinct_on_clause(query))
1843                 {
1844                         appendStringInfo(buf, " DISTINCT ON (");
1845                         sep = "";
1846                         foreach(l, query->distinctClause)
1847                         {
1848                                 SortClause *srt = (SortClause *) lfirst(l);
1849
1850                                 appendStringInfo(buf, sep);
1851                                 get_rule_sortgroupclause(srt, query->targetList,
1852                                                                                  false, context);
1853                                 sep = ", ";
1854                         }
1855                         appendStringInfo(buf, ")");
1856                 }
1857                 else
1858                         appendStringInfo(buf, " DISTINCT");
1859         }
1860
1861         /* Then we tell what to select (the targetlist) */
1862         sep = " ";
1863         colno = 0;
1864         foreach(l, query->targetList)
1865         {
1866                 TargetEntry *tle = (TargetEntry *) lfirst(l);
1867                 char       *colname;
1868
1869                 if (tle->resdom->resjunk)
1870                         continue;                       /* ignore junk entries */
1871
1872                 appendStringInfo(buf, sep);
1873                 sep = ", ";
1874                 colno++;
1875
1876                 get_rule_expr((Node *) tle->expr, context, true);
1877
1878                 /*
1879                  * Figure out what the result column should be called.  In the
1880                  * context of a view, use the view's tuple descriptor (so as to
1881                  * pick up the effects of any column RENAME that's been done on
1882                  * the view).  Otherwise, just use what we can find in the TLE.
1883                  */
1884                 if (resultDesc && colno <= resultDesc->natts)
1885                         colname = NameStr(resultDesc->attrs[colno - 1]->attname);
1886                 else
1887                         colname = tle->resdom->resname;
1888
1889                 if (colname)                    /* resname could be NULL */
1890                 {
1891                         /* Check if we must say AS ... */
1892                         bool            tell_as;
1893
1894                         if (!IsA(tle->expr, Var))
1895                                 tell_as = (strcmp(colname, "?column?") != 0);
1896                         else
1897                         {
1898                                 Var                *var = (Var *) (tle->expr);
1899                                 char       *schemaname;
1900                                 char       *refname;
1901                                 char       *attname;
1902
1903                                 get_names_for_var(var, context,
1904                                                                   &schemaname, &refname, &attname);
1905                                 tell_as = (attname == NULL ||
1906                                                    strcmp(attname, colname) != 0);
1907                         }
1908
1909                         /* and do if so */
1910                         if (tell_as)
1911                                 appendStringInfo(buf, " AS %s", quote_identifier(colname));
1912                 }
1913         }
1914
1915         /* Add the FROM clause if needed */
1916         get_from_clause(query, context);
1917
1918         /* Add the WHERE clause if given */
1919         if (query->jointree->quals != NULL)
1920         {
1921                 appendContextKeyword(context, " WHERE ",
1922                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
1923                 get_rule_expr(query->jointree->quals, context, false);
1924         }
1925
1926         /* Add the GROUP BY clause if given */
1927         if (query->groupClause != NULL)
1928         {
1929                 appendContextKeyword(context, " GROUP BY ",
1930                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
1931                 sep = "";
1932                 foreach(l, query->groupClause)
1933                 {
1934                         GroupClause *grp = (GroupClause *) lfirst(l);
1935
1936                         appendStringInfo(buf, sep);
1937                         get_rule_sortgroupclause(grp, query->targetList,
1938                                                                          false, context);
1939                         sep = ", ";
1940                 }
1941         }
1942
1943         /* Add the HAVING clause if given */
1944         if (query->havingQual != NULL)
1945         {
1946                 appendContextKeyword(context, " HAVING ",
1947                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
1948                 get_rule_expr(query->havingQual, context, false);
1949         }
1950 }
1951
1952 static void
1953 get_setop_query(Node *setOp, Query *query, deparse_context *context,
1954                                 TupleDesc resultDesc)
1955 {
1956         StringInfo      buf = context->buf;
1957
1958         if (IsA(setOp, RangeTblRef))
1959         {
1960                 RangeTblRef *rtr = (RangeTblRef *) setOp;
1961                 RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
1962                 Query      *subquery = rte->subquery;
1963
1964                 Assert(subquery != NULL);
1965                 get_query_def(subquery, buf, context->namespaces, resultDesc,
1966                                           context->prettyFlags, context->indentLevel);
1967         }
1968         else if (IsA(setOp, SetOperationStmt))
1969         {
1970                 SetOperationStmt *op = (SetOperationStmt *) setOp;
1971                 bool            need_paren;
1972
1973                 need_paren = (PRETTY_PAREN(context) ?
1974                                           !IsA(op->rarg, RangeTblRef) : true);
1975
1976                 if (!PRETTY_PAREN(context))
1977                         appendStringInfoString(buf, "((");
1978
1979                 get_setop_query(op->larg, query, context, resultDesc);
1980
1981                 if (!PRETTY_PAREN(context))
1982                         appendStringInfoChar(buf, ')');
1983                 if (!PRETTY_INDENT(context))
1984                         appendStringInfoChar(buf, ' ');
1985                 switch (op->op)
1986                 {
1987                         case SETOP_UNION:
1988                                 appendContextKeyword(context, "UNION ",
1989                                                                          -PRETTYINDENT_STD, 0, 0);
1990                                 break;
1991                         case SETOP_INTERSECT:
1992                                 appendContextKeyword(context, "INTERSECT ",
1993                                                                          -PRETTYINDENT_STD, 0, 0);
1994                                 break;
1995                         case SETOP_EXCEPT:
1996                                 appendContextKeyword(context, "EXCEPT ",
1997                                                                          -PRETTYINDENT_STD, 0, 0);
1998                                 break;
1999                         default:
2000                                 elog(ERROR, "unrecognized set op: %d",
2001                                          (int) op->op);
2002                 }
2003                 if (op->all)
2004                         appendStringInfo(buf, "ALL ");
2005
2006                 if (PRETTY_INDENT(context))
2007                         appendStringInfoChar(buf, '\n');
2008
2009                 if (PRETTY_PAREN(context))
2010                 {
2011                         if (need_paren)
2012                         {
2013                                 appendStringInfoChar(buf, '(');
2014                                 if (PRETTY_INDENT(context))
2015                                         appendStringInfoChar(buf, '\n');
2016                         }
2017                 }
2018                 else
2019                         appendStringInfoChar(buf, '(');
2020
2021                 get_setop_query(op->rarg, query, context, resultDesc);
2022
2023                 if (PRETTY_PAREN(context))
2024                 {
2025                         if (need_paren)
2026                                 appendStringInfoChar(buf, ')');
2027                 }
2028                 else
2029                         appendStringInfoString(buf, "))");
2030         }
2031         else
2032         {
2033                 elog(ERROR, "unrecognized node type: %d",
2034                          (int) nodeTag(setOp));
2035         }
2036 }
2037
2038 /*
2039  * Display a sort/group clause.
2040  *
2041  * Also returns the expression tree, so caller need not find it again.
2042  */
2043 static Node *
2044 get_rule_sortgroupclause(SortClause *srt, List *tlist, bool force_colno,
2045                                                  deparse_context *context)
2046 {
2047         StringInfo      buf = context->buf;
2048         TargetEntry *tle;
2049         Node       *expr;
2050
2051         tle = get_sortgroupclause_tle(srt, tlist);
2052         expr = (Node *) tle->expr;
2053
2054         /*
2055          * Use column-number form if requested by caller or if expression is a
2056          * constant --- a constant is ambiguous (and will be misinterpreted by
2057          * findTargetlistEntry()) if we dump it explicitly.
2058          */
2059         if (force_colno || (expr && IsA(expr, Const)))
2060         {
2061                 Assert(!tle->resdom->resjunk);
2062                 appendStringInfo(buf, "%d", tle->resdom->resno);
2063         }
2064         else
2065                 get_rule_expr(expr, context, true);
2066
2067         return expr;
2068 }
2069
2070 /* ----------
2071  * get_insert_query_def                 - Parse back an INSERT parsetree
2072  * ----------
2073  */
2074 static void
2075 get_insert_query_def(Query *query, deparse_context *context)
2076 {
2077         StringInfo      buf = context->buf;
2078         RangeTblEntry *select_rte = NULL;
2079         RangeTblEntry *rte;
2080         char       *sep;
2081         ListCell   *l;
2082         List       *strippedexprs;
2083
2084         /*
2085          * If it's an INSERT ... SELECT there will be a single subquery RTE
2086          * for the SELECT.
2087          */
2088         foreach(l, query->rtable)
2089         {
2090                 rte = (RangeTblEntry *) lfirst(l);
2091                 if (rte->rtekind != RTE_SUBQUERY)
2092                         continue;
2093                 if (select_rte)
2094                         elog(ERROR, "too many RTEs in INSERT");
2095                 select_rte = rte;
2096         }
2097
2098         /*
2099          * Start the query with INSERT INTO relname
2100          */
2101         rte = rt_fetch(query->resultRelation, query->rtable);
2102         Assert(rte->rtekind == RTE_RELATION);
2103
2104         if (PRETTY_INDENT(context))
2105         {
2106                 context->indentLevel += PRETTYINDENT_STD;
2107                 appendStringInfoChar(buf, ' ');
2108         }
2109         appendStringInfo(buf, "INSERT INTO %s (",
2110                                          generate_relation_name(rte->relid));
2111
2112         /*
2113          * Add the insert-column-names list, and make a list of the actual
2114          * assignment source expressions.
2115          */
2116         strippedexprs = NIL;
2117         sep = "";
2118         foreach(l, query->targetList)
2119         {
2120                 TargetEntry *tle = (TargetEntry *) lfirst(l);
2121
2122                 if (tle->resdom->resjunk)
2123                         continue;                       /* ignore junk entries */
2124
2125                 appendStringInfo(buf, sep);
2126                 sep = ", ";
2127
2128                 /*
2129                  * Put out name of target column; look in the catalogs, not at
2130                  * tle->resname, since resname will fail to track RENAME.
2131                  */
2132                 appendStringInfoString(buf,
2133                                                            quote_identifier(get_relid_attribute_name(rte->relid,
2134                                                                                                                                                  tle->resdom->resno)));
2135
2136                 /*
2137                  * Print any indirection needed (subfields or subscripts), and strip
2138                  * off the top-level nodes representing the indirection assignments.
2139                  */
2140                 strippedexprs = lappend(strippedexprs,
2141                                                                 processIndirection((Node *) tle->expr,
2142                                                                                                    context));
2143         }
2144         appendStringInfo(buf, ") ");
2145
2146         /* Add the VALUES or the SELECT */
2147         if (select_rte == NULL)
2148         {
2149                 appendContextKeyword(context, "VALUES (",
2150                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
2151                 sep = "";
2152                 foreach(l, strippedexprs)
2153                 {
2154                         Node   *expr = lfirst(l);
2155
2156                         appendStringInfo(buf, sep);
2157                         sep = ", ";
2158                         get_rule_expr(expr, context, false);
2159                 }
2160                 appendStringInfoChar(buf, ')');
2161         }
2162         else
2163                 get_query_def(select_rte->subquery, buf, NIL, NULL,
2164                                           context->prettyFlags, context->indentLevel);
2165 }
2166
2167
2168 /* ----------
2169  * get_update_query_def                 - Parse back an UPDATE parsetree
2170  * ----------
2171  */
2172 static void
2173 get_update_query_def(Query *query, deparse_context *context)
2174 {
2175         StringInfo               buf = context->buf;
2176         char                    *sep;
2177         RangeTblEntry   *rte;
2178         ListCell                *l;
2179
2180         /*
2181          * Start the query with UPDATE relname SET
2182          */
2183         rte = rt_fetch(query->resultRelation, query->rtable);
2184         Assert(rte->rtekind == RTE_RELATION);
2185         if (PRETTY_INDENT(context))
2186         {
2187                 appendStringInfoChar(buf, ' ');
2188                 context->indentLevel += PRETTYINDENT_STD;
2189         }
2190         appendStringInfo(buf, "UPDATE %s%s SET ",
2191                                          only_marker(rte),
2192                                          generate_relation_name(rte->relid));
2193
2194         /* Add the comma separated list of 'attname = value' */
2195         sep = "";
2196         foreach(l, query->targetList)
2197         {
2198                 TargetEntry *tle = (TargetEntry *) lfirst(l);
2199                 Node    *expr;
2200
2201                 if (tle->resdom->resjunk)
2202                         continue;                       /* ignore junk entries */
2203
2204                 appendStringInfo(buf, sep);
2205                 sep = ", ";
2206
2207                 /*
2208                  * Put out name of target column; look in the catalogs, not at
2209                  * tle->resname, since resname will fail to track RENAME.
2210                  */
2211                 appendStringInfoString(buf,
2212                                                 quote_identifier(get_relid_attribute_name(rte->relid,
2213                                                                                                                 tle->resdom->resno)));
2214
2215                 /*
2216                  * Print any indirection needed (subfields or subscripts), and strip
2217                  * off the top-level nodes representing the indirection assignments.
2218                  */
2219                 expr = processIndirection((Node *) tle->expr, context);
2220
2221                 appendStringInfo(buf, " = ");
2222
2223                 get_rule_expr(expr, context, false);
2224         }
2225
2226         /* Add the FROM clause if needed */
2227         get_from_clause(query, context);
2228
2229         /* Finally add a WHERE clause if given */
2230         if (query->jointree->quals != NULL)
2231         {
2232                 appendContextKeyword(context, " WHERE ",
2233                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2234                 get_rule_expr(query->jointree->quals, context, false);
2235         }
2236 }
2237
2238
2239 /* ----------
2240  * get_delete_query_def                 - Parse back a DELETE parsetree
2241  * ----------
2242  */
2243 static void
2244 get_delete_query_def(Query *query, deparse_context *context)
2245 {
2246         StringInfo      buf = context->buf;
2247         RangeTblEntry *rte;
2248
2249         /*
2250          * Start the query with DELETE FROM relname
2251          */
2252         rte = rt_fetch(query->resultRelation, query->rtable);
2253         Assert(rte->rtekind == RTE_RELATION);
2254         if (PRETTY_INDENT(context))
2255         {
2256                 context->indentLevel += PRETTYINDENT_STD;
2257                 appendStringInfoChar(buf, ' ');
2258         }
2259         appendStringInfo(buf, "DELETE FROM %s%s",
2260                                          only_marker(rte),
2261                                          generate_relation_name(rte->relid));
2262
2263         /* Add a WHERE clause if given */
2264         if (query->jointree->quals != NULL)
2265         {
2266                 appendContextKeyword(context, " WHERE ",
2267                                                          -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2268                 get_rule_expr(query->jointree->quals, context, false);
2269         }
2270 }
2271
2272
2273 /* ----------
2274  * get_utility_query_def                        - Parse back a UTILITY parsetree
2275  * ----------
2276  */
2277 static void
2278 get_utility_query_def(Query *query, deparse_context *context)
2279 {
2280         StringInfo      buf = context->buf;
2281
2282         if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
2283         {
2284                 NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
2285
2286                 appendContextKeyword(context, "",
2287                                                          0, PRETTYINDENT_STD, 1);
2288                 appendStringInfo(buf, "NOTIFY %s",
2289                                    quote_qualified_identifier(stmt->relation->schemaname,
2290                                                                                           stmt->relation->relname));
2291         }
2292         else
2293         {
2294                 /* Currently only NOTIFY utility commands can appear in rules */
2295                 elog(ERROR, "unexpected utility statement type");
2296         }
2297 }
2298
2299
2300 /*
2301  * Get the schemaname, refname and attname for a (possibly nonlocal) Var.
2302  *
2303  * schemaname is usually returned as NULL.      It will be non-null only if
2304  * use of the unqualified refname would find the wrong RTE.
2305  *
2306  * refname will be returned as NULL if the Var references an unnamed join.
2307  * In this case the Var *must* be displayed without any qualification.
2308  *
2309  * attname will be returned as NULL if the Var represents a whole tuple
2310  * of the relation.  (Typically we'd want to display the Var as "foo.*",
2311  * but it's convenient to return NULL to make it easier for callers to
2312  * distinguish this case.)
2313  */
2314 static void
2315 get_names_for_var(Var *var, deparse_context *context,
2316                                   char **schemaname, char **refname, char **attname)
2317 {
2318         deparse_namespace *dpns;
2319         RangeTblEntry *rte;
2320
2321         /* Find appropriate nesting depth */
2322         if (var->varlevelsup >= list_length(context->namespaces))
2323                 elog(ERROR, "bogus varlevelsup: %d", var->varlevelsup);
2324         dpns = (deparse_namespace *) list_nth(context->namespaces,
2325                                                                                   var->varlevelsup);
2326
2327         /* Find the relevant RTE */
2328         if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
2329                 rte = rt_fetch(var->varno, dpns->rtable);
2330         else if (var->varno == dpns->outer_varno)
2331                 rte = dpns->outer_rte;
2332         else if (var->varno == dpns->inner_varno)
2333                 rte = dpns->inner_rte;
2334         else
2335                 rte = NULL;
2336         if (rte == NULL)
2337                 elog(ERROR, "bogus varno: %d", var->varno);
2338
2339         /* Emit results */
2340         *schemaname = NULL;                     /* default assumptions */
2341         *refname = rte->eref->aliasname;
2342
2343         /* Exceptions occur only if the RTE is alias-less */
2344         if (rte->alias == NULL)
2345         {
2346                 if (rte->rtekind == RTE_RELATION)
2347                 {
2348                         /*
2349                          * It's possible that use of the bare refname would find
2350                          * another more-closely-nested RTE, or be ambiguous, in which
2351                          * case we need to specify the schemaname to avoid these
2352                          * errors.
2353                          */
2354                         if (find_rte_by_refname(rte->eref->aliasname, context) != rte)
2355                                 *schemaname =
2356                                         get_namespace_name(get_rel_namespace(rte->relid));
2357                 }
2358                 else if (rte->rtekind == RTE_JOIN)
2359                 {
2360                         /* Unnamed join has neither schemaname nor refname */
2361                         *refname = NULL;
2362                 }
2363         }
2364
2365         if (var->varattno == InvalidAttrNumber)
2366                 *attname = NULL;
2367         else
2368                 *attname = get_rte_attribute_name(rte, var->varattno);
2369 }
2370
2371 /*
2372  * find_rte_by_refname          - look up an RTE by refname in a deparse context
2373  *
2374  * Returns NULL if there is no matching RTE or the refname is ambiguous.
2375  *
2376  * NOTE: this code is not really correct since it does not take account of
2377  * the fact that not all the RTEs in a rangetable may be visible from the
2378  * point where a Var reference appears.  For the purposes we need, however,
2379  * the only consequence of a false match is that we might stick a schema
2380  * qualifier on a Var that doesn't really need it.  So it seems close
2381  * enough.
2382  */
2383 static RangeTblEntry *
2384 find_rte_by_refname(const char *refname, deparse_context *context)
2385 {
2386         RangeTblEntry  *result = NULL;
2387         ListCell           *nslist;
2388
2389         foreach(nslist, context->namespaces)
2390         {
2391                 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
2392                 ListCell           *rtlist;
2393
2394                 foreach(rtlist, dpns->rtable)
2395                 {
2396                         RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtlist);
2397
2398                         if (strcmp(rte->eref->aliasname, refname) == 0)
2399                         {
2400                                 if (result)
2401                                         return NULL;    /* it's ambiguous */
2402                                 result = rte;
2403                         }
2404                 }
2405                 if (dpns->outer_rte &&
2406                         strcmp(dpns->outer_rte->eref->aliasname, refname) == 0)
2407                 {
2408                         if (result)
2409                                 return NULL;    /* it's ambiguous */
2410                         result = dpns->outer_rte;
2411                 }
2412                 if (dpns->inner_rte &&
2413                         strcmp(dpns->inner_rte->eref->aliasname, refname) == 0)
2414                 {
2415                         if (result)
2416                                 return NULL;    /* it's ambiguous */
2417                         result = dpns->inner_rte;
2418                 }
2419                 if (result)
2420                         break;
2421         }
2422         return result;
2423 }
2424
2425
2426 /*
2427  * get_simple_binary_op_name
2428  *
2429  * helper function for isSimpleNode
2430  * will return single char binary operator name, or NULL if it's not
2431  */
2432 static const char *
2433 get_simple_binary_op_name(OpExpr *expr)
2434 {
2435         List       *args = expr->args;
2436
2437         if (list_length(args) == 2)
2438         {
2439                 /* binary operator */
2440                 Node       *arg1 = (Node *) linitial(args);
2441                 Node       *arg2 = (Node *) lsecond(args);
2442                 const char *op;
2443
2444                 op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
2445                 if (strlen(op) == 1)
2446                         return op;
2447         }
2448         return NULL;
2449 }
2450
2451
2452 /*
2453  * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
2454  *
2455  *      true   : simple in the context of parent node's type
2456  *      false  : not simple
2457  */
2458 static bool
2459 isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
2460 {
2461         if (!node)
2462                 return false;
2463
2464         switch (nodeTag(node))
2465         {
2466                 case T_Var:
2467                 case T_Const:
2468                 case T_Param:
2469                 case T_CoerceToDomainValue:
2470                 case T_SetToDefault:
2471                         /* single words: always simple */
2472                         return true;
2473
2474                 case T_ArrayRef:
2475                 case T_ArrayExpr:
2476                 case T_RowExpr:
2477                 case T_CoalesceExpr:
2478                 case T_NullIfExpr:
2479                 case T_Aggref:
2480                 case T_FuncExpr:
2481                         /* function-like: name(..) or name[..] */
2482                         return true;
2483
2484                         /* CASE keywords act as parentheses */
2485                 case T_CaseExpr:
2486                         return true;
2487
2488                 case T_FieldSelect:
2489
2490                         /*
2491                          * appears simple since . has top precedence, unless parent is
2492                          * T_FieldSelect itself!
2493                          */
2494                         return (IsA(parentNode, FieldSelect) ? false : true);
2495
2496                 case T_FieldStore:
2497
2498                         /*
2499                          * treat like FieldSelect (probably doesn't matter)
2500                          */
2501                         return (IsA(parentNode, FieldStore) ? false : true);
2502
2503                 case T_CoerceToDomain:
2504                         /* maybe simple, check args */
2505                         return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
2506                                                                 node, prettyFlags);
2507                 case T_RelabelType:
2508                         return isSimpleNode((Node *) ((RelabelType *) node)->arg,
2509                                                                 node, prettyFlags);
2510
2511                 case T_OpExpr:
2512                         {
2513                                 /* depends on parent node type; needs further checking */
2514                                 if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
2515                                 {
2516                                         const char *op;
2517                                         const char *parentOp;
2518                                         bool            is_lopriop;
2519                                         bool            is_hipriop;
2520                                         bool            is_lopriparent;
2521                                         bool            is_hipriparent;
2522
2523                                         op = get_simple_binary_op_name((OpExpr *) node);
2524                                         if (!op)
2525                                                 return false;
2526
2527                                         /* We know only the basic operators + - and * / % */
2528                                         is_lopriop = (strchr("+-", *op) != NULL);
2529                                         is_hipriop = (strchr("*/%", *op) != NULL);
2530                                         if (!(is_lopriop || is_hipriop))
2531                                                 return false;
2532
2533                                         parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
2534                                         if (!parentOp)
2535                                                 return false;
2536
2537                                         is_lopriparent = (strchr("+-", *parentOp) != NULL);
2538                                         is_hipriparent = (strchr("*/%", *parentOp) != NULL);
2539                                         if (!(is_lopriparent || is_hipriparent))
2540                                                 return false;
2541
2542                                         if (is_hipriop && is_lopriparent)
2543                                                 return true;    /* op binds tighter than parent */
2544
2545                                         if (is_lopriop && is_hipriparent)
2546                                                 return false;
2547
2548                                         /*
2549                                          * Operators are same priority --- can skip parens
2550                                          * only if we have (a - b) - c, not a - (b - c).
2551                                          */
2552                                         if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
2553                                                 return true;
2554
2555                                         return false;
2556                                 }
2557                                 /* else do the same stuff as for T_SubLink et al. */
2558                                 /* FALL THROUGH */
2559                         }
2560
2561                 case T_SubLink:
2562                 case T_NullTest:
2563                 case T_BooleanTest:
2564                 case T_DistinctExpr:
2565                         switch (nodeTag(parentNode))
2566                         {
2567                                 case T_FuncExpr:
2568                                         {
2569                                                 /* special handling for casts */
2570                                                 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
2571
2572                                                 if (type == COERCE_EXPLICIT_CAST ||
2573                                                         type == COERCE_IMPLICIT_CAST)
2574                                                         return false;
2575                                                 return true;    /* own parentheses */
2576                                         }
2577                                 case T_BoolExpr:                /* lower precedence */
2578                                 case T_ArrayRef:                /* other separators */
2579                                 case T_ArrayExpr:               /* other separators */
2580                                 case T_RowExpr:                 /* other separators */
2581                                 case T_CoalesceExpr:    /* own parentheses */
2582                                 case T_NullIfExpr:              /* other separators */
2583                                 case T_Aggref:                  /* own parentheses */
2584                                 case T_CaseExpr:                /* other separators */
2585                                         return true;
2586                                 default:
2587                                         return false;
2588                         }
2589
2590                 case T_BoolExpr:
2591                         switch (nodeTag(parentNode))
2592                         {
2593                                 case T_BoolExpr:
2594                                         if (prettyFlags & PRETTYFLAG_PAREN)
2595                                         {
2596                                                 BoolExprType type;
2597                                                 BoolExprType parentType;
2598
2599                                                 type = ((BoolExpr *) node)->boolop;
2600                                                 parentType = ((BoolExpr *) parentNode)->boolop;
2601                                                 switch (type)
2602                                                 {
2603                                                         case NOT_EXPR:
2604                                                         case AND_EXPR:
2605                                                                 if (parentType == AND_EXPR || parentType == OR_EXPR)
2606                                                                         return true;
2607                                                                 break;
2608                                                         case OR_EXPR:
2609                                                                 if (parentType == OR_EXPR)
2610                                                                         return true;
2611                                                                 break;
2612                                                 }
2613                                         }
2614                                         return false;
2615                                 case T_FuncExpr:
2616                                         {
2617                                                 /* special handling for casts */
2618                                                 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
2619
2620                                                 if (type == COERCE_EXPLICIT_CAST ||
2621                                                         type == COERCE_IMPLICIT_CAST)
2622                                                         return false;
2623                                                 return true;    /* own parentheses */
2624                                         }
2625                                 case T_ArrayRef:                /* other separators */
2626                                 case T_ArrayExpr:               /* other separators */
2627                                 case T_RowExpr:                 /* other separators */
2628                                 case T_CoalesceExpr:    /* own parentheses */
2629                                 case T_NullIfExpr:              /* other separators */
2630                                 case T_Aggref:                  /* own parentheses */
2631                                 case T_CaseExpr:                /* other separators */
2632                                         return true;
2633                                 default:
2634                                         return false;
2635                         }
2636
2637                 default:
2638                         break;
2639         }
2640         /* those we don't know: in dubio complexo */
2641         return false;
2642 }
2643
2644
2645 /*
2646  * appendStringInfoSpaces - append spaces to buffer
2647  */
2648 static void
2649 appendStringInfoSpaces(StringInfo buf, int count)
2650 {
2651         while (count-- > 0)
2652                 appendStringInfoChar(buf, ' ');
2653 }
2654
2655 /*
2656  * appendContextKeyword - append a keyword to buffer
2657  *
2658  * If prettyPrint is enabled, perform a line break, and adjust indentation.
2659  * Otherwise, just append the keyword.
2660  */
2661 static void
2662 appendContextKeyword(deparse_context *context, const char *str,
2663                                          int indentBefore, int indentAfter, int indentPlus)
2664 {
2665         if (PRETTY_INDENT(context))
2666         {
2667                 context->indentLevel += indentBefore;
2668                 if (context->indentLevel < 0)
2669                         context->indentLevel = 0;
2670
2671                 appendStringInfoChar(context->buf, '\n');
2672                 appendStringInfoSpaces(context->buf,
2673                                                            context->indentLevel + indentPlus);
2674         }
2675
2676         appendStringInfoString(context->buf, str);
2677
2678         if (PRETTY_INDENT(context))
2679         {
2680                 context->indentLevel += indentAfter;
2681                 if (context->indentLevel < 0)
2682                         context->indentLevel = 0;
2683         }
2684 }
2685
2686 /*
2687  * get_rule_expr_paren  - deparse expr using get_rule_expr,
2688  * embracing the string with parentheses if necessary for prettyPrint.
2689  *
2690  * Never embrace if prettyFlags=0, because it's done in the calling node.
2691  *
2692  * Any node that does *not* embrace its argument node by sql syntax (with
2693  * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
2694  * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
2695  * added.
2696  */
2697 static void
2698 get_rule_expr_paren(Node *node, deparse_context *context,
2699                                         bool showimplicit, Node *parentNode)
2700 {
2701         bool            need_paren;
2702
2703         need_paren = PRETTY_PAREN(context) &&
2704                 !isSimpleNode(node, parentNode, context->prettyFlags);
2705
2706         if (need_paren)
2707                 appendStringInfoChar(context->buf, '(');
2708
2709         get_rule_expr(node, context, showimplicit);
2710
2711         if (need_paren)
2712                 appendStringInfoChar(context->buf, ')');
2713 }
2714
2715
2716 /* ----------
2717  * get_rule_expr                        - Parse back an expression
2718  *
2719  * Note: showimplicit determines whether we display any implicit cast that
2720  * is present at the top of the expression tree.  It is a passed argument,
2721  * not a field of the context struct, because we change the value as we
2722  * recurse down into the expression.  In general we suppress implicit casts
2723  * when the result type is known with certainty (eg, the arguments of an
2724  * OR must be boolean).  We display implicit casts for arguments of functions
2725  * and operators, since this is needed to be certain that the same function
2726  * or operator will be chosen when the expression is re-parsed.
2727  * ----------
2728  */
2729 static void
2730 get_rule_expr(Node *node, deparse_context *context,
2731                           bool showimplicit)
2732 {
2733         StringInfo      buf = context->buf;
2734
2735         if (node == NULL)
2736                 return;
2737
2738         /*
2739          * Each level of get_rule_expr must emit an indivisible term
2740          * (parenthesized if necessary) to ensure result is reparsed into the
2741          * same expression tree.
2742          *
2743          * There might be some work left here to support additional node types.
2744          */
2745         switch (nodeTag(node))
2746         {
2747                 case T_Var:
2748                         {
2749                                 Var                *var = (Var *) node;
2750                                 char       *schemaname;
2751                                 char       *refname;
2752                                 char       *attname;
2753
2754                                 get_names_for_var(var, context,
2755                                                                   &schemaname, &refname, &attname);
2756                                 if (refname && (context->varprefix || attname == NULL))
2757                                 {
2758                                         if (schemaname)
2759                                                 appendStringInfo(buf, "%s.",
2760                                                                                  quote_identifier(schemaname));
2761
2762                                         if (strcmp(refname, "*NEW*") == 0)
2763                                                 appendStringInfo(buf, "new.");
2764                                         else if (strcmp(refname, "*OLD*") == 0)
2765                                                 appendStringInfo(buf, "old.");
2766                                         else
2767                                                 appendStringInfo(buf, "%s.",
2768                                                                                  quote_identifier(refname));
2769                                 }
2770                                 if (attname)
2771                                         appendStringInfoString(buf, quote_identifier(attname));
2772                                 else
2773                                         appendStringInfo(buf, "*");
2774                         }
2775                         break;
2776
2777                 case T_Const:
2778                         get_const_expr((Const *) node, context);
2779                         break;
2780
2781                 case T_Param:
2782                         {
2783                                 Param      *param = (Param *) node;
2784
2785                                 switch (param->paramkind)
2786                                 {
2787                                         case PARAM_NAMED:
2788                                                 appendStringInfo(buf, "$%s", param->paramname);
2789                                                 break;
2790                                         case PARAM_NUM:
2791                                         case PARAM_EXEC:
2792                                                 appendStringInfo(buf, "$%d", param->paramid);
2793                                                 break;
2794                                         default:
2795                                                 appendStringInfo(buf, "(param)");
2796                                                 break;
2797                                 }
2798                         }
2799                         break;
2800
2801                 case T_Aggref:
2802                         get_agg_expr((Aggref *) node, context);
2803                         break;
2804
2805                 case T_ArrayRef:
2806                         {
2807                                 ArrayRef   *aref = (ArrayRef *) node;
2808                                 bool            need_parens;
2809
2810                                 /*
2811                                  * Parenthesize the argument unless it's a simple Var or
2812                                  * a FieldSelect.  (In particular, if it's another ArrayRef,
2813                                  * we *must* parenthesize to avoid confusion.)
2814                                  */
2815                                 need_parens = !IsA(aref->refexpr, Var) &&
2816                                         !IsA(aref->refexpr, FieldSelect);
2817                                 if (need_parens)
2818                                         appendStringInfoChar(buf, '(');
2819                                 get_rule_expr((Node *) aref->refexpr, context, showimplicit);
2820                                 if (need_parens)
2821                                         appendStringInfoChar(buf, ')');
2822                                 printSubscripts(aref, context);
2823                                 /*
2824                                  * Array assignment nodes should have been handled in
2825                                  * processIndirection().
2826                                  */
2827                                 if (aref->refassgnexpr)
2828                                         elog(ERROR, "unexpected refassgnexpr");
2829                         }
2830                         break;
2831
2832                 case T_FuncExpr:
2833                         get_func_expr((FuncExpr *) node, context, showimplicit);
2834                         break;
2835
2836                 case T_OpExpr:
2837                         get_oper_expr((OpExpr *) node, context);
2838                         break;
2839
2840                 case T_DistinctExpr:
2841                         {
2842                                 DistinctExpr *expr = (DistinctExpr *) node;
2843                                 List       *args = expr->args;
2844                                 Node       *arg1 = (Node *) linitial(args);
2845                                 Node       *arg2 = (Node *) lsecond(args);
2846
2847                                 if (!PRETTY_PAREN(context))
2848                                         appendStringInfoChar(buf, '(');
2849                                 get_rule_expr_paren(arg1, context, true, node);
2850                                 appendStringInfo(buf, " IS DISTINCT FROM ");
2851                                 get_rule_expr_paren(arg2, context, true, node);
2852                                 if (!PRETTY_PAREN(context))
2853                                         appendStringInfoChar(buf, ')');
2854                         }
2855                         break;
2856
2857                 case T_ScalarArrayOpExpr:
2858                         {
2859                                 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
2860                                 List       *args = expr->args;
2861                                 Node       *arg1 = (Node *) linitial(args);
2862                                 Node       *arg2 = (Node *) lsecond(args);
2863
2864                                 if (!PRETTY_PAREN(context))
2865                                         appendStringInfoChar(buf, '(');
2866                                 get_rule_expr_paren(arg1, context, true, node);
2867                                 appendStringInfo(buf, " %s %s (",
2868                                                                  generate_operator_name(expr->opno,
2869                                                                                                                 exprType(arg1),
2870                                                                            get_element_type(exprType(arg2))),
2871                                                                  expr->useOr ? "ANY" : "ALL");
2872                                 get_rule_expr_paren(arg2, context, true, node);
2873                                 appendStringInfoChar(buf, ')');
2874                                 if (!PRETTY_PAREN(context))
2875                                         appendStringInfoChar(buf, ')');
2876                         }
2877                         break;
2878
2879                 case T_BoolExpr:
2880                         {
2881                                 BoolExpr   *expr = (BoolExpr *) node;
2882                                 Node       *first_arg = linitial(expr->args);
2883                                 ListCell   *arg = lnext(list_head(expr->args));
2884
2885                                 switch (expr->boolop)
2886                                 {
2887                                         case AND_EXPR:
2888                                                 if (!PRETTY_PAREN(context))
2889                                                         appendStringInfoChar(buf, '(');
2890                                                 get_rule_expr_paren(first_arg, context,
2891                                                                                         false, node);
2892                                                 while (arg)
2893                                                 {
2894                                                         appendStringInfo(buf, " AND ");
2895                                                         get_rule_expr_paren((Node *) lfirst(arg), context,
2896                                                                                                 false, node);
2897                                                         arg = lnext(arg);
2898                                                 }
2899                                                 if (!PRETTY_PAREN(context))
2900                                                         appendStringInfoChar(buf, ')');
2901                                                 break;
2902
2903                                         case OR_EXPR:
2904                                                 if (!PRETTY_PAREN(context))
2905                                                         appendStringInfoChar(buf, '(');
2906                                                 get_rule_expr_paren(first_arg, context,
2907                                                                                         false, node);
2908                                                 while (arg)
2909                                                 {
2910                                                         appendStringInfo(buf, " OR ");
2911                                                         get_rule_expr_paren((Node *) lfirst(arg), context,
2912                                                                                                 false, node);
2913                                                         arg = lnext(arg);
2914                                                 }
2915                                                 if (!PRETTY_PAREN(context))
2916                                                         appendStringInfoChar(buf, ')');
2917                                                 break;
2918
2919                                         case NOT_EXPR:
2920                                                 if (!PRETTY_PAREN(context))
2921                                                         appendStringInfoChar(buf, '(');
2922                                                 appendStringInfo(buf, "NOT ");
2923                                                 get_rule_expr_paren(first_arg, context,
2924                                                                                         false, node);
2925                                                 if (!PRETTY_PAREN(context))
2926                                                         appendStringInfoChar(buf, ')');
2927                                                 break;
2928
2929                                         default:
2930                                                 elog(ERROR, "unrecognized boolop: %d",
2931                                                          (int) expr->boolop);
2932                                 }
2933                         }
2934                         break;
2935
2936                 case T_SubLink:
2937                         get_sublink_expr((SubLink *) node, context);
2938                         break;
2939
2940                 case T_SubPlan:
2941                         {
2942                                 /*
2943                                  * We cannot see an already-planned subplan in rule
2944                                  * deparsing, only while EXPLAINing a query plan. For now,
2945                                  * just punt.
2946                                  */
2947                                 if (((SubPlan *) node)->useHashTable)
2948                                         appendStringInfo(buf, "(hashed subplan)");
2949                                 else
2950                                         appendStringInfo(buf, "(subplan)");
2951                         }
2952                         break;
2953
2954                 case T_FieldSelect:
2955                         {
2956                                 FieldSelect *fselect = (FieldSelect *) node;
2957                                 Oid                     argType = exprType((Node *) fselect->arg);
2958                                 Oid                     typrelid;
2959                                 char       *fieldname;
2960                                 bool            need_parens;
2961
2962                                 /* lookup arg type and get the field name */
2963                                 typrelid = get_typ_typrelid(argType);
2964                                 if (!OidIsValid(typrelid))
2965                                         elog(ERROR, "argument type %s of FieldSelect is not a tuple type",
2966                                                  format_type_be(argType));
2967                                 fieldname = get_relid_attribute_name(typrelid,
2968                                                                                                          fselect->fieldnum);
2969                                 /*
2970                                  * Parenthesize the argument unless it's an ArrayRef or
2971                                  * another FieldSelect.  Note in particular that it would be
2972                                  * WRONG to not parenthesize a Var argument; simplicity is not
2973                                  * the issue here, having the right number of names is.
2974                                  */
2975                                 need_parens = !IsA(fselect->arg, ArrayRef) &&
2976                                         !IsA(fselect->arg, FieldSelect);
2977                                 if (need_parens)
2978                                         appendStringInfoChar(buf, '(');
2979                                 get_rule_expr((Node *) fselect->arg, context, true);
2980                                 if (need_parens)
2981                                         appendStringInfoChar(buf, ')');
2982                                 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
2983                         }
2984                         break;
2985
2986                 case T_FieldStore:
2987                         /*
2988                          * We shouldn't see FieldStore here; it should have been
2989                          * stripped off by processIndirection().
2990                          */
2991                         elog(ERROR, "unexpected FieldStore");
2992                         break;
2993
2994                 case T_RelabelType:
2995                         {
2996                                 RelabelType *relabel = (RelabelType *) node;
2997                                 Node       *arg = (Node *) relabel->arg;
2998
2999                                 if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
3000                                         !showimplicit)
3001                                 {
3002                                         /* don't show the implicit cast */
3003                                         get_rule_expr_paren(arg, context, false, node);
3004                                 }
3005                                 else
3006                                 {
3007                                         if (!PRETTY_PAREN(context))
3008                                                 appendStringInfoChar(buf, '(');
3009                                         get_rule_expr_paren(arg, context, false, node);
3010                                         if (!PRETTY_PAREN(context))
3011                                                 appendStringInfoChar(buf, ')');
3012                                         appendStringInfo(buf, "::%s",
3013                                                         format_type_with_typemod(relabel->resulttype,
3014                                                                                                  relabel->resulttypmod));
3015                                 }
3016                         }
3017                         break;
3018
3019                 case T_CaseExpr:
3020                         {
3021                                 CaseExpr   *caseexpr = (CaseExpr *) node;
3022                                 ListCell   *temp;
3023
3024                                 appendContextKeyword(context, "CASE",
3025                                                                          0, PRETTYINDENT_VAR, 0);
3026                                 if (caseexpr->arg)
3027                                 {
3028                                         appendStringInfoChar(buf, ' ');
3029                                         get_rule_expr((Node *) caseexpr->arg, context, true);
3030                                 }
3031                                 foreach(temp, caseexpr->args)
3032                                 {
3033                                         CaseWhen   *when = (CaseWhen *) lfirst(temp);
3034
3035                                         if (!PRETTY_INDENT(context))
3036                                                 appendStringInfoChar(buf, ' ');
3037                                         appendContextKeyword(context, "WHEN ",
3038                                                                                  0, 0, 0);
3039                                         if (caseexpr->arg)
3040                                         {
3041                                                 /* Show only the RHS of "CaseTestExpr = RHS" */
3042                                                 Node   *rhs;
3043
3044                                                 Assert(IsA(when->expr, OpExpr));
3045                                                 rhs = (Node *) lsecond(((OpExpr *) when->expr)->args);
3046                                                 get_rule_expr(rhs, context, false);
3047                                         }
3048                                         else
3049                                                 get_rule_expr((Node *) when->expr, context, false);
3050                                         appendStringInfo(buf, " THEN ");
3051                                         get_rule_expr((Node *) when->result, context, true);
3052                                 }
3053                                 if (!PRETTY_INDENT(context))
3054                                         appendStringInfoChar(buf, ' ');
3055                                 appendContextKeyword(context, "ELSE ",
3056                                                                          0, 0, 0);
3057                                 get_rule_expr((Node *) caseexpr->defresult, context, true);
3058                                 if (!PRETTY_INDENT(context))
3059                                         appendStringInfoChar(buf, ' ');
3060                                 appendContextKeyword(context, "END",
3061                                                                          -PRETTYINDENT_VAR, 0, 0);
3062                         }
3063                         break;
3064
3065                 case T_ArrayExpr:
3066                         {
3067                                 ArrayExpr  *arrayexpr = (ArrayExpr *) node;
3068                                 ListCell   *element;
3069                                 char       *sep;
3070
3071                                 appendStringInfo(buf, "ARRAY[");
3072                                 sep = "";
3073                                 foreach(element, arrayexpr->elements)
3074                                 {
3075                                         Node       *e = (Node *) lfirst(element);
3076
3077                                         appendStringInfo(buf, sep);
3078                                         get_rule_expr(e, context, true);
3079                                         sep = ", ";
3080                                 }
3081                                 appendStringInfo(buf, "]");
3082                         }
3083                         break;
3084
3085                 case T_RowExpr:
3086                         {
3087                                 RowExpr    *rowexpr = (RowExpr *) node;
3088                                 ListCell   *arg;
3089                                 char       *sep;
3090
3091                                 /*
3092                                  * SQL99 allows "ROW" to be omitted when list_length(args) > 1,
3093                                  * but for simplicity we always print it.
3094                                  */
3095                                 appendStringInfo(buf, "ROW(");
3096                                 sep = "";
3097                                 foreach(arg, rowexpr->args)
3098                                 {
3099                                         Node       *e = (Node *) lfirst(arg);
3100
3101                                         appendStringInfo(buf, sep);
3102                                         get_rule_expr(e, context, true);
3103                                         sep = ", ";
3104                                 }
3105                                 appendStringInfo(buf, ")");
3106                                 if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
3107                                         appendStringInfo(buf, "::%s",
3108                                                                          format_type_with_typemod(rowexpr->row_typeid, -1));
3109                         }
3110                         break;
3111
3112                 case T_CoalesceExpr:
3113                         {
3114                                 CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
3115                                 ListCell   *arg;
3116                                 char       *sep;
3117
3118                                 appendStringInfo(buf, "COALESCE(");
3119                                 sep = "";
3120                                 foreach(arg, coalesceexpr->args)
3121                                 {
3122                                         Node       *e = (Node *) lfirst(arg);
3123
3124                                         appendStringInfo(buf, sep);
3125                                         get_rule_expr(e, context, true);
3126                                         sep = ", ";
3127                                 }
3128                                 appendStringInfo(buf, ")");
3129                         }
3130                         break;
3131
3132                 case T_NullIfExpr:
3133                         {
3134                                 NullIfExpr *nullifexpr = (NullIfExpr *) node;
3135                                 ListCell   *arg;
3136                                 char       *sep;
3137
3138                                 appendStringInfo(buf, "NULLIF(");
3139                                 sep = "";
3140                                 foreach(arg, nullifexpr->args)
3141                                 {
3142                                         Node       *e = (Node *) lfirst(arg);
3143
3144                                         appendStringInfo(buf, sep);
3145                                         get_rule_expr(e, context, true);
3146                                         sep = ", ";
3147                                 }
3148                                 appendStringInfo(buf, ")");
3149                         }
3150                         break;
3151
3152                 case T_NullTest:
3153                         {
3154                                 NullTest   *ntest = (NullTest *) node;
3155
3156                                 if (!PRETTY_PAREN(context))
3157                                         appendStringInfoChar(buf, '(');
3158                                 get_rule_expr_paren((Node *) ntest->arg, context, true, node);
3159                                 switch (ntest->nulltesttype)
3160                                 {
3161                                         case IS_NULL:
3162                                                 appendStringInfo(buf, " IS NULL");
3163                                                 break;
3164                                         case IS_NOT_NULL:
3165                                                 appendStringInfo(buf, " IS NOT NULL");
3166                                                 break;
3167                                         default:
3168                                                 elog(ERROR, "unrecognized nulltesttype: %d",
3169                                                          (int) ntest->nulltesttype);
3170                                 }
3171                                 if (!PRETTY_PAREN(context))
3172                                         appendStringInfoChar(buf, ')');
3173                         }
3174                         break;
3175
3176                 case T_BooleanTest:
3177                         {
3178                                 BooleanTest *btest = (BooleanTest *) node;
3179
3180                                 if (!PRETTY_PAREN(context))
3181                                         appendStringInfoChar(buf, '(');
3182                                 get_rule_expr_paren((Node *) btest->arg, context, false, node);
3183                                 switch (btest->booltesttype)
3184                                 {
3185                                         case IS_TRUE:
3186                                                 appendStringInfo(buf, " IS TRUE");
3187                                                 break;
3188                                         case IS_NOT_TRUE:
3189                                                 appendStringInfo(buf, " IS NOT TRUE");
3190                                                 break;
3191                                         case IS_FALSE:
3192                                                 appendStringInfo(buf, " IS FALSE");
3193                                                 break;
3194                                         case IS_NOT_FALSE:
3195                                                 appendStringInfo(buf, " IS NOT FALSE");
3196                                                 break;
3197                                         case IS_UNKNOWN:
3198                                                 appendStringInfo(buf, " IS UNKNOWN");
3199                                                 break;
3200                                         case IS_NOT_UNKNOWN:
3201                                                 appendStringInfo(buf, " IS NOT UNKNOWN");
3202                                                 break;
3203                                         default:
3204                                                 elog(ERROR, "unrecognized booltesttype: %d",
3205                                                          (int) btest->booltesttype);
3206                                 }
3207                                 if (!PRETTY_PAREN(context))
3208                                         appendStringInfoChar(buf, ')');
3209                         }
3210                         break;
3211
3212                 case T_CoerceToDomain:
3213                         {
3214                                 CoerceToDomain *ctest = (CoerceToDomain *) node;
3215                                 Node       *arg = (Node *) ctest->arg;
3216
3217                                 if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
3218                                         !showimplicit)
3219                                 {
3220                                         /* don't show the implicit cast */
3221                                         get_rule_expr(arg, context, false);
3222                                 }
3223                                 else
3224                                 {
3225                                         if (!PRETTY_PAREN(context))
3226                                                 appendStringInfoChar(buf, '(');
3227                                         get_rule_expr_paren(arg, context, false, node);
3228                                         if (!PRETTY_PAREN(context))
3229                                                 appendStringInfoChar(buf, ')');
3230                                         appendStringInfo(buf, "::%s",
3231                                                           format_type_with_typemod(ctest->resulttype,
3232                                                                                                    ctest->resulttypmod));
3233                                 }
3234                         }
3235                         break;
3236
3237                 case T_CoerceToDomainValue:
3238                         appendStringInfo(buf, "VALUE");
3239                         break;
3240
3241                 case T_SetToDefault:
3242                         appendStringInfo(buf, "DEFAULT");
3243                         break;
3244
3245                 default:
3246                         elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
3247                         break;
3248         }
3249 }
3250
3251
3252 /*
3253  * get_oper_expr                        - Parse back an OpExpr node
3254  */
3255 static void
3256 get_oper_expr(OpExpr *expr, deparse_context *context)
3257 {
3258         StringInfo      buf = context->buf;
3259         Oid                     opno = expr->opno;
3260         List       *args = expr->args;
3261
3262         if (!PRETTY_PAREN(context))
3263                 appendStringInfoChar(buf, '(');
3264         if (list_length(args) == 2)
3265         {
3266                 /* binary operator */
3267                 Node       *arg1 = (Node *) linitial(args);
3268                 Node       *arg2 = (Node *) lsecond(args);
3269
3270                 get_rule_expr_paren(arg1, context, true, (Node *) expr);
3271                 appendStringInfo(buf, " %s ",
3272                                                  generate_operator_name(opno,
3273                                                                                                 exprType(arg1),
3274                                                                                                 exprType(arg2)));
3275                 get_rule_expr_paren(arg2, context, true, (Node *) expr);
3276         }
3277         else
3278         {
3279                 /* unary operator --- but which side? */
3280                 Node       *arg = (Node *) linitial(args);
3281                 HeapTuple       tp;
3282                 Form_pg_operator optup;
3283
3284                 tp = SearchSysCache(OPEROID,
3285                                                         ObjectIdGetDatum(opno),
3286                                                         0, 0, 0);
3287                 if (!HeapTupleIsValid(tp))
3288                         elog(ERROR, "cache lookup failed for operator %u", opno);
3289                 optup = (Form_pg_operator) GETSTRUCT(tp);
3290                 switch (optup->oprkind)
3291                 {
3292                         case 'l':
3293                                 appendStringInfo(buf, "%s ",
3294                                                                  generate_operator_name(opno,
3295                                                                                                                 InvalidOid,
3296                                                                                                                 exprType(arg)));
3297                                 get_rule_expr_paren(arg, context, true, (Node *) expr);
3298                                 break;
3299                         case 'r':
3300                                 get_rule_expr_paren(arg, context, true, (Node *) expr);
3301                                 appendStringInfo(buf, " %s",
3302                                                                  generate_operator_name(opno,
3303                                                                                                                 exprType(arg),
3304                                                                                                                 InvalidOid));
3305                                 break;
3306                         default:
3307                                 elog(ERROR, "bogus oprkind: %d", optup->oprkind);
3308                 }
3309                 ReleaseSysCache(tp);
3310         }
3311         if (!PRETTY_PAREN(context))
3312                 appendStringInfoChar(buf, ')');
3313 }
3314
3315 /*
3316  * get_func_expr                        - Parse back a FuncExpr node
3317  */
3318 static void
3319 get_func_expr(FuncExpr *expr, deparse_context *context,
3320                           bool showimplicit)
3321 {
3322         StringInfo      buf = context->buf;
3323         Oid                     funcoid = expr->funcid;
3324         Oid                     argtypes[FUNC_MAX_ARGS];
3325         int                     nargs;
3326         ListCell   *l;
3327         char       *sep;
3328
3329         /*
3330          * If the function call came from an implicit coercion, then just show
3331          * the first argument --- unless caller wants to see implicit
3332          * coercions.
3333          */
3334         if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
3335         {
3336                 get_rule_expr_paren((Node *) linitial(expr->args), context,
3337                                                         false, (Node *) expr);
3338                 return;
3339         }
3340
3341         /*
3342          * If the function call came from a cast, then show the first argument
3343          * plus an explicit cast operation.
3344          */
3345         if (expr->funcformat == COERCE_EXPLICIT_CAST ||
3346                 expr->funcformat == COERCE_IMPLICIT_CAST)
3347         {
3348                 Node       *arg = linitial(expr->args);
3349                 Oid                     rettype = expr->funcresulttype;
3350                 int32           coercedTypmod;
3351
3352                 /* Get the typmod if this is a length-coercion function */
3353                 (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
3354
3355                 if (!PRETTY_PAREN(context))
3356                         appendStringInfoChar(buf, '(');
3357                 get_rule_expr_paren(arg, context, false, (Node *) expr);
3358                 if (!PRETTY_PAREN(context))
3359                         appendStringInfoChar(buf, ')');
3360                 appendStringInfo(buf, "::%s",
3361                                            format_type_with_typemod(rettype, coercedTypmod));
3362
3363                 return;
3364         }
3365
3366         /*
3367          * Normal function: display as proname(args).  First we need to
3368          * extract the argument datatypes.
3369          */
3370         nargs = 0;
3371         foreach(l, expr->args)
3372         {
3373                 Assert(nargs < FUNC_MAX_ARGS);
3374                 argtypes[nargs] = exprType((Node *) lfirst(l));
3375                 nargs++;
3376         }
3377
3378         appendStringInfo(buf, "%s(",
3379                                          generate_function_name(funcoid, nargs, argtypes));
3380
3381         sep = "";
3382         foreach(l, expr->args)
3383         {
3384                 appendStringInfo(buf, sep);
3385                 sep = ", ";
3386                 get_rule_expr((Node *) lfirst(l), context, true);
3387         }
3388         appendStringInfoChar(buf, ')');
3389 }
3390
3391 /*
3392  * get_agg_expr                 - Parse back an Aggref node
3393  */
3394 static void
3395 get_agg_expr(Aggref *aggref, deparse_context *context)
3396 {
3397         StringInfo      buf = context->buf;
3398         Oid                     argtype = exprType((Node *) aggref->target);
3399
3400         appendStringInfo(buf, "%s(%s",
3401                                    generate_function_name(aggref->aggfnoid, 1, &argtype),
3402                                          aggref->aggdistinct ? "DISTINCT " : "");
3403         if (aggref->aggstar)
3404                 appendStringInfo(buf, "*");
3405         else
3406                 get_rule_expr((Node *) aggref->target, context, true);
3407         appendStringInfoChar(buf, ')');
3408 }
3409
3410
3411 /* ----------
3412  * get_const_expr
3413  *
3414  *      Make a string representation of a Const
3415  * ----------
3416  */
3417 static void
3418 get_const_expr(Const *constval, deparse_context *context)
3419 {
3420         StringInfo      buf = context->buf;
3421         Oid                     typoutput;
3422         Oid                     typioparam;
3423         bool            typIsVarlena;
3424         char       *extval;
3425         char       *valptr;
3426         bool            isfloat = false;
3427         bool            needlabel;
3428
3429         if (constval->constisnull)
3430         {
3431                 /*
3432                  * Always label the type of a NULL constant to prevent
3433                  * misdecisions about type when reparsing.
3434                  */
3435                 appendStringInfo(buf, "NULL::%s",
3436                                           format_type_with_typemod(constval->consttype, -1));
3437                 return;
3438         }
3439
3440         getTypeOutputInfo(constval->consttype,
3441                                           &typoutput, &typioparam, &typIsVarlena);
3442
3443         extval = DatumGetCString(OidFunctionCall3(typoutput,
3444                                                                                           constval->constvalue,
3445                                                                                           ObjectIdGetDatum(typioparam),
3446                                                                                           Int32GetDatum(-1)));
3447
3448         switch (constval->consttype)
3449         {
3450                 case INT2OID:
3451                 case INT4OID:
3452                 case INT8OID:
3453                 case OIDOID:
3454                 case FLOAT4OID:
3455                 case FLOAT8OID:
3456                 case NUMERICOID:
3457                         {
3458                                 /*
3459                                  * These types are printed without quotes unless they
3460                                  * contain values that aren't accepted by the scanner
3461                                  * unquoted (e.g., 'NaN').      Note that strtod() and friends
3462                                  * might accept NaN, so we can't use that to test.
3463                                  *
3464                                  * In reality we only need to defend against infinity and
3465                                  * NaN, so we need not get too crazy about pattern
3466                                  * matching here.
3467                                  */
3468                                 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
3469                                 {
3470                                         appendStringInfoString(buf, extval);
3471                                         if (strcspn(extval, "eE.") != strlen(extval))
3472                                                 isfloat = true; /* it looks like a float */
3473                                 }
3474                                 else
3475                                         appendStringInfo(buf, "'%s'", extval);
3476                         }
3477                         break;
3478
3479                 case BITOID:
3480                 case VARBITOID:
3481                         appendStringInfo(buf, "B'%s'", extval);
3482                         break;
3483
3484                 case BOOLOID:
3485                         if (strcmp(extval, "t") == 0)
3486                                 appendStringInfo(buf, "true");
3487                         else
3488                                 appendStringInfo(buf, "false");
3489                         break;
3490
3491                 default:
3492
3493                         /*
3494                          * We must quote any funny characters in the constant's
3495                          * representation. XXX Any MULTIBYTE considerations here?
3496                          */
3497                         appendStringInfoChar(buf, '\'');
3498                         for (valptr = extval; *valptr; valptr++)
3499                         {
3500                                 char            ch = *valptr;
3501
3502                                 if (ch == '\'' || ch == '\\')
3503                                 {
3504                                         appendStringInfoChar(buf, '\\');
3505                                         appendStringInfoChar(buf, ch);
3506                                 }
3507                                 else if (((unsigned char) ch) < ((unsigned char) ' '))
3508                                         appendStringInfo(buf, "\\%03o", (int) ch);
3509                                 else
3510                                         appendStringInfoChar(buf, ch);
3511                         }
3512                         appendStringInfoChar(buf, '\'');
3513                         break;
3514         }
3515
3516         pfree(extval);
3517
3518         /*
3519          * Append ::typename unless the constant will be implicitly typed as
3520          * the right type when it is read in.  XXX this code has to be kept in
3521          * sync with the behavior of the parser, especially make_const.
3522          */
3523         switch (constval->consttype)
3524         {
3525                 case BOOLOID:
3526                 case INT4OID:
3527                 case UNKNOWNOID:
3528                         /* These types can be left unlabeled */
3529                         needlabel = false;
3530                         break;
3531                 case NUMERICOID:
3532                         /* Float-looking constants will be typed as numeric */
3533                         needlabel = !isfloat;
3534                         break;
3535                 default:
3536                         needlabel = true;
3537                         break;
3538         }
3539         if (needlabel)
3540                 appendStringInfo(buf, "::%s",
3541                                           format_type_with_typemod(constval->consttype, -1));
3542 }
3543
3544
3545 /* ----------
3546  * get_sublink_expr                     - Parse back a sublink
3547  * ----------
3548  */
3549 static void
3550 get_sublink_expr(SubLink *sublink, deparse_context *context)
3551 {
3552         StringInfo      buf = context->buf;
3553         Query      *query = (Query *) (sublink->subselect);
3554         ListCell   *l;
3555         char       *sep;
3556         bool            need_paren;
3557
3558         if (sublink->subLinkType == ARRAY_SUBLINK)
3559                 appendStringInfo(buf, "ARRAY(");
3560         else
3561                 appendStringInfoChar(buf, '(');
3562
3563         if (sublink->lefthand != NIL)
3564         {
3565                 need_paren = (list_length(sublink->lefthand) > 1);
3566                 if (need_paren)
3567                         appendStringInfoChar(buf, '(');
3568
3569                 sep = "";
3570                 foreach(l, sublink->lefthand)
3571                 {
3572                         appendStringInfo(buf, sep);
3573                         sep = ", ";
3574                         get_rule_expr((Node *) lfirst(l), context, true);
3575                 }
3576
3577                 if (need_paren)
3578                         appendStringInfo(buf, ") ");
3579                 else
3580                         appendStringInfoChar(buf, ' ');
3581         }
3582
3583         need_paren = true;
3584
3585         /*
3586          * XXX we regurgitate the originally given operator name, with or
3587          * without schema qualification.  This is not necessarily 100% right
3588          * but it's the best we can do, since the operators actually used
3589          * might not all be in the same schema.
3590          */
3591         switch (sublink->subLinkType)
3592         {
3593                 case EXISTS_SUBLINK:
3594                         appendStringInfo(buf, "EXISTS ");
3595                         break;
3596
3597                 case ANY_SUBLINK:
3598                         if (list_length(sublink->operName) == 1 &&
3599                                 strcmp(strVal(linitial(sublink->operName)), "=") == 0)
3600                         {
3601                                 /* Represent = ANY as IN */
3602                                 appendStringInfo(buf, "IN ");
3603                         }
3604                         else
3605                         {
3606                                 print_operator_name(buf, sublink->operName);
3607                                 appendStringInfo(buf, " ANY ");
3608                         }
3609                         break;
3610
3611                 case ALL_SUBLINK:
3612                         print_operator_name(buf, sublink->operName);
3613                         appendStringInfo(buf, " ALL ");
3614                         break;
3615
3616                 case MULTIEXPR_SUBLINK:
3617                         print_operator_name(buf, sublink->operName);
3618                         appendStringInfoChar(buf, ' ');
3619                         break;
3620
3621                 case EXPR_SUBLINK:
3622                 case ARRAY_SUBLINK:
3623                         need_paren = false;
3624                         break;
3625
3626                 default:
3627                         elog(ERROR, "unrecognized sublink type: %d",
3628                                  (int) sublink->subLinkType);
3629                         break;
3630         }
3631
3632         if (need_paren)
3633                 appendStringInfoChar(buf, '(');
3634
3635         get_query_def(query, buf, context->namespaces, NULL,
3636                                   context->prettyFlags, context->indentLevel);
3637
3638         if (need_paren)
3639                 appendStringInfo(buf, "))");
3640         else
3641                 appendStringInfoChar(buf, ')');
3642 }
3643
3644
3645 /* ----------
3646  * get_from_clause                      - Parse back a FROM clause
3647  * ----------
3648  */
3649 static void
3650 get_from_clause(Query *query, deparse_context *context)
3651 {
3652         StringInfo      buf = context->buf;
3653         bool            first = true;
3654         ListCell   *l;
3655
3656         /*
3657          * We use the query's jointree as a guide to what to print.  However,
3658          * we must ignore auto-added RTEs that are marked not inFromCl. (These
3659          * can only appear at the top level of the jointree, so it's
3660          * sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW
3661          * and OLD.
3662          */
3663         foreach(l, query->jointree->fromlist)
3664         {
3665                 Node       *jtnode = (Node *) lfirst(l);
3666
3667                 if (IsA(jtnode, RangeTblRef))
3668                 {
3669                         int                     varno = ((RangeTblRef *) jtnode)->rtindex;
3670                         RangeTblEntry *rte = rt_fetch(varno, query->rtable);
3671
3672                         if (!rte->inFromCl)
3673                                 continue;
3674                         if (strcmp(rte->eref->aliasname, "*NEW*") == 0)
3675                                 continue;
3676                         if (strcmp(rte->eref->aliasname, "*OLD*") == 0)
3677                                 continue;
3678                 }
3679
3680                 if (first)
3681                 {
3682                         appendContextKeyword(context, " FROM ",
3683                                                                  -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
3684                         first = false;
3685                 }
3686                 else
3687                         appendStringInfoString(buf, ", ");
3688
3689                 get_from_clause_item(jtnode, query, context);
3690         }
3691 }
3692
3693 static void
3694 get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
3695 {
3696         StringInfo      buf = context->buf;
3697
3698         if (IsA(jtnode, RangeTblRef))
3699         {
3700                 int                     varno = ((RangeTblRef *) jtnode)->rtindex;
3701                 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
3702                 List       *coldeflist = NIL;
3703                 bool            gavealias = false;
3704
3705                 switch (rte->rtekind)
3706                 {
3707                         case RTE_RELATION:
3708                                 /* Normal relation RTE */
3709                                 appendStringInfo(buf, "%s%s",
3710                                                                  only_marker(rte),
3711                                                                  generate_relation_name(rte->relid));
3712                                 break;
3713                         case RTE_SUBQUERY:
3714                                 /* Subquery RTE */
3715                                 appendStringInfoChar(buf, '(');
3716                                 get_query_def(rte->subquery, buf, context->namespaces, NULL,
3717                                                           context->prettyFlags, context->indentLevel);
3718                                 appendStringInfoChar(buf, ')');
3719                                 break;
3720                         case RTE_FUNCTION:
3721                                 /* Function RTE */
3722                                 get_rule_expr(rte->funcexpr, context, true);
3723                                 /* might need to emit column list for RECORD function */
3724                                 coldeflist = rte->coldeflist;
3725                                 break;
3726                         default:
3727                                 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
3728                                 break;
3729                 }
3730                 if (rte->alias != NULL)
3731                 {
3732                         appendStringInfo(buf, " %s",
3733                                                          quote_identifier(rte->alias->aliasname));
3734                         gavealias = true;
3735                         if (rte->alias->colnames != NIL && coldeflist == NIL)
3736                         {
3737                                 ListCell   *col;
3738
3739                                 appendStringInfoChar(buf, '(');
3740                                 foreach(col, rte->alias->colnames)
3741                                 {
3742                                         if (col != list_head(rte->alias->colnames))
3743                                                 appendStringInfo(buf, ", ");
3744                                         appendStringInfoString(buf,
3745                                                                                    quote_identifier(strVal(lfirst(col))));
3746                                 }
3747                                 appendStringInfoChar(buf, ')');
3748                         }
3749                 }
3750                 else if (rte->rtekind == RTE_RELATION &&
3751                          strcmp(rte->eref->aliasname, get_rel_name(rte->relid)) != 0)
3752                 {
3753                         /*
3754                          * Apparently the rel has been renamed since the rule was
3755                          * made. Emit a fake alias clause so that variable references
3756                          * will still work.  This is not a 100% solution but should
3757                          * work in most reasonable situations.
3758                          */
3759                         appendStringInfo(buf, " %s",
3760                                                          quote_identifier(rte->eref->aliasname));
3761                         gavealias = true;
3762                 }
3763                 if (coldeflist != NIL)
3764                 {
3765                         if (!gavealias)
3766                                 appendStringInfo(buf, " AS ");
3767                         get_from_clause_coldeflist(coldeflist, context);
3768                 }
3769         }
3770         else if (IsA(jtnode, JoinExpr))
3771         {
3772                 JoinExpr   *j = (JoinExpr *) jtnode;
3773                 bool            need_paren_on_right;
3774
3775                 need_paren_on_right = PRETTY_PAREN(context) &&
3776                         !IsA(j->rarg, RangeTblRef);
3777
3778                 if (!PRETTY_PAREN(context) || j->alias != NULL)
3779                         appendStringInfoChar(buf, '(');
3780
3781                 get_from_clause_item(j->larg, query, context);
3782
3783                 if (j->isNatural)
3784                 {
3785                         if (!PRETTY_INDENT(context))
3786                                 appendStringInfoChar(buf, ' ');
3787                         switch (j->jointype)
3788                         {
3789                                 case JOIN_INNER:
3790                                         appendContextKeyword(context, "NATURAL JOIN ",
3791                                                                                  -PRETTYINDENT_JOIN,
3792                                                                                  PRETTYINDENT_JOIN, 0);
3793                                         break;
3794                                 case JOIN_LEFT:
3795                                         appendContextKeyword(context, "NATURAL LEFT JOIN ",
3796                                                                                  -PRETTYINDENT_JOIN,
3797                                                                                  PRETTYINDENT_JOIN, 0);
3798                                         break;
3799                                 case JOIN_FULL:
3800                                         appendContextKeyword(context, "NATURAL FULL JOIN ",
3801                                                                                  -PRETTYINDENT_JOIN,
3802                                                                                  PRETTYINDENT_JOIN, 0);
3803                                         break;
3804                                 case JOIN_RIGHT:
3805                                         appendContextKeyword(context, "NATURAL RIGHT JOIN ",
3806                                                                                  -PRETTYINDENT_JOIN,
3807                                                                                  PRETTYINDENT_JOIN, 0);
3808                                         break;
3809                                 case JOIN_UNION:
3810                                         appendContextKeyword(context, "NATURAL UNION JOIN ",
3811                                                                                  -PRETTYINDENT_JOIN,
3812                                                                                  PRETTYINDENT_JOIN, 0);
3813                                         break;
3814                                 default:
3815                                         elog(ERROR, "unrecognized join type: %d",
3816                                                  (int) j->jointype);
3817                         }
3818                 }
3819                 else
3820                 {
3821                         switch (j->jointype)
3822                         {
3823                                 case JOIN_INNER:
3824                                         if (j->quals)
3825                                                 appendContextKeyword(context, " JOIN ",
3826                                                                                          -PRETTYINDENT_JOIN,
3827                                                                                          PRETTYINDENT_JOIN, 2);
3828                                         else
3829                                                 appendContextKeyword(context, " CROSS JOIN ",
3830                                                                                          -PRETTYINDENT_JOIN,
3831                                                                                          PRETTYINDENT_JOIN, 1);
3832                                         break;
3833                                 case JOIN_LEFT:
3834                                         appendContextKeyword(context, " LEFT JOIN ",
3835                                                                                  -PRETTYINDENT_JOIN,
3836                                                                                  PRETTYINDENT_JOIN, 2);
3837                                         break;
3838                                 case JOIN_FULL:
3839                                         appendContextKeyword(context, " FULL JOIN ",
3840                                                                                  -PRETTYINDENT_JOIN,
3841                                                                                  PRETTYINDENT_JOIN, 2);
3842                                         break;
3843                                 case JOIN_RIGHT:
3844                                         appendContextKeyword(context, " RIGHT JOIN ",
3845                                                                                  -PRETTYINDENT_JOIN,
3846                                                                                  PRETTYINDENT_JOIN, 2);
3847                                         break;
3848                                 case JOIN_UNION:
3849                                         appendContextKeyword(context, " UNION JOIN ",
3850                                                                                  -PRETTYINDENT_JOIN,
3851                                                                                  PRETTYINDENT_JOIN, 2);
3852                                         break;
3853                                 default:
3854                                         elog(ERROR, "unrecognized join type: %d",
3855                                                  (int) j->jointype);
3856                         }
3857                 }
3858
3859                 if (need_paren_on_right)
3860                         appendStringInfoChar(buf, '(');
3861                 get_from_clause_item(j->rarg, query, context);
3862                 if (need_paren_on_right)
3863                         appendStringInfoChar(buf, ')');
3864
3865                 context->indentLevel -= PRETTYINDENT_JOIN_ON;
3866
3867                 if (!j->isNatural)
3868                 {
3869                         if (j->using)
3870                         {
3871                                 ListCell   *col;
3872
3873                                 appendStringInfo(buf, " USING (");
3874                                 foreach(col, j->using)
3875                                 {
3876                                         if (col != list_head(j->using))
3877                                                 appendStringInfo(buf, ", ");
3878                                         appendStringInfoString(buf,
3879                                                                 quote_identifier(strVal(lfirst(col))));
3880                                 }
3881                                 appendStringInfoChar(buf, ')');
3882                         }
3883                         else if (j->quals)
3884                         {
3885                                 appendStringInfo(buf, " ON ");
3886                                 if (!PRETTY_PAREN(context))
3887                                         appendStringInfoChar(buf, '(');
3888                                 get_rule_expr(j->quals, context, false);
3889                                 if (!PRETTY_PAREN(context))
3890                                         appendStringInfoChar(buf, ')');
3891                         }
3892                 }
3893                 if (!PRETTY_PAREN(context) || j->alias != NULL)
3894                         appendStringInfoChar(buf, ')');
3895
3896                 /* Yes, it's correct to put alias after the right paren ... */
3897                 if (j->alias != NULL)
3898                 {
3899                         appendStringInfo(buf, " %s",
3900                                                          quote_identifier(j->alias->aliasname));
3901                         if (j->alias->colnames != NIL)
3902                         {
3903                                 ListCell   *col;
3904
3905                                 appendStringInfoChar(buf, '(');
3906                                 foreach(col, j->alias->colnames)
3907                                 {
3908                                         if (col != list_head(j->alias->colnames))
3909                                                 appendStringInfo(buf, ", ");
3910                                         appendStringInfoString(buf,
3911                                                                   quote_identifier(strVal(lfirst(col))));
3912                                 }
3913                                 appendStringInfoChar(buf, ')');
3914                         }
3915                 }
3916         }
3917         else
3918                 elog(ERROR, "unrecognized node type: %d",
3919                          (int) nodeTag(jtnode));
3920 }
3921
3922 /*
3923  * get_from_clause_coldeflist - reproduce FROM clause coldeflist
3924  *
3925  * The coldeflist is appended immediately (no space) to buf.  Caller is
3926  * responsible for ensuring that an alias or AS is present before it.
3927  */
3928 static void
3929 get_from_clause_coldeflist(List *coldeflist, deparse_context *context)
3930 {
3931         StringInfo      buf = context->buf;
3932         ListCell   *col;
3933         int                     i = 0;
3934
3935         appendStringInfoChar(buf, '(');
3936
3937         foreach(col, coldeflist)
3938         {
3939                 ColumnDef  *n = lfirst(col);
3940                 char       *attname;
3941                 Oid                     atttypeid;
3942                 int32           atttypmod;
3943
3944                 attname = n->colname;
3945                 atttypeid = typenameTypeId(n->typename);
3946                 atttypmod = n->typename->typmod;
3947
3948                 if (i > 0)
3949                         appendStringInfo(buf, ", ");
3950                 appendStringInfo(buf, "%s %s",
3951                                                  quote_identifier(attname),
3952                                                  format_type_with_typemod(atttypeid, atttypmod));
3953                 i++;
3954         }
3955
3956         appendStringInfoChar(buf, ')');
3957 }
3958
3959 /*
3960  * get_opclass_name                     - fetch name of an index operator class
3961  *
3962  * The opclass name is appended (after a space) to buf.
3963  *
3964  * Output is suppressed if the opclass is the default for the given
3965  * actual_datatype.  (If you don't want this behavior, just pass
3966  * InvalidOid for actual_datatype.)
3967  */
3968 static void
3969 get_opclass_name(Oid opclass, Oid actual_datatype,
3970                                  StringInfo buf)
3971 {
3972         HeapTuple       ht_opc;
3973         Form_pg_opclass opcrec;
3974         char       *opcname;
3975         char       *nspname;
3976         bool            isvisible;
3977
3978         /* Domains use their base type's default opclass */
3979         if (OidIsValid(actual_datatype))
3980                 actual_datatype = getBaseType(actual_datatype);
3981
3982         ht_opc = SearchSysCache(CLAOID,
3983                                                         ObjectIdGetDatum(opclass),
3984                                                         0, 0, 0);
3985         if (!HeapTupleIsValid(ht_opc))
3986                 elog(ERROR, "cache lookup failed for opclass %u", opclass);
3987         opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
3988
3989         /* Special case for ARRAY_OPS: pretend it is default for any array type */
3990         if (OidIsValid(actual_datatype))
3991         {
3992                 if (opcrec->opcintype == ANYARRAYOID &&
3993                         OidIsValid(get_element_type(actual_datatype)))
3994                         actual_datatype = opcrec->opcintype;
3995         }
3996
3997         /* Must force use of opclass name if not in search path */
3998         isvisible = OpclassIsVisible(opclass);
3999         
4000         if (actual_datatype != opcrec->opcintype || !opcrec->opcdefault ||
4001                 !isvisible)
4002         {
4003                 /* Okay, we need the opclass name.      Do we need to qualify it? */
4004                 opcname = NameStr(opcrec->opcname);
4005                 if (isvisible)
4006                         appendStringInfo(buf, " %s", quote_identifier(opcname));
4007                 else
4008                 {
4009                         nspname = get_namespace_name(opcrec->opcnamespace);
4010                         appendStringInfo(buf, " %s.%s",
4011                                                          quote_identifier(nspname),
4012                                                          quote_identifier(opcname));
4013                 }
4014         }
4015         ReleaseSysCache(ht_opc);
4016 }
4017
4018 /*
4019  * processIndirection - take care of array and subfield assignment
4020  *
4021  * We strip any top-level FieldStore or assignment ArrayRef nodes that
4022  * appear in the input, printing out the appropriate decoration for the
4023  * base column name (that the caller just printed).  We return the
4024  * subexpression that's to be assigned.
4025  */
4026 static Node *
4027 processIndirection(Node *node, deparse_context *context)
4028 {
4029         StringInfo      buf = context->buf;
4030
4031         for (;;)
4032         {
4033                 if (node == NULL)
4034                         break;
4035                 if (IsA(node, FieldStore))
4036                 {
4037                         FieldStore *fstore = (FieldStore *) node;
4038                         Oid                     typrelid;
4039                         char       *fieldname;
4040
4041                         /* lookup tuple type */
4042                         typrelid = get_typ_typrelid(fstore->resulttype);
4043                         if (!OidIsValid(typrelid))
4044                                 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
4045                                          format_type_be(fstore->resulttype));
4046                         /*
4047                          * Get the field name.  Note we assume here that there's only
4048                          * one field being assigned to.  This is okay in stored rules
4049                          * but could be wrong in executable target lists.  Presently no
4050                          * problem since explain.c doesn't print plan targetlists, but
4051                          * someday may have to think of something ...
4052                          */
4053                         fieldname = get_relid_attribute_name(typrelid,
4054                                                                                                  linitial_int(fstore->fieldnums));
4055                         appendStringInfo(buf, ".%s", quote_identifier(fieldname));
4056                         /*
4057                          * We ignore arg since it should be an uninteresting reference
4058                          * to the target column or subcolumn.
4059                          */
4060                         node = (Node *) linitial(fstore->newvals);
4061                 }
4062                 else if (IsA(node, ArrayRef))
4063                 {
4064                         ArrayRef   *aref = (ArrayRef *) node;
4065
4066                         if (aref->refassgnexpr == NULL)
4067                                 break;
4068                         printSubscripts(aref, context);
4069                         /*
4070                          * We ignore refexpr since it should be an uninteresting reference
4071                          * to the target column or subcolumn.
4072                          */
4073                         node = (Node *) aref->refassgnexpr;
4074                 }
4075                 else
4076                         break;
4077         }
4078
4079         return node;
4080 }
4081
4082 static void
4083 printSubscripts(ArrayRef *aref, deparse_context *context)
4084 {
4085         StringInfo      buf = context->buf;
4086         ListCell   *lowlist_item;
4087         ListCell   *uplist_item;
4088
4089         lowlist_item = list_head(aref->reflowerindexpr); /* could be NULL */
4090         foreach(uplist_item, aref->refupperindexpr)
4091         {
4092                 appendStringInfoChar(buf, '[');
4093                 if (lowlist_item)
4094                 {
4095                         get_rule_expr((Node *) lfirst(lowlist_item), context, false);
4096                         appendStringInfoChar(buf, ':');
4097                         lowlist_item = lnext(lowlist_item);
4098                 }
4099                 get_rule_expr((Node *) lfirst(uplist_item), context, false);
4100                 appendStringInfoChar(buf, ']');
4101         }
4102 }
4103
4104 /*
4105  * quote_identifier                     - Quote an identifier only if needed
4106  *
4107  * When quotes are needed, we palloc the required space; slightly
4108  * space-wasteful but well worth it for notational simplicity.
4109  */
4110 const char *
4111 quote_identifier(const char *ident)
4112 {
4113         /*
4114          * Can avoid quoting if ident starts with a lowercase letter or
4115          * underscore and contains only lowercase letters, digits, and
4116          * underscores, *and* is not any SQL keyword.  Otherwise, supply
4117          * quotes.
4118          */
4119         int                     nquotes = 0;
4120         bool            safe;
4121         const char *ptr;
4122         char       *result;
4123         char       *optr;
4124
4125         /*
4126          * would like to use <ctype.h> macros here, but they might yield
4127          * unwanted locale-specific results...
4128          */
4129         safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
4130
4131         for (ptr = ident; *ptr; ptr++)
4132         {
4133                 char            ch = *ptr;
4134
4135                 if ((ch >= 'a' && ch <= 'z') ||
4136                         (ch >= '0' && ch <= '9') ||
4137                         (ch == '_'))
4138                 {
4139                         /* okay */
4140                 }
4141                 else
4142                 {
4143                         safe = false;
4144                         if (ch == '"')
4145                                 nquotes++;
4146                 }
4147         }
4148
4149         if (safe)
4150         {
4151                 /*
4152                  * Check for keyword.  This test is overly strong, since many of
4153                  * the "keywords" known to the parser are usable as column names,
4154                  * but the parser doesn't provide any easy way to test for whether
4155                  * an identifier is safe or not... so be safe not sorry.
4156                  *
4157                  * Note: ScanKeywordLookup() does case-insensitive comparison, but
4158                  * that's fine, since we already know we have all-lower-case.
4159                  */
4160                 if (ScanKeywordLookup(ident) != NULL)
4161                         safe = false;
4162         }
4163
4164         if (safe)
4165                 return ident;                   /* no change needed */
4166
4167         result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
4168
4169         optr = result;
4170         *optr++ = '"';
4171         for (ptr = ident; *ptr; ptr++)
4172         {
4173                 char            ch = *ptr;
4174
4175                 if (ch == '"')
4176                         *optr++ = '"';
4177                 *optr++ = ch;
4178         }
4179         *optr++ = '"';
4180         *optr = '\0';
4181
4182         return result;
4183 }
4184
4185 /*
4186  * quote_qualified_identifier   - Quote a possibly-qualified identifier
4187  *
4188  * Return a name of the form namespace.ident, or just ident if namespace
4189  * is NULL, quoting each component if necessary.  The result is palloc'd.
4190  */
4191 char *
4192 quote_qualified_identifier(const char *namespace,
4193                                                    const char *ident)
4194 {
4195         StringInfoData buf;
4196
4197         initStringInfo(&buf);
4198         if (namespace)
4199                 appendStringInfo(&buf, "%s.", quote_identifier(namespace));
4200         appendStringInfoString(&buf, quote_identifier(ident));
4201         return buf.data;
4202 }
4203
4204 /*
4205  * generate_relation_name
4206  *              Compute the name to display for a relation specified by OID
4207  *
4208  * The result includes all necessary quoting and schema-prefixing.
4209  */
4210 static char *
4211 generate_relation_name(Oid relid)
4212 {
4213         HeapTuple       tp;
4214         Form_pg_class reltup;
4215         char       *nspname;
4216         char       *result;
4217
4218         tp = SearchSysCache(RELOID,
4219                                                 ObjectIdGetDatum(relid),
4220                                                 0, 0, 0);
4221         if (!HeapTupleIsValid(tp))
4222                 elog(ERROR, "cache lookup failed for relation %u", relid);
4223         reltup = (Form_pg_class) GETSTRUCT(tp);
4224
4225         /* Qualify the name if not visible in search path */
4226         if (RelationIsVisible(relid))
4227                 nspname = NULL;
4228         else
4229                 nspname = get_namespace_name(reltup->relnamespace);
4230
4231         result = quote_qualified_identifier(nspname, NameStr(reltup->relname));
4232
4233         ReleaseSysCache(tp);
4234
4235         return result;
4236 }
4237
4238 /*
4239  * generate_function_name
4240  *              Compute the name to display for a function specified by OID,
4241  *              given that it is being called with the specified actual arg types.
4242  *              (Arg types matter because of ambiguous-function resolution rules.)
4243  *
4244  * The result includes all necessary quoting and schema-prefixing.
4245  */
4246 static char *
4247 generate_function_name(Oid funcid, int nargs, Oid *argtypes)
4248 {
4249         HeapTuple       proctup;
4250         Form_pg_proc procform;
4251         char       *proname;
4252         char       *nspname;
4253         char       *result;
4254         FuncDetailCode p_result;
4255         Oid                     p_funcid;
4256         Oid                     p_rettype;
4257         bool            p_retset;
4258         Oid                *p_true_typeids;
4259
4260         proctup = SearchSysCache(PROCOID,
4261                                                          ObjectIdGetDatum(funcid),
4262                                                          0, 0, 0);
4263         if (!HeapTupleIsValid(proctup))
4264                 elog(ERROR, "cache lookup failed for function %u", funcid);
4265         procform = (Form_pg_proc) GETSTRUCT(proctup);
4266         proname = NameStr(procform->proname);
4267         Assert(nargs == procform->pronargs);
4268
4269         /*
4270          * The idea here is to schema-qualify only if the parser would fail to
4271          * resolve the correct function given the unqualified func name with
4272          * the specified argtypes.
4273          */
4274         p_result = func_get_detail(list_make1(makeString(proname)),
4275                                                            NIL, nargs, argtypes,
4276                                                            &p_funcid, &p_rettype,
4277                                                            &p_retset, &p_true_typeids);
4278         if ((p_result == FUNCDETAIL_NORMAL || p_result == FUNCDETAIL_AGGREGATE) &&
4279                 p_funcid == funcid)
4280                 nspname = NULL;
4281         else
4282                 nspname = get_namespace_name(procform->pronamespace);
4283
4284         result = quote_qualified_identifier(nspname, proname);
4285
4286         ReleaseSysCache(proctup);
4287
4288         return result;
4289 }
4290
4291 /*
4292  * generate_operator_name
4293  *              Compute the name to display for an operator specified by OID,
4294  *              given that it is being called with the specified actual arg types.
4295  *              (Arg types matter because of ambiguous-operator resolution rules.
4296  *              Pass InvalidOid for unused arg of a unary operator.)
4297  *
4298  * The result includes all necessary quoting and schema-prefixing,
4299  * plus the OPERATOR() decoration needed to use a qualified operator name
4300  * in an expression.
4301  */
4302 static char *
4303 generate_operator_name(Oid operid, Oid arg1, Oid arg2)
4304 {
4305         StringInfoData buf;
4306         HeapTuple       opertup;
4307         Form_pg_operator operform;
4308         char       *oprname;
4309         char       *nspname;
4310         Operator        p_result;
4311
4312         initStringInfo(&buf);
4313
4314         opertup = SearchSysCache(OPEROID,
4315                                                          ObjectIdGetDatum(operid),
4316                                                          0, 0, 0);
4317         if (!HeapTupleIsValid(opertup))
4318                 elog(ERROR, "cache lookup failed for operator %u", operid);
4319         operform = (Form_pg_operator) GETSTRUCT(opertup);
4320         oprname = NameStr(operform->oprname);
4321
4322         /*
4323          * The idea here is to schema-qualify only if the parser would fail to
4324          * resolve the correct operator given the unqualified op name with the
4325          * specified argtypes.
4326          */
4327         switch (operform->oprkind)
4328         {
4329                 case 'b':
4330                         p_result = oper(list_make1(makeString(oprname)), arg1, arg2, true);
4331                         break;
4332                 case 'l':
4333                         p_result = left_oper(list_make1(makeString(oprname)), arg2, true);
4334                         break;
4335                 case 'r':
4336                         p_result = right_oper(list_make1(makeString(oprname)), arg1, true);
4337                         break;
4338                 default:
4339                         elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
4340                         p_result = NULL;        /* keep compiler quiet */
4341                         break;
4342         }
4343
4344         if (p_result != NULL && oprid(p_result) == operid)
4345                 nspname = NULL;
4346         else
4347         {
4348                 nspname = get_namespace_name(operform->oprnamespace);
4349                 appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
4350         }
4351
4352         appendStringInfoString(&buf, oprname);
4353
4354         if (nspname)
4355                 appendStringInfoChar(&buf, ')');
4356
4357         if (p_result != NULL)
4358                 ReleaseSysCache(p_result);
4359
4360         ReleaseSysCache(opertup);
4361
4362         return buf.data;
4363 }
4364
4365 /*
4366  * Print out a possibly-qualified operator name
4367  */
4368 static void
4369 print_operator_name(StringInfo buf, List *opname)
4370 {
4371         ListCell        *op = list_head(opname);
4372         int                      nnames = list_length(opname);
4373
4374         if (nnames == 1)
4375                 appendStringInfoString(buf, strVal(lfirst(op)));
4376         else
4377         {
4378                 appendStringInfo(buf, "OPERATOR(");
4379                 while (nnames-- > 1)
4380                 {
4381                         appendStringInfo(buf, "%s.",
4382                                                          quote_identifier(strVal(lfirst(op))));
4383                         op = lnext(op);
4384                 }
4385                 appendStringInfo(buf, "%s)", strVal(lfirst(op)));
4386         }
4387 }
4388
4389 /*
4390  * Given a C string, produce a TEXT datum.
4391  *
4392  * We assume that the input was palloc'd and may be freed.
4393  */
4394 static text *
4395 string_to_text(char *str)
4396 {
4397         text       *result;
4398         int                     slen = strlen(str);
4399         int                     tlen;
4400
4401         tlen = slen + VARHDRSZ;
4402         result = (text *) palloc(tlen);
4403         VARATT_SIZEP(result) = tlen;
4404         memcpy(VARDATA(result), str, slen);
4405
4406         pfree(str);
4407
4408         return result;
4409 }