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