Fix failure to double-quote function argument names when needed, in
[PostgreSQL.git] / src / backend / utils / adt / ruleutils.c
blobdb2182fd905acd41665a8dfcd0b50b8a3f51ff5f
1 /*-------------------------------------------------------------------------
3 * ruleutils.c
4 * Functions to convert stored expressions/querytrees back to
5 * source text
7 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * IDENTIFICATION
12 * $PostgreSQL$
14 *-------------------------------------------------------------------------
16 #include "postgres.h"
18 #include <unistd.h>
19 #include <fcntl.h>
21 #include "access/genam.h"
22 #include "access/sysattr.h"
23 #include "catalog/dependency.h"
24 #include "catalog/indexing.h"
25 #include "catalog/pg_authid.h"
26 #include "catalog/pg_constraint.h"
27 #include "catalog/pg_depend.h"
28 #include "catalog/pg_language.h"
29 #include "catalog/pg_opclass.h"
30 #include "catalog/pg_operator.h"
31 #include "catalog/pg_proc.h"
32 #include "catalog/pg_trigger.h"
33 #include "catalog/pg_type.h"
34 #include "commands/defrem.h"
35 #include "commands/tablespace.h"
36 #include "executor/spi.h"
37 #include "funcapi.h"
38 #include "nodes/makefuncs.h"
39 #include "nodes/nodeFuncs.h"
40 #include "optimizer/clauses.h"
41 #include "optimizer/tlist.h"
42 #include "parser/gramparse.h"
43 #include "parser/keywords.h"
44 #include "parser/parse_func.h"
45 #include "parser/parse_oper.h"
46 #include "parser/parsetree.h"
47 #include "rewrite/rewriteHandler.h"
48 #include "rewrite/rewriteManip.h"
49 #include "rewrite/rewriteSupport.h"
50 #include "utils/array.h"
51 #include "utils/builtins.h"
52 #include "utils/fmgroids.h"
53 #include "utils/lsyscache.h"
54 #include "utils/tqual.h"
55 #include "utils/syscache.h"
56 #include "utils/typcache.h"
57 #include "utils/xml.h"
60 /* ----------
61 * Pretty formatting constants
62 * ----------
65 /* Indent counts */
66 #define PRETTYINDENT_STD 8
67 #define PRETTYINDENT_JOIN 13
68 #define PRETTYINDENT_JOIN_ON (PRETTYINDENT_JOIN-PRETTYINDENT_STD)
69 #define PRETTYINDENT_VAR 4
71 /* Pretty flags */
72 #define PRETTYFLAG_PAREN 1
73 #define PRETTYFLAG_INDENT 2
75 /* macro to test if pretty action needed */
76 #define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
77 #define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)
80 /* ----------
81 * Local data types
82 * ----------
85 /* Context info needed for invoking a recursive querytree display routine */
86 typedef struct
88 StringInfo buf; /* output buffer to append to */
89 List *namespaces; /* List of deparse_namespace nodes */
90 List *windowClause; /* Current query level's WINDOW clause */
91 List *windowTList; /* targetlist for resolving WINDOW clause */
92 int prettyFlags; /* enabling of pretty-print functions */
93 int indentLevel; /* current indent level for prettyprint */
94 bool varprefix; /* TRUE to print prefixes on Vars */
95 } deparse_context;
98 * Each level of query context around a subtree needs a level of Var namespace.
99 * A Var having varlevelsup=N refers to the N'th item (counting from 0) in
100 * the current context's namespaces list.
102 * The rangetable is the list of actual RTEs from the query tree, and the
103 * cte list is the list of actual CTEs.
105 * For deparsing plan trees, we provide for outer and inner subplan nodes.
106 * The tlists of these nodes are used to resolve OUTER and INNER varnos.
107 * Also, in the plan-tree case we don't have access to the parse-time CTE
108 * list, so we need a list of subplans instead.
110 typedef struct
112 List *rtable; /* List of RangeTblEntry nodes */
113 List *ctes; /* List of CommonTableExpr nodes */
114 List *subplans; /* List of subplans, in plan-tree case */
115 Plan *outer_plan; /* OUTER subplan, or NULL if none */
116 Plan *inner_plan; /* INNER subplan, or NULL if none */
117 } deparse_namespace;
120 /* ----------
121 * Global data
122 * ----------
124 static SPIPlanPtr plan_getrulebyoid = NULL;
125 static const char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";
126 static SPIPlanPtr plan_getviewrule = NULL;
127 static const char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";
130 /* ----------
131 * Local functions
133 * Most of these functions used to use fixed-size buffers to build their
134 * results. Now, they take an (already initialized) StringInfo object
135 * as a parameter, and append their text output to its contents.
136 * ----------
138 static char *deparse_expression_pretty(Node *expr, List *dpcontext,
139 bool forceprefix, bool showimplicit,
140 int prettyFlags, int startIndent);
141 static char *pg_get_viewdef_worker(Oid viewoid, int prettyFlags);
142 static void decompile_column_index_array(Datum column_index_array, Oid relId,
143 StringInfo buf);
144 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
145 static char *pg_get_indexdef_worker(Oid indexrelid, int colno, bool showTblSpc,
146 int prettyFlags);
147 static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
148 int prettyFlags);
149 static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
150 int prettyFlags);
151 static int print_function_arguments(StringInfo buf, HeapTuple proctup,
152 bool print_table_args, bool print_defaults);
153 static void print_function_rettype(StringInfo buf, HeapTuple proctup);
154 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
155 int prettyFlags);
156 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
157 int prettyFlags);
158 static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
159 TupleDesc resultDesc, int prettyFlags, int startIndent);
160 static void get_values_def(List *values_lists, deparse_context *context);
161 static void get_with_clause(Query *query, deparse_context *context);
162 static void get_select_query_def(Query *query, deparse_context *context,
163 TupleDesc resultDesc);
164 static void get_insert_query_def(Query *query, deparse_context *context);
165 static void get_update_query_def(Query *query, deparse_context *context);
166 static void get_delete_query_def(Query *query, deparse_context *context);
167 static void get_utility_query_def(Query *query, deparse_context *context);
168 static void get_basic_select_query(Query *query, deparse_context *context,
169 TupleDesc resultDesc);
170 static void get_target_list(List *targetList, deparse_context *context,
171 TupleDesc resultDesc);
172 static void get_setop_query(Node *setOp, Query *query,
173 deparse_context *context,
174 TupleDesc resultDesc);
175 static Node *get_rule_sortgroupclause(SortGroupClause *srt, List *tlist,
176 bool force_colno,
177 deparse_context *context);
178 static void get_rule_orderby(List *orderList, List *targetList,
179 bool force_colno, deparse_context *context);
180 static void get_rule_windowclause(Query *query, deparse_context *context);
181 static void get_rule_windowspec(WindowClause *wc, List *targetList,
182 deparse_context *context);
183 static void push_plan(deparse_namespace *dpns, Plan *subplan);
184 static char *get_variable(Var *var, int levelsup, bool showstar,
185 deparse_context *context);
186 static RangeTblEntry *find_rte_by_refname(const char *refname,
187 deparse_context *context);
188 static const char *get_simple_binary_op_name(OpExpr *expr);
189 static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
190 static void appendStringInfoSpaces(StringInfo buf, int count);
191 static void appendContextKeyword(deparse_context *context, const char *str,
192 int indentBefore, int indentAfter, int indentPlus);
193 static void get_rule_expr(Node *node, deparse_context *context,
194 bool showimplicit);
195 static void get_oper_expr(OpExpr *expr, deparse_context *context);
196 static void get_func_expr(FuncExpr *expr, deparse_context *context,
197 bool showimplicit);
198 static void get_agg_expr(Aggref *aggref, deparse_context *context);
199 static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
200 static void get_coercion_expr(Node *arg, deparse_context *context,
201 Oid resulttype, int32 resulttypmod,
202 Node *parentNode);
203 static void get_const_expr(Const *constval, deparse_context *context,
204 int showtype);
205 static void simple_quote_literal(StringInfo buf, const char *val);
206 static void get_sublink_expr(SubLink *sublink, deparse_context *context);
207 static void get_from_clause(Query *query, const char *prefix,
208 deparse_context *context);
209 static void get_from_clause_item(Node *jtnode, Query *query,
210 deparse_context *context);
211 static void get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
212 deparse_context *context);
213 static void get_from_clause_coldeflist(List *names, List *types, List *typmods,
214 deparse_context *context);
215 static void get_opclass_name(Oid opclass, Oid actual_datatype,
216 StringInfo buf);
217 static Node *processIndirection(Node *node, deparse_context *context,
218 bool printit);
219 static void printSubscripts(ArrayRef *aref, deparse_context *context);
220 static char *generate_relation_name(Oid relid, List *namespaces);
221 static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes,
222 bool *is_variadic);
223 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
224 static text *string_to_text(char *str);
225 static char *flatten_reloptions(Oid relid);
227 #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
230 /* ----------
231 * get_ruledef - Do it all and return a text
232 * that could be used as a statement
233 * to recreate the rule
234 * ----------
236 Datum
237 pg_get_ruledef(PG_FUNCTION_ARGS)
239 Oid ruleoid = PG_GETARG_OID(0);
241 PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, 0)));
245 Datum
246 pg_get_ruledef_ext(PG_FUNCTION_ARGS)
248 Oid ruleoid = PG_GETARG_OID(0);
249 bool pretty = PG_GETARG_BOOL(1);
250 int prettyFlags;
252 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
253 PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, prettyFlags)));
257 static char *
258 pg_get_ruledef_worker(Oid ruleoid, int prettyFlags)
260 Datum args[1];
261 char nulls[1];
262 int spirc;
263 HeapTuple ruletup;
264 TupleDesc rulettc;
265 StringInfoData buf;
268 * Do this first so that string is alloc'd in outer context not SPI's.
270 initStringInfo(&buf);
273 * Connect to SPI manager
275 if (SPI_connect() != SPI_OK_CONNECT)
276 elog(ERROR, "SPI_connect failed");
279 * On the first call prepare the plan to lookup pg_rewrite. We read
280 * pg_rewrite over the SPI manager instead of using the syscache to be
281 * checked for read access on pg_rewrite.
283 if (plan_getrulebyoid == NULL)
285 Oid argtypes[1];
286 SPIPlanPtr plan;
288 argtypes[0] = OIDOID;
289 plan = SPI_prepare(query_getrulebyoid, 1, argtypes);
290 if (plan == NULL)
291 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);
292 plan_getrulebyoid = SPI_saveplan(plan);
296 * Get the pg_rewrite tuple for this rule
298 args[0] = ObjectIdGetDatum(ruleoid);
299 nulls[0] = ' ';
300 spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 1);
301 if (spirc != SPI_OK_SELECT)
302 elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);
303 if (SPI_processed != 1)
304 appendStringInfo(&buf, "-");
305 else
308 * Get the rule's definition and put it into executor's memory
310 ruletup = SPI_tuptable->vals[0];
311 rulettc = SPI_tuptable->tupdesc;
312 make_ruledef(&buf, ruletup, rulettc, prettyFlags);
316 * Disconnect from SPI manager
318 if (SPI_finish() != SPI_OK_FINISH)
319 elog(ERROR, "SPI_finish failed");
321 return buf.data;
325 /* ----------
326 * get_viewdef - Mainly the same thing, but we
327 * only return the SELECT part of a view
328 * ----------
330 Datum
331 pg_get_viewdef(PG_FUNCTION_ARGS)
333 /* By OID */
334 Oid viewoid = PG_GETARG_OID(0);
336 PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, 0)));
340 Datum
341 pg_get_viewdef_ext(PG_FUNCTION_ARGS)
343 /* By OID */
344 Oid viewoid = PG_GETARG_OID(0);
345 bool pretty = PG_GETARG_BOOL(1);
346 int prettyFlags;
348 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
349 PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags)));
352 Datum
353 pg_get_viewdef_name(PG_FUNCTION_ARGS)
355 /* By qualified name */
356 text *viewname = PG_GETARG_TEXT_P(0);
357 RangeVar *viewrel;
358 Oid viewoid;
360 viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
361 viewoid = RangeVarGetRelid(viewrel, false);
363 PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, 0)));
367 Datum
368 pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
370 /* By qualified name */
371 text *viewname = PG_GETARG_TEXT_P(0);
372 bool pretty = PG_GETARG_BOOL(1);
373 int prettyFlags;
374 RangeVar *viewrel;
375 Oid viewoid;
377 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
378 viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname));
379 viewoid = RangeVarGetRelid(viewrel, false);
381 PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags)));
385 * Common code for by-OID and by-name variants of pg_get_viewdef
387 static char *
388 pg_get_viewdef_worker(Oid viewoid, int prettyFlags)
390 Datum args[2];
391 char nulls[2];
392 int spirc;
393 HeapTuple ruletup;
394 TupleDesc rulettc;
395 StringInfoData buf;
398 * Do this first so that string is alloc'd in outer context not SPI's.
400 initStringInfo(&buf);
403 * Connect to SPI manager
405 if (SPI_connect() != SPI_OK_CONNECT)
406 elog(ERROR, "SPI_connect failed");
409 * On the first call prepare the plan to lookup pg_rewrite. We read
410 * pg_rewrite over the SPI manager instead of using the syscache to be
411 * checked for read access on pg_rewrite.
413 if (plan_getviewrule == NULL)
415 Oid argtypes[2];
416 SPIPlanPtr plan;
418 argtypes[0] = OIDOID;
419 argtypes[1] = NAMEOID;
420 plan = SPI_prepare(query_getviewrule, 2, argtypes);
421 if (plan == NULL)
422 elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);
423 plan_getviewrule = SPI_saveplan(plan);
427 * Get the pg_rewrite tuple for the view's SELECT rule
429 args[0] = ObjectIdGetDatum(viewoid);
430 args[1] = PointerGetDatum(ViewSelectRuleName);
431 nulls[0] = ' ';
432 nulls[1] = ' ';
433 spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 2);
434 if (spirc != SPI_OK_SELECT)
435 elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);
436 if (SPI_processed != 1)
437 appendStringInfo(&buf, "Not a view");
438 else
441 * Get the rule's definition and put it into executor's memory
443 ruletup = SPI_tuptable->vals[0];
444 rulettc = SPI_tuptable->tupdesc;
445 make_viewdef(&buf, ruletup, rulettc, prettyFlags);
449 * Disconnect from SPI manager
451 if (SPI_finish() != SPI_OK_FINISH)
452 elog(ERROR, "SPI_finish failed");
454 return buf.data;
457 /* ----------
458 * get_triggerdef - Get the definition of a trigger
459 * ----------
461 Datum
462 pg_get_triggerdef(PG_FUNCTION_ARGS)
464 Oid trigid = PG_GETARG_OID(0);
465 HeapTuple ht_trig;
466 Form_pg_trigger trigrec;
467 StringInfoData buf;
468 Relation tgrel;
469 ScanKeyData skey[1];
470 SysScanDesc tgscan;
471 int findx = 0;
472 char *tgname;
475 * Fetch the pg_trigger tuple by the Oid of the trigger
477 tgrel = heap_open(TriggerRelationId, AccessShareLock);
479 ScanKeyInit(&skey[0],
480 ObjectIdAttributeNumber,
481 BTEqualStrategyNumber, F_OIDEQ,
482 ObjectIdGetDatum(trigid));
484 tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true,
485 SnapshotNow, 1, skey);
487 ht_trig = systable_getnext(tgscan);
489 if (!HeapTupleIsValid(ht_trig))
490 elog(ERROR, "could not find tuple for trigger %u", trigid);
492 trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
495 * Start the trigger definition. Note that the trigger's name should never
496 * be schema-qualified, but the trigger rel's name may be.
498 initStringInfo(&buf);
500 tgname = NameStr(trigrec->tgname);
501 appendStringInfo(&buf, "CREATE %sTRIGGER %s ",
502 trigrec->tgisconstraint ? "CONSTRAINT " : "",
503 quote_identifier(tgname));
505 if (TRIGGER_FOR_BEFORE(trigrec->tgtype))
506 appendStringInfo(&buf, "BEFORE");
507 else
508 appendStringInfo(&buf, "AFTER");
509 if (TRIGGER_FOR_INSERT(trigrec->tgtype))
511 appendStringInfo(&buf, " INSERT");
512 findx++;
514 if (TRIGGER_FOR_DELETE(trigrec->tgtype))
516 if (findx > 0)
517 appendStringInfo(&buf, " OR DELETE");
518 else
519 appendStringInfo(&buf, " DELETE");
520 findx++;
522 if (TRIGGER_FOR_UPDATE(trigrec->tgtype))
524 if (findx > 0)
525 appendStringInfo(&buf, " OR UPDATE");
526 else
527 appendStringInfo(&buf, " UPDATE");
529 if (TRIGGER_FOR_TRUNCATE(trigrec->tgtype))
531 if (findx > 0)
532 appendStringInfo(&buf, " OR TRUNCATE");
533 else
534 appendStringInfo(&buf, " TRUNCATE");
536 appendStringInfo(&buf, " ON %s ",
537 generate_relation_name(trigrec->tgrelid, NIL));
539 if (trigrec->tgisconstraint)
541 if (trigrec->tgconstrrelid != InvalidOid)
542 appendStringInfo(&buf, "FROM %s ",
543 generate_relation_name(trigrec->tgconstrrelid,
544 NIL));
545 if (!trigrec->tgdeferrable)
546 appendStringInfo(&buf, "NOT ");
547 appendStringInfo(&buf, "DEFERRABLE INITIALLY ");
548 if (trigrec->tginitdeferred)
549 appendStringInfo(&buf, "DEFERRED ");
550 else
551 appendStringInfo(&buf, "IMMEDIATE ");
555 if (TRIGGER_FOR_ROW(trigrec->tgtype))
556 appendStringInfo(&buf, "FOR EACH ROW ");
557 else
558 appendStringInfo(&buf, "FOR EACH STATEMENT ");
560 appendStringInfo(&buf, "EXECUTE PROCEDURE %s(",
561 generate_function_name(trigrec->tgfoid, 0, NULL, NULL));
563 if (trigrec->tgnargs > 0)
565 bytea *val;
566 bool isnull;
567 char *p;
568 int i;
570 val = DatumGetByteaP(fastgetattr(ht_trig,
571 Anum_pg_trigger_tgargs,
572 tgrel->rd_att, &isnull));
573 if (isnull)
574 elog(ERROR, "tgargs is null for trigger %u", trigid);
575 p = (char *) VARDATA(val);
576 for (i = 0; i < trigrec->tgnargs; i++)
578 if (i > 0)
579 appendStringInfo(&buf, ", ");
580 simple_quote_literal(&buf, p);
581 /* advance p to next string embedded in tgargs */
582 while (*p)
583 p++;
584 p++;
588 /* We deliberately do not put semi-colon at end */
589 appendStringInfo(&buf, ")");
591 /* Clean up */
592 systable_endscan(tgscan);
594 heap_close(tgrel, AccessShareLock);
596 PG_RETURN_TEXT_P(string_to_text(buf.data));
599 /* ----------
600 * get_indexdef - Get the definition of an index
602 * In the extended version, there is a colno argument as well as pretty bool.
603 * if colno == 0, we want a complete index definition.
604 * if colno > 0, we only want the Nth index key's variable or expression.
606 * Note that the SQL-function versions of this omit any info about the
607 * index tablespace; this is intentional because pg_dump wants it that way.
608 * However pg_get_indexdef_string() includes index tablespace if not default.
609 * ----------
611 Datum
612 pg_get_indexdef(PG_FUNCTION_ARGS)
614 Oid indexrelid = PG_GETARG_OID(0);
616 PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, 0,
617 false, 0)));
620 Datum
621 pg_get_indexdef_ext(PG_FUNCTION_ARGS)
623 Oid indexrelid = PG_GETARG_OID(0);
624 int32 colno = PG_GETARG_INT32(1);
625 bool pretty = PG_GETARG_BOOL(2);
626 int prettyFlags;
628 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
629 PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, colno,
630 false, prettyFlags)));
633 /* Internal version that returns a palloc'd C string */
634 char *
635 pg_get_indexdef_string(Oid indexrelid)
637 return pg_get_indexdef_worker(indexrelid, 0, true, 0);
640 static char *
641 pg_get_indexdef_worker(Oid indexrelid, int colno, bool showTblSpc,
642 int prettyFlags)
644 HeapTuple ht_idx;
645 HeapTuple ht_idxrel;
646 HeapTuple ht_am;
647 Form_pg_index idxrec;
648 Form_pg_class idxrelrec;
649 Form_pg_am amrec;
650 List *indexprs;
651 ListCell *indexpr_item;
652 List *context;
653 Oid indrelid;
654 int keyno;
655 Oid keycoltype;
656 Datum indclassDatum;
657 Datum indoptionDatum;
658 bool isnull;
659 oidvector *indclass;
660 int2vector *indoption;
661 StringInfoData buf;
662 char *str;
663 char *sep;
666 * Fetch the pg_index tuple by the Oid of the index
668 ht_idx = SearchSysCache(INDEXRELID,
669 ObjectIdGetDatum(indexrelid),
670 0, 0, 0);
671 if (!HeapTupleIsValid(ht_idx))
672 elog(ERROR, "cache lookup failed for index %u", indexrelid);
673 idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
675 indrelid = idxrec->indrelid;
676 Assert(indexrelid == idxrec->indexrelid);
678 /* Must get indclass and indoption the hard way */
679 indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
680 Anum_pg_index_indclass, &isnull);
681 Assert(!isnull);
682 indclass = (oidvector *) DatumGetPointer(indclassDatum);
683 indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
684 Anum_pg_index_indoption, &isnull);
685 Assert(!isnull);
686 indoption = (int2vector *) DatumGetPointer(indoptionDatum);
689 * Fetch the pg_class tuple of the index relation
691 ht_idxrel = SearchSysCache(RELOID,
692 ObjectIdGetDatum(indexrelid),
693 0, 0, 0);
694 if (!HeapTupleIsValid(ht_idxrel))
695 elog(ERROR, "cache lookup failed for relation %u", indexrelid);
696 idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
699 * Fetch the pg_am tuple of the index' access method
701 ht_am = SearchSysCache(AMOID,
702 ObjectIdGetDatum(idxrelrec->relam),
703 0, 0, 0);
704 if (!HeapTupleIsValid(ht_am))
705 elog(ERROR, "cache lookup failed for access method %u",
706 idxrelrec->relam);
707 amrec = (Form_pg_am) GETSTRUCT(ht_am);
710 * Get the index expressions, if any. (NOTE: we do not use the relcache
711 * versions of the expressions and predicate, because we want to display
712 * non-const-folded expressions.)
714 if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))
716 Datum exprsDatum;
717 bool isnull;
718 char *exprsString;
720 exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
721 Anum_pg_index_indexprs, &isnull);
722 Assert(!isnull);
723 exprsString = TextDatumGetCString(exprsDatum);
724 indexprs = (List *) stringToNode(exprsString);
725 pfree(exprsString);
727 else
728 indexprs = NIL;
730 indexpr_item = list_head(indexprs);
732 context = deparse_context_for(get_rel_name(indrelid), indrelid);
735 * Start the index definition. Note that the index's name should never be
736 * schema-qualified, but the indexed rel's name may be.
738 initStringInfo(&buf);
740 if (!colno)
741 appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
742 idxrec->indisunique ? "UNIQUE " : "",
743 quote_identifier(NameStr(idxrelrec->relname)),
744 generate_relation_name(indrelid, NIL),
745 quote_identifier(NameStr(amrec->amname)));
748 * Report the indexed attributes
750 sep = "";
751 for (keyno = 0; keyno < idxrec->indnatts; keyno++)
753 AttrNumber attnum = idxrec->indkey.values[keyno];
754 int16 opt = indoption->values[keyno];
756 if (!colno)
757 appendStringInfoString(&buf, sep);
758 sep = ", ";
760 if (attnum != 0)
762 /* Simple index column */
763 char *attname;
765 attname = get_relid_attribute_name(indrelid, attnum);
766 if (!colno || colno == keyno + 1)
767 appendStringInfoString(&buf, quote_identifier(attname));
768 keycoltype = get_atttype(indrelid, attnum);
770 else
772 /* expressional index */
773 Node *indexkey;
775 if (indexpr_item == NULL)
776 elog(ERROR, "too few entries in indexprs list");
777 indexkey = (Node *) lfirst(indexpr_item);
778 indexpr_item = lnext(indexpr_item);
779 /* Deparse */
780 str = deparse_expression_pretty(indexkey, context, false, false,
781 prettyFlags, 0);
782 if (!colno || colno == keyno + 1)
784 /* Need parens if it's not a bare function call */
785 if (indexkey && IsA(indexkey, FuncExpr) &&
786 ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
787 appendStringInfoString(&buf, str);
788 else
789 appendStringInfo(&buf, "(%s)", str);
791 keycoltype = exprType(indexkey);
794 /* Provide decoration only in the colno=0 case */
795 if (!colno)
797 /* Add the operator class name, if not default */
798 get_opclass_name(indclass->values[keyno], keycoltype, &buf);
800 /* Add options if relevant */
801 if (amrec->amcanorder)
803 /* if it supports sort ordering, report DESC and NULLS opts */
804 if (opt & INDOPTION_DESC)
806 appendStringInfo(&buf, " DESC");
807 /* NULLS FIRST is the default in this case */
808 if (!(opt & INDOPTION_NULLS_FIRST))
809 appendStringInfo(&buf, " NULLS LAST");
811 else
813 if (opt & INDOPTION_NULLS_FIRST)
814 appendStringInfo(&buf, " NULLS FIRST");
820 if (!colno)
822 appendStringInfoChar(&buf, ')');
825 * If it has options, append "WITH (options)"
827 str = flatten_reloptions(indexrelid);
828 if (str)
830 appendStringInfo(&buf, " WITH (%s)", str);
831 pfree(str);
835 * If it's in a nondefault tablespace, say so, but only if requested
837 if (showTblSpc)
839 Oid tblspc;
841 tblspc = get_rel_tablespace(indexrelid);
842 if (OidIsValid(tblspc))
843 appendStringInfo(&buf, " TABLESPACE %s",
844 quote_identifier(get_tablespace_name(tblspc)));
848 * If it's a partial index, decompile and append the predicate
850 if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))
852 Node *node;
853 Datum predDatum;
854 bool isnull;
855 char *predString;
857 /* Convert text string to node tree */
858 predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
859 Anum_pg_index_indpred, &isnull);
860 Assert(!isnull);
861 predString = TextDatumGetCString(predDatum);
862 node = (Node *) stringToNode(predString);
863 pfree(predString);
865 /* Deparse */
866 str = deparse_expression_pretty(node, context, false, false,
867 prettyFlags, 0);
868 appendStringInfo(&buf, " WHERE %s", str);
872 /* Clean up */
873 ReleaseSysCache(ht_idx);
874 ReleaseSysCache(ht_idxrel);
875 ReleaseSysCache(ht_am);
877 return buf.data;
882 * pg_get_constraintdef
884 * Returns the definition for the constraint, ie, everything that needs to
885 * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>".
887 Datum
888 pg_get_constraintdef(PG_FUNCTION_ARGS)
890 Oid constraintId = PG_GETARG_OID(0);
892 PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,
893 false, 0)));
896 Datum
897 pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
899 Oid constraintId = PG_GETARG_OID(0);
900 bool pretty = PG_GETARG_BOOL(1);
901 int prettyFlags;
903 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
904 PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,
905 false, prettyFlags)));
908 /* Internal version that returns a palloc'd C string */
909 char *
910 pg_get_constraintdef_string(Oid constraintId)
912 return pg_get_constraintdef_worker(constraintId, true, 0);
915 static char *
916 pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
917 int prettyFlags)
919 HeapTuple tup;
920 Form_pg_constraint conForm;
921 StringInfoData buf;
923 tup = SearchSysCache(CONSTROID,
924 ObjectIdGetDatum(constraintId),
925 0, 0, 0);
926 if (!HeapTupleIsValid(tup)) /* should not happen */
927 elog(ERROR, "cache lookup failed for constraint %u", constraintId);
928 conForm = (Form_pg_constraint) GETSTRUCT(tup);
930 initStringInfo(&buf);
932 if (fullCommand && OidIsValid(conForm->conrelid))
934 appendStringInfo(&buf, "ALTER TABLE ONLY %s ADD CONSTRAINT %s ",
935 generate_relation_name(conForm->conrelid, NIL),
936 quote_identifier(NameStr(conForm->conname)));
939 switch (conForm->contype)
941 case CONSTRAINT_FOREIGN:
943 Datum val;
944 bool isnull;
945 const char *string;
947 /* Start off the constraint definition */
948 appendStringInfo(&buf, "FOREIGN KEY (");
950 /* Fetch and build referencing-column list */
951 val = SysCacheGetAttr(CONSTROID, tup,
952 Anum_pg_constraint_conkey, &isnull);
953 if (isnull)
954 elog(ERROR, "null conkey for constraint %u",
955 constraintId);
957 decompile_column_index_array(val, conForm->conrelid, &buf);
959 /* add foreign relation name */
960 appendStringInfo(&buf, ") REFERENCES %s(",
961 generate_relation_name(conForm->confrelid,
962 NIL));
964 /* Fetch and build referenced-column list */
965 val = SysCacheGetAttr(CONSTROID, tup,
966 Anum_pg_constraint_confkey, &isnull);
967 if (isnull)
968 elog(ERROR, "null confkey for constraint %u",
969 constraintId);
971 decompile_column_index_array(val, conForm->confrelid, &buf);
973 appendStringInfo(&buf, ")");
975 /* Add match type */
976 switch (conForm->confmatchtype)
978 case FKCONSTR_MATCH_FULL:
979 string = " MATCH FULL";
980 break;
981 case FKCONSTR_MATCH_PARTIAL:
982 string = " MATCH PARTIAL";
983 break;
984 case FKCONSTR_MATCH_UNSPECIFIED:
985 string = "";
986 break;
987 default:
988 elog(ERROR, "unrecognized confmatchtype: %d",
989 conForm->confmatchtype);
990 string = ""; /* keep compiler quiet */
991 break;
993 appendStringInfoString(&buf, string);
995 /* Add ON UPDATE and ON DELETE clauses, if needed */
996 switch (conForm->confupdtype)
998 case FKCONSTR_ACTION_NOACTION:
999 string = NULL; /* suppress default */
1000 break;
1001 case FKCONSTR_ACTION_RESTRICT:
1002 string = "RESTRICT";
1003 break;
1004 case FKCONSTR_ACTION_CASCADE:
1005 string = "CASCADE";
1006 break;
1007 case FKCONSTR_ACTION_SETNULL:
1008 string = "SET NULL";
1009 break;
1010 case FKCONSTR_ACTION_SETDEFAULT:
1011 string = "SET DEFAULT";
1012 break;
1013 default:
1014 elog(ERROR, "unrecognized confupdtype: %d",
1015 conForm->confupdtype);
1016 string = NULL; /* keep compiler quiet */
1017 break;
1019 if (string)
1020 appendStringInfo(&buf, " ON UPDATE %s", string);
1022 switch (conForm->confdeltype)
1024 case FKCONSTR_ACTION_NOACTION:
1025 string = NULL; /* suppress default */
1026 break;
1027 case FKCONSTR_ACTION_RESTRICT:
1028 string = "RESTRICT";
1029 break;
1030 case FKCONSTR_ACTION_CASCADE:
1031 string = "CASCADE";
1032 break;
1033 case FKCONSTR_ACTION_SETNULL:
1034 string = "SET NULL";
1035 break;
1036 case FKCONSTR_ACTION_SETDEFAULT:
1037 string = "SET DEFAULT";
1038 break;
1039 default:
1040 elog(ERROR, "unrecognized confdeltype: %d",
1041 conForm->confdeltype);
1042 string = NULL; /* keep compiler quiet */
1043 break;
1045 if (string)
1046 appendStringInfo(&buf, " ON DELETE %s", string);
1048 if (conForm->condeferrable)
1049 appendStringInfo(&buf, " DEFERRABLE");
1050 if (conForm->condeferred)
1051 appendStringInfo(&buf, " INITIALLY DEFERRED");
1053 break;
1055 case CONSTRAINT_PRIMARY:
1056 case CONSTRAINT_UNIQUE:
1058 Datum val;
1059 bool isnull;
1060 Oid indexId;
1062 /* Start off the constraint definition */
1063 if (conForm->contype == CONSTRAINT_PRIMARY)
1064 appendStringInfo(&buf, "PRIMARY KEY (");
1065 else
1066 appendStringInfo(&buf, "UNIQUE (");
1068 /* Fetch and build target column list */
1069 val = SysCacheGetAttr(CONSTROID, tup,
1070 Anum_pg_constraint_conkey, &isnull);
1071 if (isnull)
1072 elog(ERROR, "null conkey for constraint %u",
1073 constraintId);
1075 decompile_column_index_array(val, conForm->conrelid, &buf);
1077 appendStringInfo(&buf, ")");
1079 indexId = get_constraint_index(constraintId);
1081 /* XXX why do we only print these bits if fullCommand? */
1082 if (fullCommand && OidIsValid(indexId))
1084 char *options = flatten_reloptions(indexId);
1085 Oid tblspc;
1087 if (options)
1089 appendStringInfo(&buf, " WITH (%s)", options);
1090 pfree(options);
1093 tblspc = get_rel_tablespace(indexId);
1094 if (OidIsValid(tblspc))
1095 appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
1096 quote_identifier(get_tablespace_name(tblspc)));
1099 break;
1101 case CONSTRAINT_CHECK:
1103 Datum val;
1104 bool isnull;
1105 char *conbin;
1106 char *consrc;
1107 Node *expr;
1108 List *context;
1110 /* Fetch constraint expression in parsetree form */
1111 val = SysCacheGetAttr(CONSTROID, tup,
1112 Anum_pg_constraint_conbin, &isnull);
1113 if (isnull)
1114 elog(ERROR, "null conbin for constraint %u",
1115 constraintId);
1117 conbin = TextDatumGetCString(val);
1118 expr = stringToNode(conbin);
1120 /* Set up deparsing context for Var nodes in constraint */
1121 if (conForm->conrelid != InvalidOid)
1123 /* relation constraint */
1124 context = deparse_context_for(get_rel_name(conForm->conrelid),
1125 conForm->conrelid);
1127 else
1129 /* domain constraint --- can't have Vars */
1130 context = NIL;
1133 consrc = deparse_expression_pretty(expr, context, false, false,
1134 prettyFlags, 0);
1137 * Now emit the constraint definition. There are cases where
1138 * the constraint expression will be fully parenthesized and
1139 * we don't need the outer parens ... but there are other
1140 * cases where we do need 'em. Be conservative for now.
1142 * Note that simply checking for leading '(' and trailing ')'
1143 * would NOT be good enough, consider "(x > 0) AND (y > 0)".
1145 appendStringInfo(&buf, "CHECK (%s)", consrc);
1147 break;
1149 default:
1150 elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);
1151 break;
1154 /* Cleanup */
1155 ReleaseSysCache(tup);
1157 return buf.data;
1162 * Convert an int16[] Datum into a comma-separated list of column names
1163 * for the indicated relation; append the list to buf.
1165 static void
1166 decompile_column_index_array(Datum column_index_array, Oid relId,
1167 StringInfo buf)
1169 Datum *keys;
1170 int nKeys;
1171 int j;
1173 /* Extract data from array of int16 */
1174 deconstruct_array(DatumGetArrayTypeP(column_index_array),
1175 INT2OID, 2, true, 's',
1176 &keys, NULL, &nKeys);
1178 for (j = 0; j < nKeys; j++)
1180 char *colName;
1182 colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j]));
1184 if (j == 0)
1185 appendStringInfoString(buf, quote_identifier(colName));
1186 else
1187 appendStringInfo(buf, ", %s", quote_identifier(colName));
1192 /* ----------
1193 * get_expr - Decompile an expression tree
1195 * Input: an expression tree in nodeToString form, and a relation OID
1197 * Output: reverse-listed expression
1199 * Currently, the expression can only refer to a single relation, namely
1200 * the one specified by the second parameter. This is sufficient for
1201 * partial indexes, column default expressions, etc. We also support
1202 * Var-free expressions, for which the OID can be InvalidOid.
1203 * ----------
1205 Datum
1206 pg_get_expr(PG_FUNCTION_ARGS)
1208 text *expr = PG_GETARG_TEXT_P(0);
1209 Oid relid = PG_GETARG_OID(1);
1210 char *relname;
1212 if (OidIsValid(relid))
1214 /* Get the name for the relation */
1215 relname = get_rel_name(relid);
1218 * If the OID isn't actually valid, don't throw an error, just return
1219 * NULL. This is a bit questionable, but it's what we've done
1220 * historically, and it can help avoid unwanted failures when
1221 * examining catalog entries for just-deleted relations.
1223 if (relname == NULL)
1224 PG_RETURN_NULL();
1226 else
1227 relname = NULL;
1229 PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, 0));
1232 Datum
1233 pg_get_expr_ext(PG_FUNCTION_ARGS)
1235 text *expr = PG_GETARG_TEXT_P(0);
1236 Oid relid = PG_GETARG_OID(1);
1237 bool pretty = PG_GETARG_BOOL(2);
1238 int prettyFlags;
1239 char *relname;
1241 prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
1243 if (OidIsValid(relid))
1245 /* Get the name for the relation */
1246 relname = get_rel_name(relid);
1247 /* See notes above */
1248 if (relname == NULL)
1249 PG_RETURN_NULL();
1251 else
1252 relname = NULL;
1254 PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
1257 static text *
1258 pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
1260 Node *node;
1261 List *context;
1262 char *exprstr;
1263 char *str;
1265 /* Convert input TEXT object to C string */
1266 exprstr = text_to_cstring(expr);
1268 /* Convert expression to node tree */
1269 node = (Node *) stringToNode(exprstr);
1271 pfree(exprstr);
1273 /* Prepare deparse context if needed */
1274 if (OidIsValid(relid))
1275 context = deparse_context_for(relname, relid);
1276 else
1277 context = NIL;
1279 /* Deparse */
1280 str = deparse_expression_pretty(node, context, false, false,
1281 prettyFlags, 0);
1283 return string_to_text(str);
1287 /* ----------
1288 * get_userbyid - Get a user name by roleid and
1289 * fallback to 'unknown (OID=n)'
1290 * ----------
1292 Datum
1293 pg_get_userbyid(PG_FUNCTION_ARGS)
1295 Oid roleid = PG_GETARG_OID(0);
1296 Name result;
1297 HeapTuple roletup;
1298 Form_pg_authid role_rec;
1301 * Allocate space for the result
1303 result = (Name) palloc(NAMEDATALEN);
1304 memset(NameStr(*result), 0, NAMEDATALEN);
1307 * Get the pg_authid entry and print the result
1309 roletup = SearchSysCache(AUTHOID,
1310 ObjectIdGetDatum(roleid),
1311 0, 0, 0);
1312 if (HeapTupleIsValid(roletup))
1314 role_rec = (Form_pg_authid) GETSTRUCT(roletup);
1315 StrNCpy(NameStr(*result), NameStr(role_rec->rolname), NAMEDATALEN);
1316 ReleaseSysCache(roletup);
1318 else
1319 sprintf(NameStr(*result), "unknown (OID=%u)", roleid);
1321 PG_RETURN_NAME(result);
1326 * pg_get_serial_sequence
1327 * Get the name of the sequence used by a serial column,
1328 * formatted suitably for passing to setval, nextval or currval.
1329 * First parameter is not treated as double-quoted, second parameter
1330 * is --- see documentation for reason.
1332 Datum
1333 pg_get_serial_sequence(PG_FUNCTION_ARGS)
1335 text *tablename = PG_GETARG_TEXT_P(0);
1336 text *columnname = PG_GETARG_TEXT_PP(1);
1337 RangeVar *tablerv;
1338 Oid tableOid;
1339 char *column;
1340 AttrNumber attnum;
1341 Oid sequenceId = InvalidOid;
1342 Relation depRel;
1343 ScanKeyData key[3];
1344 SysScanDesc scan;
1345 HeapTuple tup;
1347 /* Get the OID of the table */
1348 tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1349 tableOid = RangeVarGetRelid(tablerv, false);
1351 /* Get the number of the column */
1352 column = text_to_cstring(columnname);
1354 attnum = get_attnum(tableOid, column);
1355 if (attnum == InvalidAttrNumber)
1356 ereport(ERROR,
1357 (errcode(ERRCODE_UNDEFINED_COLUMN),
1358 errmsg("column \"%s\" of relation \"%s\" does not exist",
1359 column, tablerv->relname)));
1361 /* Search the dependency table for the dependent sequence */
1362 depRel = heap_open(DependRelationId, AccessShareLock);
1364 ScanKeyInit(&key[0],
1365 Anum_pg_depend_refclassid,
1366 BTEqualStrategyNumber, F_OIDEQ,
1367 ObjectIdGetDatum(RelationRelationId));
1368 ScanKeyInit(&key[1],
1369 Anum_pg_depend_refobjid,
1370 BTEqualStrategyNumber, F_OIDEQ,
1371 ObjectIdGetDatum(tableOid));
1372 ScanKeyInit(&key[2],
1373 Anum_pg_depend_refobjsubid,
1374 BTEqualStrategyNumber, F_INT4EQ,
1375 Int32GetDatum(attnum));
1377 scan = systable_beginscan(depRel, DependReferenceIndexId, true,
1378 SnapshotNow, 3, key);
1380 while (HeapTupleIsValid(tup = systable_getnext(scan)))
1382 Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
1385 * We assume any auto dependency of a sequence on a column must be
1386 * what we are looking for. (We need the relkind test because indexes
1387 * can also have auto dependencies on columns.)
1389 if (deprec->classid == RelationRelationId &&
1390 deprec->objsubid == 0 &&
1391 deprec->deptype == DEPENDENCY_AUTO &&
1392 get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
1394 sequenceId = deprec->objid;
1395 break;
1399 systable_endscan(scan);
1400 heap_close(depRel, AccessShareLock);
1402 if (OidIsValid(sequenceId))
1404 HeapTuple classtup;
1405 Form_pg_class classtuple;
1406 char *nspname;
1407 char *result;
1409 /* Get the sequence's pg_class entry */
1410 classtup = SearchSysCache(RELOID,
1411 ObjectIdGetDatum(sequenceId),
1412 0, 0, 0);
1413 if (!HeapTupleIsValid(classtup))
1414 elog(ERROR, "cache lookup failed for relation %u", sequenceId);
1415 classtuple = (Form_pg_class) GETSTRUCT(classtup);
1417 /* Get the namespace */
1418 nspname = get_namespace_name(classtuple->relnamespace);
1419 if (!nspname)
1420 elog(ERROR, "cache lookup failed for namespace %u",
1421 classtuple->relnamespace);
1423 /* And construct the result string */
1424 result = quote_qualified_identifier(nspname,
1425 NameStr(classtuple->relname));
1427 ReleaseSysCache(classtup);
1429 PG_RETURN_TEXT_P(string_to_text(result));
1432 PG_RETURN_NULL();
1437 * pg_get_functiondef
1438 * Returns the complete "CREATE OR REPLACE FUNCTION ..." statement for
1439 * the specified function.
1441 Datum
1442 pg_get_functiondef(PG_FUNCTION_ARGS)
1444 Oid funcid = PG_GETARG_OID(0);
1445 StringInfoData buf;
1446 StringInfoData dq;
1447 HeapTuple proctup;
1448 HeapTuple langtup;
1449 Form_pg_proc proc;
1450 Form_pg_language lang;
1451 Datum tmp;
1452 bool isnull;
1453 const char *prosrc;
1454 const char *name;
1455 const char *nsp;
1456 float4 procost;
1457 int oldlen;
1459 initStringInfo(&buf);
1461 /* Look up the function */
1462 proctup = SearchSysCache(PROCOID,
1463 ObjectIdGetDatum(funcid),
1464 0, 0, 0);
1465 if (!HeapTupleIsValid(proctup))
1466 elog(ERROR, "cache lookup failed for function %u", funcid);
1467 proc = (Form_pg_proc) GETSTRUCT(proctup);
1468 name = NameStr(proc->proname);
1470 if (proc->proisagg)
1471 ereport(ERROR,
1472 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1473 errmsg("\"%s\" is an aggregate function", name)));
1475 /* Need its pg_language tuple for the language name */
1476 langtup = SearchSysCache(LANGOID,
1477 ObjectIdGetDatum(proc->prolang),
1478 0, 0, 0);
1479 if (!HeapTupleIsValid(langtup))
1480 elog(ERROR, "cache lookup failed for language %u", proc->prolang);
1481 lang = (Form_pg_language) GETSTRUCT(langtup);
1484 * We always qualify the function name, to ensure the right function
1485 * gets replaced.
1487 nsp = get_namespace_name(proc->pronamespace);
1488 appendStringInfo(&buf, "CREATE OR REPLACE FUNCTION %s(",
1489 quote_qualified_identifier(nsp, name));
1490 (void) print_function_arguments(&buf, proctup, false, true);
1491 appendStringInfoString(&buf, ")\n RETURNS ");
1492 print_function_rettype(&buf, proctup);
1493 appendStringInfo(&buf, "\n LANGUAGE %s\n",
1494 quote_identifier(NameStr(lang->lanname)));
1496 /* Emit some miscellaneous options on one line */
1497 oldlen = buf.len;
1499 if (proc->proiswindow)
1500 appendStringInfoString(&buf, " WINDOW");
1501 switch (proc->provolatile)
1503 case PROVOLATILE_IMMUTABLE:
1504 appendStringInfoString(&buf, " IMMUTABLE");
1505 break;
1506 case PROVOLATILE_STABLE:
1507 appendStringInfoString(&buf, " STABLE");
1508 break;
1509 case PROVOLATILE_VOLATILE:
1510 break;
1512 if (proc->proisstrict)
1513 appendStringInfoString(&buf, " STRICT");
1514 if (proc->prosecdef)
1515 appendStringInfoString(&buf, " SECURITY DEFINER");
1517 /* This code for the default cost and rows should match functioncmds.c */
1518 if (proc->prolang == INTERNALlanguageId ||
1519 proc->prolang == ClanguageId)
1520 procost = 1;
1521 else
1522 procost = 100;
1523 if (proc->procost != procost)
1524 appendStringInfo(&buf, " COST %g", proc->procost);
1526 if (proc->prorows > 0 && proc->prorows != 1000)
1527 appendStringInfo(&buf, " ROWS %g", proc->prorows);
1529 if (oldlen != buf.len)
1530 appendStringInfoChar(&buf, '\n');
1532 /* Emit any proconfig options, one per line */
1533 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_proconfig, &isnull);
1534 if (!isnull)
1536 ArrayType *a = DatumGetArrayTypeP(tmp);
1537 int i;
1539 Assert(ARR_ELEMTYPE(a) == TEXTOID);
1540 Assert(ARR_NDIM(a) == 1);
1541 Assert(ARR_LBOUND(a)[0] == 1);
1543 for (i = 1; i <= ARR_DIMS(a)[0]; i++)
1545 Datum d;
1547 d = array_ref(a, 1, &i,
1548 -1 /* varlenarray */ ,
1549 -1 /* TEXT's typlen */ ,
1550 false /* TEXT's typbyval */ ,
1551 'i' /* TEXT's typalign */ ,
1552 &isnull);
1553 if (!isnull)
1555 char *configitem = TextDatumGetCString(d);
1556 char *pos;
1558 pos = strchr(configitem, '=');
1559 if (pos == NULL)
1560 continue;
1561 *pos++ = '\0';
1563 appendStringInfo(&buf, " SET %s TO ",
1564 quote_identifier(configitem));
1567 * Some GUC variable names are 'LIST' type and hence must not
1568 * be quoted.
1570 if (pg_strcasecmp(configitem, "DateStyle") == 0
1571 || pg_strcasecmp(configitem, "search_path") == 0)
1572 appendStringInfoString(&buf, pos);
1573 else
1574 simple_quote_literal(&buf, pos);
1575 appendStringInfoChar(&buf, '\n');
1580 /* And finally the function definition ... */
1581 appendStringInfoString(&buf, "AS ");
1583 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull);
1584 if (!isnull)
1586 simple_quote_literal(&buf, TextDatumGetCString(tmp));
1587 appendStringInfoString(&buf, ", "); /* assume prosrc isn't null */
1590 tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosrc, &isnull);
1591 if (isnull)
1592 elog(ERROR, "null prosrc");
1593 prosrc = TextDatumGetCString(tmp);
1596 * We always use dollar quoting. Figure out a suitable delimiter.
1598 * Since the user is likely to be editing the function body string,
1599 * we shouldn't use a short delimiter that he might easily create a
1600 * conflict with. Hence prefer "$function$", but extend if needed.
1602 initStringInfo(&dq);
1603 appendStringInfoString(&dq, "$function");
1604 while (strstr(prosrc, dq.data) != NULL)
1605 appendStringInfoChar(&dq, 'x');
1606 appendStringInfoChar(&dq, '$');
1608 appendStringInfoString(&buf, dq.data);
1609 appendStringInfoString(&buf, prosrc);
1610 appendStringInfoString(&buf, dq.data);
1612 appendStringInfoString(&buf, "\n");
1614 ReleaseSysCache(langtup);
1615 ReleaseSysCache(proctup);
1617 PG_RETURN_TEXT_P(string_to_text(buf.data));
1621 * pg_get_function_arguments
1622 * Get a nicely-formatted list of arguments for a function.
1623 * This is everything that would go between the parentheses in
1624 * CREATE FUNCTION.
1626 Datum
1627 pg_get_function_arguments(PG_FUNCTION_ARGS)
1629 Oid funcid = PG_GETARG_OID(0);
1630 StringInfoData buf;
1631 HeapTuple proctup;
1633 initStringInfo(&buf);
1635 proctup = SearchSysCache(PROCOID,
1636 ObjectIdGetDatum(funcid),
1637 0, 0, 0);
1638 if (!HeapTupleIsValid(proctup))
1639 elog(ERROR, "cache lookup failed for function %u", funcid);
1641 (void) print_function_arguments(&buf, proctup, false, true);
1643 ReleaseSysCache(proctup);
1645 PG_RETURN_TEXT_P(string_to_text(buf.data));
1649 * pg_get_function_identity_arguments
1650 * Get a formatted list of arguments for a function.
1651 * This is everything that would go between the parentheses in
1652 * ALTER FUNCTION, etc. In particular, don't print defaults.
1654 Datum
1655 pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
1657 Oid funcid = PG_GETARG_OID(0);
1658 StringInfoData buf;
1659 HeapTuple proctup;
1661 initStringInfo(&buf);
1663 proctup = SearchSysCache(PROCOID,
1664 ObjectIdGetDatum(funcid),
1665 0, 0, 0);
1666 if (!HeapTupleIsValid(proctup))
1667 elog(ERROR, "cache lookup failed for function %u", funcid);
1669 (void) print_function_arguments(&buf, proctup, false, false);
1671 ReleaseSysCache(proctup);
1673 PG_RETURN_TEXT_P(string_to_text(buf.data));
1677 * pg_get_function_result
1678 * Get a nicely-formatted version of the result type of a function.
1679 * This is what would appear after RETURNS in CREATE FUNCTION.
1681 Datum
1682 pg_get_function_result(PG_FUNCTION_ARGS)
1684 Oid funcid = PG_GETARG_OID(0);
1685 StringInfoData buf;
1686 HeapTuple proctup;
1688 initStringInfo(&buf);
1690 proctup = SearchSysCache(PROCOID,
1691 ObjectIdGetDatum(funcid),
1692 0, 0, 0);
1693 if (!HeapTupleIsValid(proctup))
1694 elog(ERROR, "cache lookup failed for function %u", funcid);
1696 print_function_rettype(&buf, proctup);
1698 ReleaseSysCache(proctup);
1700 PG_RETURN_TEXT_P(string_to_text(buf.data));
1704 * Guts of pg_get_function_result: append the function's return type
1705 * to the specified buffer.
1707 static void
1708 print_function_rettype(StringInfo buf, HeapTuple proctup)
1710 Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
1711 int ntabargs = 0;
1712 StringInfoData rbuf;
1714 initStringInfo(&rbuf);
1716 if (proc->proretset)
1718 /* It might be a table function; try to print the arguments */
1719 appendStringInfoString(&rbuf, "TABLE(");
1720 ntabargs = print_function_arguments(&rbuf, proctup, true, false);
1721 if (ntabargs > 0)
1722 appendStringInfoString(&rbuf, ")");
1723 else
1724 resetStringInfo(&rbuf);
1727 if (ntabargs == 0)
1729 /* Not a table function, so do the normal thing */
1730 if (proc->proretset)
1731 appendStringInfoString(&rbuf, "SETOF ");
1732 appendStringInfoString(&rbuf, format_type_be(proc->prorettype));
1735 appendStringInfoString(buf, rbuf.data);
1739 * Common code for pg_get_function_arguments and pg_get_function_result:
1740 * append the desired subset of arguments to buf. We print only TABLE
1741 * arguments when print_table_args is true, and all the others when it's false.
1742 * We print argument defaults only if print_defaults is true.
1743 * Function return value is the number of arguments printed.
1745 static int
1746 print_function_arguments(StringInfo buf, HeapTuple proctup,
1747 bool print_table_args, bool print_defaults)
1749 Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup);
1750 int numargs;
1751 Oid *argtypes;
1752 char **argnames;
1753 char *argmodes;
1754 int argsprinted;
1755 int inputargno;
1756 int nlackdefaults;
1757 ListCell *nextargdefault = NULL;
1758 int i;
1760 numargs = get_func_arg_info(proctup,
1761 &argtypes, &argnames, &argmodes);
1763 nlackdefaults = numargs;
1764 if (print_defaults && proc->pronargdefaults > 0)
1766 Datum proargdefaults;
1767 bool isnull;
1769 proargdefaults = SysCacheGetAttr(PROCOID, proctup,
1770 Anum_pg_proc_proargdefaults,
1771 &isnull);
1772 if (!isnull)
1774 char *str;
1775 List *argdefaults;
1777 str = TextDatumGetCString(proargdefaults);
1778 argdefaults = (List *) stringToNode(str);
1779 Assert(IsA(argdefaults, List));
1780 pfree(str);
1781 nextargdefault = list_head(argdefaults);
1782 /* nlackdefaults counts only *input* arguments lacking defaults */
1783 nlackdefaults = proc->pronargs - list_length(argdefaults);
1787 argsprinted = 0;
1788 inputargno = 0;
1789 for (i = 0; i < numargs; i++)
1791 Oid argtype = argtypes[i];
1792 char *argname = argnames ? argnames[i] : NULL;
1793 char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
1794 const char *modename;
1795 bool isinput;
1797 switch (argmode)
1799 case PROARGMODE_IN:
1800 modename = "";
1801 isinput = true;
1802 break;
1803 case PROARGMODE_INOUT:
1804 modename = "INOUT ";
1805 isinput = true;
1806 break;
1807 case PROARGMODE_OUT:
1808 modename = "OUT ";
1809 isinput = false;
1810 break;
1811 case PROARGMODE_VARIADIC:
1812 modename = "VARIADIC ";
1813 isinput = true;
1814 break;
1815 case PROARGMODE_TABLE:
1816 modename = "";
1817 isinput = false;
1818 break;
1819 default:
1820 elog(ERROR, "invalid parameter mode '%c'", argmode);
1821 modename = NULL; /* keep compiler quiet */
1822 isinput = false;
1823 break;
1825 if (isinput)
1826 inputargno++; /* this is a 1-based counter */
1828 if (print_table_args != (argmode == PROARGMODE_TABLE))
1829 continue;
1831 if (argsprinted)
1832 appendStringInfoString(buf, ", ");
1833 appendStringInfoString(buf, modename);
1834 if (argname && argname[0])
1835 appendStringInfo(buf, "%s ", quote_identifier(argname));
1836 appendStringInfoString(buf, format_type_be(argtype));
1837 if (print_defaults && isinput && inputargno > nlackdefaults)
1839 Node *expr;
1841 Assert(nextargdefault != NULL);
1842 expr = (Node *) lfirst(nextargdefault);
1843 nextargdefault = lnext(nextargdefault);
1845 appendStringInfo(buf, " DEFAULT %s",
1846 deparse_expression(expr, NIL, false, false));
1848 argsprinted++;
1851 return argsprinted;
1856 * deparse_expression - General utility for deparsing expressions
1858 * calls deparse_expression_pretty with all prettyPrinting disabled
1860 char *
1861 deparse_expression(Node *expr, List *dpcontext,
1862 bool forceprefix, bool showimplicit)
1864 return deparse_expression_pretty(expr, dpcontext, forceprefix,
1865 showimplicit, 0, 0);
1868 /* ----------
1869 * deparse_expression_pretty - General utility for deparsing expressions
1871 * expr is the node tree to be deparsed. It must be a transformed expression
1872 * tree (ie, not the raw output of gram.y).
1874 * dpcontext is a list of deparse_namespace nodes representing the context
1875 * for interpreting Vars in the node tree.
1877 * forceprefix is TRUE to force all Vars to be prefixed with their table names.
1879 * showimplicit is TRUE to force all implicit casts to be shown explicitly.
1881 * tries to pretty up the output according to prettyFlags and startIndent.
1883 * The result is a palloc'd string.
1884 * ----------
1886 static char *
1887 deparse_expression_pretty(Node *expr, List *dpcontext,
1888 bool forceprefix, bool showimplicit,
1889 int prettyFlags, int startIndent)
1891 StringInfoData buf;
1892 deparse_context context;
1894 initStringInfo(&buf);
1895 context.buf = &buf;
1896 context.namespaces = dpcontext;
1897 context.windowClause = NIL;
1898 context.windowTList = NIL;
1899 context.varprefix = forceprefix;
1900 context.prettyFlags = prettyFlags;
1901 context.indentLevel = startIndent;
1903 get_rule_expr(expr, &context, showimplicit);
1905 return buf.data;
1908 /* ----------
1909 * deparse_context_for - Build deparse context for a single relation
1911 * Given the reference name (alias) and OID of a relation, build deparsing
1912 * context for an expression referencing only that relation (as varno 1,
1913 * varlevelsup 0). This is sufficient for many uses of deparse_expression.
1914 * ----------
1916 List *
1917 deparse_context_for(const char *aliasname, Oid relid)
1919 deparse_namespace *dpns;
1920 RangeTblEntry *rte;
1922 dpns = (deparse_namespace *) palloc(sizeof(deparse_namespace));
1924 /* Build a minimal RTE for the rel */
1925 rte = makeNode(RangeTblEntry);
1926 rte->rtekind = RTE_RELATION;
1927 rte->relid = relid;
1928 rte->eref = makeAlias(aliasname, NIL);
1929 rte->inh = false;
1930 rte->inFromCl = true;
1932 /* Build one-element rtable */
1933 dpns->rtable = list_make1(rte);
1934 dpns->ctes = NIL;
1935 dpns->subplans = NIL;
1936 dpns->outer_plan = dpns->inner_plan = NULL;
1938 /* Return a one-deep namespace stack */
1939 return list_make1(dpns);
1943 * deparse_context_for_plan - Build deparse context for a plan node
1945 * When deparsing an expression in a Plan tree, we might have to resolve
1946 * OUTER or INNER references. To do this, the caller must provide the
1947 * parent Plan node. In the normal case of a join plan node, OUTER and
1948 * INNER references can be resolved by drilling down into the left and
1949 * right child plans. A special case is that a nestloop inner indexscan
1950 * might have OUTER Vars, but the outer side of the join is not a child
1951 * plan node. To handle such cases the outer plan node must be passed
1952 * separately. (Pass NULL for outer_plan otherwise.)
1954 * Note: plan and outer_plan really ought to be declared as "Plan *", but
1955 * we use "Node *" to avoid having to include plannodes.h in builtins.h.
1957 * The plan's rangetable list must also be passed. We actually prefer to use
1958 * the rangetable to resolve simple Vars, but the plan inputs are necessary
1959 * for Vars that reference expressions computed in subplan target lists.
1961 * We also need the list of subplans associated with the Plan tree; this
1962 * is for resolving references to CTE subplans.
1964 List *
1965 deparse_context_for_plan(Node *plan, Node *outer_plan,
1966 List *rtable, List *subplans)
1968 deparse_namespace *dpns;
1970 dpns = (deparse_namespace *) palloc(sizeof(deparse_namespace));
1972 dpns->rtable = rtable;
1973 dpns->ctes = NIL;
1974 dpns->subplans = subplans;
1977 * Set up outer_plan and inner_plan from the Plan node (this includes
1978 * various special cases for particular Plan types).
1980 push_plan(dpns, (Plan *) plan);
1983 * If outer_plan is given, that overrides whatever we got from the plan.
1985 if (outer_plan)
1986 dpns->outer_plan = (Plan *) outer_plan;
1988 /* Return a one-deep namespace stack */
1989 return list_make1(dpns);
1992 /* ----------
1993 * make_ruledef - reconstruct the CREATE RULE command
1994 * for a given pg_rewrite tuple
1995 * ----------
1997 static void
1998 make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
1999 int prettyFlags)
2001 char *rulename;
2002 char ev_type;
2003 Oid ev_class;
2004 int2 ev_attr;
2005 bool is_instead;
2006 char *ev_qual;
2007 char *ev_action;
2008 List *actions = NIL;
2009 int fno;
2010 Datum dat;
2011 bool isnull;
2014 * Get the attribute values from the rules tuple
2016 fno = SPI_fnumber(rulettc, "rulename");
2017 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2018 Assert(!isnull);
2019 rulename = NameStr(*(DatumGetName(dat)));
2021 fno = SPI_fnumber(rulettc, "ev_type");
2022 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2023 Assert(!isnull);
2024 ev_type = DatumGetChar(dat);
2026 fno = SPI_fnumber(rulettc, "ev_class");
2027 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2028 Assert(!isnull);
2029 ev_class = DatumGetObjectId(dat);
2031 fno = SPI_fnumber(rulettc, "ev_attr");
2032 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2033 Assert(!isnull);
2034 ev_attr = DatumGetInt16(dat);
2036 fno = SPI_fnumber(rulettc, "is_instead");
2037 dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
2038 Assert(!isnull);
2039 is_instead = DatumGetBool(dat);
2041 /* these could be nulls */
2042 fno = SPI_fnumber(rulettc, "ev_qual");
2043 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
2045 fno = SPI_fnumber(rulettc, "ev_action");
2046 ev_action = SPI_getvalue(ruletup, rulettc, fno);
2047 if (ev_action != NULL)
2048 actions = (List *) stringToNode(ev_action);
2051 * Build the rules definition text
2053 appendStringInfo(buf, "CREATE RULE %s AS",
2054 quote_identifier(rulename));
2056 if (prettyFlags & PRETTYFLAG_INDENT)
2057 appendStringInfoString(buf, "\n ON ");
2058 else
2059 appendStringInfoString(buf, " ON ");
2061 /* The event the rule is fired for */
2062 switch (ev_type)
2064 case '1':
2065 appendStringInfo(buf, "SELECT");
2066 break;
2068 case '2':
2069 appendStringInfo(buf, "UPDATE");
2070 break;
2072 case '3':
2073 appendStringInfo(buf, "INSERT");
2074 break;
2076 case '4':
2077 appendStringInfo(buf, "DELETE");
2078 break;
2080 default:
2081 ereport(ERROR,
2082 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2083 errmsg("rule \"%s\" has unsupported event type %d",
2084 rulename, ev_type)));
2085 break;
2088 /* The relation the rule is fired on */
2089 appendStringInfo(buf, " TO %s", generate_relation_name(ev_class, NIL));
2090 if (ev_attr > 0)
2091 appendStringInfo(buf, ".%s",
2092 quote_identifier(get_relid_attribute_name(ev_class,
2093 ev_attr)));
2095 /* If the rule has an event qualification, add it */
2096 if (ev_qual == NULL)
2097 ev_qual = "";
2098 if (strlen(ev_qual) > 0 && strcmp(ev_qual, "<>") != 0)
2100 Node *qual;
2101 Query *query;
2102 deparse_context context;
2103 deparse_namespace dpns;
2105 if (prettyFlags & PRETTYFLAG_INDENT)
2106 appendStringInfoString(buf, "\n ");
2107 appendStringInfo(buf, " WHERE ");
2109 qual = stringToNode(ev_qual);
2112 * We need to make a context for recognizing any Vars in the qual
2113 * (which can only be references to OLD and NEW). Use the rtable of
2114 * the first query in the action list for this purpose.
2116 query = (Query *) linitial(actions);
2119 * If the action is INSERT...SELECT, OLD/NEW have been pushed down
2120 * into the SELECT, and that's what we need to look at. (Ugly kluge
2121 * ... try to fix this when we redesign querytrees.)
2123 query = getInsertSelectQuery(query, NULL);
2125 /* Must acquire locks right away; see notes in get_query_def() */
2126 AcquireRewriteLocks(query);
2128 context.buf = buf;
2129 context.namespaces = list_make1(&dpns);
2130 context.windowClause = NIL;
2131 context.windowTList = NIL;
2132 context.varprefix = (list_length(query->rtable) != 1);
2133 context.prettyFlags = prettyFlags;
2134 context.indentLevel = PRETTYINDENT_STD;
2135 dpns.rtable = query->rtable;
2136 dpns.ctes = query->cteList;
2137 dpns.subplans = NIL;
2138 dpns.outer_plan = dpns.inner_plan = NULL;
2140 get_rule_expr(qual, &context, false);
2143 appendStringInfo(buf, " DO ");
2145 /* The INSTEAD keyword (if so) */
2146 if (is_instead)
2147 appendStringInfo(buf, "INSTEAD ");
2149 /* Finally the rules actions */
2150 if (list_length(actions) > 1)
2152 ListCell *action;
2153 Query *query;
2155 appendStringInfo(buf, "(");
2156 foreach(action, actions)
2158 query = (Query *) lfirst(action);
2159 get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
2160 if (prettyFlags)
2161 appendStringInfo(buf, ";\n");
2162 else
2163 appendStringInfo(buf, "; ");
2165 appendStringInfo(buf, ");");
2167 else if (list_length(actions) == 0)
2169 appendStringInfo(buf, "NOTHING;");
2171 else
2173 Query *query;
2175 query = (Query *) linitial(actions);
2176 get_query_def(query, buf, NIL, NULL, prettyFlags, 0);
2177 appendStringInfo(buf, ";");
2182 /* ----------
2183 * make_viewdef - reconstruct the SELECT part of a
2184 * view rewrite rule
2185 * ----------
2187 static void
2188 make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
2189 int prettyFlags)
2191 Query *query;
2192 char ev_type;
2193 Oid ev_class;
2194 int2 ev_attr;
2195 bool is_instead;
2196 char *ev_qual;
2197 char *ev_action;
2198 List *actions = NIL;
2199 Relation ev_relation;
2200 int fno;
2201 bool isnull;
2204 * Get the attribute values from the rules tuple
2206 fno = SPI_fnumber(rulettc, "ev_type");
2207 ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2209 fno = SPI_fnumber(rulettc, "ev_class");
2210 ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2212 fno = SPI_fnumber(rulettc, "ev_attr");
2213 ev_attr = (int2) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2215 fno = SPI_fnumber(rulettc, "is_instead");
2216 is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);
2218 fno = SPI_fnumber(rulettc, "ev_qual");
2219 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
2221 fno = SPI_fnumber(rulettc, "ev_action");
2222 ev_action = SPI_getvalue(ruletup, rulettc, fno);
2223 if (ev_action != NULL)
2224 actions = (List *) stringToNode(ev_action);
2226 if (list_length(actions) != 1)
2228 appendStringInfo(buf, "Not a view");
2229 return;
2232 query = (Query *) linitial(actions);
2234 if (ev_type != '1' || ev_attr >= 0 || !is_instead ||
2235 strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)
2237 appendStringInfo(buf, "Not a view");
2238 return;
2241 ev_relation = heap_open(ev_class, AccessShareLock);
2243 get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),
2244 prettyFlags, 0);
2245 appendStringInfo(buf, ";");
2247 heap_close(ev_relation, AccessShareLock);
2251 /* ----------
2252 * get_query_def - Parse back one query parsetree
2254 * If resultDesc is not NULL, then it is the output tuple descriptor for
2255 * the view represented by a SELECT query.
2256 * ----------
2258 static void
2259 get_query_def(Query *query, StringInfo buf, List *parentnamespace,
2260 TupleDesc resultDesc, int prettyFlags, int startIndent)
2262 deparse_context context;
2263 deparse_namespace dpns;
2266 * Before we begin to examine the query, acquire locks on referenced
2267 * relations, and fix up deleted columns in JOIN RTEs. This ensures
2268 * consistent results. Note we assume it's OK to scribble on the passed
2269 * querytree!
2271 AcquireRewriteLocks(query);
2273 context.buf = buf;
2274 context.namespaces = lcons(&dpns, list_copy(parentnamespace));
2275 context.windowClause = NIL;
2276 context.windowTList = NIL;
2277 context.varprefix = (parentnamespace != NIL ||
2278 list_length(query->rtable) != 1);
2279 context.prettyFlags = prettyFlags;
2280 context.indentLevel = startIndent;
2282 dpns.rtable = query->rtable;
2283 dpns.ctes = query->cteList;
2284 dpns.subplans = NIL;
2285 dpns.outer_plan = dpns.inner_plan = NULL;
2287 switch (query->commandType)
2289 case CMD_SELECT:
2290 get_select_query_def(query, &context, resultDesc);
2291 break;
2293 case CMD_UPDATE:
2294 get_update_query_def(query, &context);
2295 break;
2297 case CMD_INSERT:
2298 get_insert_query_def(query, &context);
2299 break;
2301 case CMD_DELETE:
2302 get_delete_query_def(query, &context);
2303 break;
2305 case CMD_NOTHING:
2306 appendStringInfo(buf, "NOTHING");
2307 break;
2309 case CMD_UTILITY:
2310 get_utility_query_def(query, &context);
2311 break;
2313 default:
2314 elog(ERROR, "unrecognized query command type: %d",
2315 query->commandType);
2316 break;
2320 /* ----------
2321 * get_values_def - Parse back a VALUES list
2322 * ----------
2324 static void
2325 get_values_def(List *values_lists, deparse_context *context)
2327 StringInfo buf = context->buf;
2328 bool first_list = true;
2329 ListCell *vtl;
2331 appendStringInfoString(buf, "VALUES ");
2333 foreach(vtl, values_lists)
2335 List *sublist = (List *) lfirst(vtl);
2336 bool first_col = true;
2337 ListCell *lc;
2339 if (first_list)
2340 first_list = false;
2341 else
2342 appendStringInfoString(buf, ", ");
2344 appendStringInfoChar(buf, '(');
2345 foreach(lc, sublist)
2347 Node *col = (Node *) lfirst(lc);
2349 if (first_col)
2350 first_col = false;
2351 else
2352 appendStringInfoChar(buf, ',');
2355 * Strip any top-level nodes representing indirection assignments,
2356 * then print the result.
2358 get_rule_expr(processIndirection(col, context, false),
2359 context, false);
2361 appendStringInfoChar(buf, ')');
2365 /* ----------
2366 * get_with_clause - Parse back a WITH clause
2367 * ----------
2369 static void
2370 get_with_clause(Query *query, deparse_context *context)
2372 StringInfo buf = context->buf;
2373 const char *sep;
2374 ListCell *l;
2376 if (query->cteList == NIL)
2377 return;
2379 if (PRETTY_INDENT(context))
2381 context->indentLevel += PRETTYINDENT_STD;
2382 appendStringInfoChar(buf, ' ');
2385 if (query->hasRecursive)
2386 sep = "WITH RECURSIVE ";
2387 else
2388 sep = "WITH ";
2389 foreach(l, query->cteList)
2391 CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
2393 appendStringInfoString(buf, sep);
2394 appendStringInfoString(buf, quote_identifier(cte->ctename));
2395 if (cte->aliascolnames)
2397 bool first = true;
2398 ListCell *col;
2400 appendStringInfoChar(buf, '(');
2401 foreach(col, cte->aliascolnames)
2403 if (first)
2404 first = false;
2405 else
2406 appendStringInfoString(buf, ", ");
2407 appendStringInfoString(buf,
2408 quote_identifier(strVal(lfirst(col))));
2410 appendStringInfoChar(buf, ')');
2412 appendStringInfoString(buf, " AS (");
2413 if (PRETTY_INDENT(context))
2414 appendContextKeyword(context, "", 0, 0, 0);
2415 get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
2416 context->prettyFlags, context->indentLevel);
2417 if (PRETTY_INDENT(context))
2418 appendContextKeyword(context, "", 0, 0, 0);
2419 appendStringInfoChar(buf, ')');
2420 sep = ", ";
2423 if (PRETTY_INDENT(context))
2425 context->indentLevel -= PRETTYINDENT_STD;
2426 appendContextKeyword(context, "", 0, 0, 0);
2428 else
2429 appendStringInfoChar(buf, ' ');
2432 /* ----------
2433 * get_select_query_def - Parse back a SELECT parsetree
2434 * ----------
2436 static void
2437 get_select_query_def(Query *query, deparse_context *context,
2438 TupleDesc resultDesc)
2440 StringInfo buf = context->buf;
2441 List *save_windowclause;
2442 List *save_windowtlist;
2443 bool force_colno;
2444 ListCell *l;
2446 /* Insert the WITH clause if given */
2447 get_with_clause(query, context);
2449 /* Set up context for possible window functions */
2450 save_windowclause = context->windowClause;
2451 context->windowClause = query->windowClause;
2452 save_windowtlist = context->windowTList;
2453 context->windowTList = query->targetList;
2456 * If the Query node has a setOperations tree, then it's the top level of
2457 * a UNION/INTERSECT/EXCEPT query; only the WITH, ORDER BY and LIMIT
2458 * fields are interesting in the top query itself.
2460 if (query->setOperations)
2462 get_setop_query(query->setOperations, query, context, resultDesc);
2463 /* ORDER BY clauses must be simple in this case */
2464 force_colno = true;
2466 else
2468 get_basic_select_query(query, context, resultDesc);
2469 force_colno = false;
2472 /* Add the ORDER BY clause if given */
2473 if (query->sortClause != NIL)
2475 appendContextKeyword(context, " ORDER BY ",
2476 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2477 get_rule_orderby(query->sortClause, query->targetList,
2478 force_colno, context);
2481 /* Add the LIMIT clause if given */
2482 if (query->limitOffset != NULL)
2484 appendContextKeyword(context, " OFFSET ",
2485 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2486 get_rule_expr(query->limitOffset, context, false);
2488 if (query->limitCount != NULL)
2490 appendContextKeyword(context, " LIMIT ",
2491 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2492 if (IsA(query->limitCount, Const) &&
2493 ((Const *) query->limitCount)->constisnull)
2494 appendStringInfo(buf, "ALL");
2495 else
2496 get_rule_expr(query->limitCount, context, false);
2499 /* Add FOR UPDATE/SHARE clauses if present */
2500 foreach(l, query->rowMarks)
2502 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
2503 RangeTblEntry *rte = rt_fetch(rc->rti, query->rtable);
2505 if (rc->forUpdate)
2506 appendContextKeyword(context, " FOR UPDATE",
2507 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2508 else
2509 appendContextKeyword(context, " FOR SHARE",
2510 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2511 appendStringInfo(buf, " OF %s",
2512 quote_identifier(rte->eref->aliasname));
2513 if (rc->noWait)
2514 appendStringInfo(buf, " NOWAIT");
2517 context->windowClause = save_windowclause;
2518 context->windowTList = save_windowtlist;
2521 static void
2522 get_basic_select_query(Query *query, deparse_context *context,
2523 TupleDesc resultDesc)
2525 StringInfo buf = context->buf;
2526 char *sep;
2527 ListCell *l;
2529 if (PRETTY_INDENT(context))
2531 context->indentLevel += PRETTYINDENT_STD;
2532 appendStringInfoChar(buf, ' ');
2536 * If the query looks like SELECT * FROM (VALUES ...), then print just the
2537 * VALUES part. This reverses what transformValuesClause() did at parse
2538 * time. If the jointree contains just a single VALUES RTE, we assume
2539 * this case applies (without looking at the targetlist...)
2541 if (list_length(query->jointree->fromlist) == 1)
2543 RangeTblRef *rtr = (RangeTblRef *) linitial(query->jointree->fromlist);
2545 if (IsA(rtr, RangeTblRef))
2547 RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
2549 if (rte->rtekind == RTE_VALUES)
2551 get_values_def(rte->values_lists, context);
2552 return;
2558 * Build up the query string - first we say SELECT
2560 appendStringInfo(buf, "SELECT");
2562 /* Add the DISTINCT clause if given */
2563 if (query->distinctClause != NIL)
2565 if (query->hasDistinctOn)
2567 appendStringInfo(buf, " DISTINCT ON (");
2568 sep = "";
2569 foreach(l, query->distinctClause)
2571 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
2573 appendStringInfoString(buf, sep);
2574 get_rule_sortgroupclause(srt, query->targetList,
2575 false, context);
2576 sep = ", ";
2578 appendStringInfo(buf, ")");
2580 else
2581 appendStringInfo(buf, " DISTINCT");
2584 /* Then we tell what to select (the targetlist) */
2585 get_target_list(query->targetList, context, resultDesc);
2587 /* Add the FROM clause if needed */
2588 get_from_clause(query, " FROM ", context);
2590 /* Add the WHERE clause if given */
2591 if (query->jointree->quals != NULL)
2593 appendContextKeyword(context, " WHERE ",
2594 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2595 get_rule_expr(query->jointree->quals, context, false);
2598 /* Add the GROUP BY clause if given */
2599 if (query->groupClause != NULL)
2601 appendContextKeyword(context, " GROUP BY ",
2602 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2603 sep = "";
2604 foreach(l, query->groupClause)
2606 SortGroupClause *grp = (SortGroupClause *) lfirst(l);
2608 appendStringInfoString(buf, sep);
2609 get_rule_sortgroupclause(grp, query->targetList,
2610 false, context);
2611 sep = ", ";
2615 /* Add the HAVING clause if given */
2616 if (query->havingQual != NULL)
2618 appendContextKeyword(context, " HAVING ",
2619 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2620 get_rule_expr(query->havingQual, context, false);
2623 /* Add the WINDOW clause if needed */
2624 if (query->windowClause != NIL)
2625 get_rule_windowclause(query, context);
2628 /* ----------
2629 * get_target_list - Parse back a SELECT target list
2631 * This is also used for RETURNING lists in INSERT/UPDATE/DELETE.
2632 * ----------
2634 static void
2635 get_target_list(List *targetList, deparse_context *context,
2636 TupleDesc resultDesc)
2638 StringInfo buf = context->buf;
2639 char *sep;
2640 int colno;
2641 ListCell *l;
2643 sep = " ";
2644 colno = 0;
2645 foreach(l, targetList)
2647 TargetEntry *tle = (TargetEntry *) lfirst(l);
2648 char *colname;
2649 char *attname;
2651 if (tle->resjunk)
2652 continue; /* ignore junk entries */
2654 appendStringInfoString(buf, sep);
2655 sep = ", ";
2656 colno++;
2659 * We special-case Var nodes rather than using get_rule_expr. This is
2660 * needed because get_rule_expr will display a whole-row Var as
2661 * "foo.*", which is the preferred notation in most contexts, but at
2662 * the top level of a SELECT list it's not right (the parser will
2663 * expand that notation into multiple columns, yielding behavior
2664 * different from a whole-row Var). We want just "foo", instead.
2666 if (tle->expr && IsA(tle->expr, Var))
2668 attname = get_variable((Var *) tle->expr, 0, false, context);
2670 else
2672 get_rule_expr((Node *) tle->expr, context, true);
2673 /* We'll show the AS name unless it's this: */
2674 attname = "?column?";
2678 * Figure out what the result column should be called. In the context
2679 * of a view, use the view's tuple descriptor (so as to pick up the
2680 * effects of any column RENAME that's been done on the view).
2681 * Otherwise, just use what we can find in the TLE.
2683 if (resultDesc && colno <= resultDesc->natts)
2684 colname = NameStr(resultDesc->attrs[colno - 1]->attname);
2685 else
2686 colname = tle->resname;
2688 /* Show AS unless the column's name is correct as-is */
2689 if (colname) /* resname could be NULL */
2691 if (attname == NULL || strcmp(attname, colname) != 0)
2692 appendStringInfo(buf, " AS %s", quote_identifier(colname));
2697 static void
2698 get_setop_query(Node *setOp, Query *query, deparse_context *context,
2699 TupleDesc resultDesc)
2701 StringInfo buf = context->buf;
2702 bool need_paren;
2704 if (IsA(setOp, RangeTblRef))
2706 RangeTblRef *rtr = (RangeTblRef *) setOp;
2707 RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
2708 Query *subquery = rte->subquery;
2710 Assert(subquery != NULL);
2711 Assert(subquery->setOperations == NULL);
2712 /* Need parens if WITH, ORDER BY, FOR UPDATE, or LIMIT; see gram.y */
2713 need_paren = (subquery->cteList ||
2714 subquery->sortClause ||
2715 subquery->rowMarks ||
2716 subquery->limitOffset ||
2717 subquery->limitCount);
2718 if (need_paren)
2719 appendStringInfoChar(buf, '(');
2720 get_query_def(subquery, buf, context->namespaces, resultDesc,
2721 context->prettyFlags, context->indentLevel);
2722 if (need_paren)
2723 appendStringInfoChar(buf, ')');
2725 else if (IsA(setOp, SetOperationStmt))
2727 SetOperationStmt *op = (SetOperationStmt *) setOp;
2729 if (PRETTY_INDENT(context))
2731 context->indentLevel += PRETTYINDENT_STD;
2732 appendStringInfoSpaces(buf, PRETTYINDENT_STD);
2736 * We force parens whenever nesting two SetOperationStmts. There are
2737 * some cases in which parens are needed around a leaf query too, but
2738 * those are more easily handled at the next level down (see code
2739 * above).
2741 need_paren = !IsA(op->larg, RangeTblRef);
2743 if (need_paren)
2744 appendStringInfoChar(buf, '(');
2745 get_setop_query(op->larg, query, context, resultDesc);
2746 if (need_paren)
2747 appendStringInfoChar(buf, ')');
2749 if (!PRETTY_INDENT(context))
2750 appendStringInfoChar(buf, ' ');
2751 switch (op->op)
2753 case SETOP_UNION:
2754 appendContextKeyword(context, "UNION ",
2755 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2756 break;
2757 case SETOP_INTERSECT:
2758 appendContextKeyword(context, "INTERSECT ",
2759 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2760 break;
2761 case SETOP_EXCEPT:
2762 appendContextKeyword(context, "EXCEPT ",
2763 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
2764 break;
2765 default:
2766 elog(ERROR, "unrecognized set op: %d",
2767 (int) op->op);
2769 if (op->all)
2770 appendStringInfo(buf, "ALL ");
2772 if (PRETTY_INDENT(context))
2773 appendContextKeyword(context, "", 0, 0, 0);
2775 need_paren = !IsA(op->rarg, RangeTblRef);
2777 if (need_paren)
2778 appendStringInfoChar(buf, '(');
2779 get_setop_query(op->rarg, query, context, resultDesc);
2780 if (need_paren)
2781 appendStringInfoChar(buf, ')');
2783 if (PRETTY_INDENT(context))
2784 context->indentLevel -= PRETTYINDENT_STD;
2786 else
2788 elog(ERROR, "unrecognized node type: %d",
2789 (int) nodeTag(setOp));
2794 * Display a sort/group clause.
2796 * Also returns the expression tree, so caller need not find it again.
2798 static Node *
2799 get_rule_sortgroupclause(SortGroupClause *srt, List *tlist, bool force_colno,
2800 deparse_context *context)
2802 StringInfo buf = context->buf;
2803 TargetEntry *tle;
2804 Node *expr;
2806 tle = get_sortgroupclause_tle(srt, tlist);
2807 expr = (Node *) tle->expr;
2810 * Use column-number form if requested by caller. Otherwise, if
2811 * expression is a constant, force it to be dumped with an explicit
2812 * cast as decoration --- this is because a simple integer constant
2813 * is ambiguous (and will be misinterpreted by findTargetlistEntry())
2814 * if we dump it without any decoration. Otherwise, just dump the
2815 * expression normally.
2817 if (force_colno)
2819 Assert(!tle->resjunk);
2820 appendStringInfo(buf, "%d", tle->resno);
2822 else if (expr && IsA(expr, Const))
2823 get_const_expr((Const *) expr, context, 1);
2824 else
2825 get_rule_expr(expr, context, true);
2827 return expr;
2831 * Display an ORDER BY list.
2833 static void
2834 get_rule_orderby(List *orderList, List *targetList,
2835 bool force_colno, deparse_context *context)
2837 StringInfo buf = context->buf;
2838 const char *sep;
2839 ListCell *l;
2841 sep = "";
2842 foreach(l, orderList)
2844 SortGroupClause *srt = (SortGroupClause *) lfirst(l);
2845 Node *sortexpr;
2846 Oid sortcoltype;
2847 TypeCacheEntry *typentry;
2849 appendStringInfoString(buf, sep);
2850 sortexpr = get_rule_sortgroupclause(srt, targetList,
2851 force_colno, context);
2852 sortcoltype = exprType(sortexpr);
2853 /* See whether operator is default < or > for datatype */
2854 typentry = lookup_type_cache(sortcoltype,
2855 TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
2856 if (srt->sortop == typentry->lt_opr)
2858 /* ASC is default, so emit nothing for it */
2859 if (srt->nulls_first)
2860 appendStringInfo(buf, " NULLS FIRST");
2862 else if (srt->sortop == typentry->gt_opr)
2864 appendStringInfo(buf, " DESC");
2865 /* DESC defaults to NULLS FIRST */
2866 if (!srt->nulls_first)
2867 appendStringInfo(buf, " NULLS LAST");
2869 else
2871 appendStringInfo(buf, " USING %s",
2872 generate_operator_name(srt->sortop,
2873 sortcoltype,
2874 sortcoltype));
2875 /* be specific to eliminate ambiguity */
2876 if (srt->nulls_first)
2877 appendStringInfo(buf, " NULLS FIRST");
2878 else
2879 appendStringInfo(buf, " NULLS LAST");
2881 sep = ", ";
2886 * Display a WINDOW clause.
2888 * Note that the windowClause list might contain only anonymous window
2889 * specifications, in which case we should print nothing here.
2891 static void
2892 get_rule_windowclause(Query *query, deparse_context *context)
2894 StringInfo buf = context->buf;
2895 const char *sep;
2896 ListCell *l;
2898 sep = NULL;
2899 foreach(l, query->windowClause)
2901 WindowClause *wc = (WindowClause *) lfirst(l);
2903 if (wc->name == NULL)
2904 continue; /* ignore anonymous windows */
2906 if (sep == NULL)
2907 appendContextKeyword(context, " WINDOW ",
2908 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
2909 else
2910 appendStringInfoString(buf, sep);
2912 appendStringInfo(buf, "%s AS ", quote_identifier(wc->name));
2914 get_rule_windowspec(wc, query->targetList, context);
2916 sep = ", ";
2921 * Display a window definition
2923 static void
2924 get_rule_windowspec(WindowClause *wc, List *targetList,
2925 deparse_context *context)
2927 StringInfo buf = context->buf;
2928 bool needspace = false;
2929 const char *sep;
2930 ListCell *l;
2932 appendStringInfoChar(buf, '(');
2933 if (wc->refname)
2935 appendStringInfoString(buf, quote_identifier(wc->refname));
2936 needspace = true;
2938 /* partition clauses are always inherited, so only print if no refname */
2939 if (wc->partitionClause && !wc->refname)
2941 if (needspace)
2942 appendStringInfoChar(buf, ' ');
2943 appendStringInfoString(buf, "PARTITION BY ");
2944 sep = "";
2945 foreach(l, wc->partitionClause)
2947 SortGroupClause *grp = (SortGroupClause *) lfirst(l);
2949 appendStringInfoString(buf, sep);
2950 get_rule_sortgroupclause(grp, targetList,
2951 false, context);
2952 sep = ", ";
2954 needspace = true;
2956 /* print ordering clause only if not inherited */
2957 if (wc->orderClause && !wc->copiedOrder)
2959 if (needspace)
2960 appendStringInfoChar(buf, ' ');
2961 appendStringInfoString(buf, "ORDER BY ");
2962 get_rule_orderby(wc->orderClause, targetList, false, context);
2963 needspace = true;
2965 /* framing clause is never inherited, so print unless it's default */
2966 if (wc->frameOptions & FRAMEOPTION_NONDEFAULT)
2968 if (needspace)
2969 appendStringInfoChar(buf, ' ');
2970 if (wc->frameOptions & FRAMEOPTION_RANGE)
2971 appendStringInfoString(buf, "RANGE ");
2972 else if (wc->frameOptions & FRAMEOPTION_ROWS)
2973 appendStringInfoString(buf, "ROWS ");
2974 else
2975 Assert(false);
2976 if (wc->frameOptions & FRAMEOPTION_BETWEEN)
2977 appendStringInfoString(buf, "BETWEEN ");
2978 if (wc->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
2979 appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
2980 else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW)
2981 appendStringInfoString(buf, "CURRENT ROW ");
2982 else
2983 Assert(false);
2984 if (wc->frameOptions & FRAMEOPTION_BETWEEN)
2986 appendStringInfoString(buf, "AND ");
2987 if (wc->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
2988 appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
2989 else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
2990 appendStringInfoString(buf, "CURRENT ROW ");
2991 else
2992 Assert(false);
2994 /* we will now have a trailing space; remove it */
2995 buf->len--;
2997 appendStringInfoChar(buf, ')');
3000 /* ----------
3001 * get_insert_query_def - Parse back an INSERT parsetree
3002 * ----------
3004 static void
3005 get_insert_query_def(Query *query, deparse_context *context)
3007 StringInfo buf = context->buf;
3008 RangeTblEntry *select_rte = NULL;
3009 RangeTblEntry *values_rte = NULL;
3010 RangeTblEntry *rte;
3011 char *sep;
3012 ListCell *values_cell;
3013 ListCell *l;
3014 List *strippedexprs;
3017 * If it's an INSERT ... SELECT or VALUES (...), (...), ... there will be
3018 * a single RTE for the SELECT or VALUES.
3020 foreach(l, query->rtable)
3022 rte = (RangeTblEntry *) lfirst(l);
3024 if (rte->rtekind == RTE_SUBQUERY)
3026 if (select_rte)
3027 elog(ERROR, "too many subquery RTEs in INSERT");
3028 select_rte = rte;
3031 if (rte->rtekind == RTE_VALUES)
3033 if (values_rte)
3034 elog(ERROR, "too many values RTEs in INSERT");
3035 values_rte = rte;
3038 if (select_rte && values_rte)
3039 elog(ERROR, "both subquery and values RTEs in INSERT");
3042 * Start the query with INSERT INTO relname
3044 rte = rt_fetch(query->resultRelation, query->rtable);
3045 Assert(rte->rtekind == RTE_RELATION);
3047 if (PRETTY_INDENT(context))
3049 context->indentLevel += PRETTYINDENT_STD;
3050 appendStringInfoChar(buf, ' ');
3052 appendStringInfo(buf, "INSERT INTO %s (",
3053 generate_relation_name(rte->relid, NIL));
3056 * Add the insert-column-names list. To handle indirection properly, we
3057 * need to look for indirection nodes in the top targetlist (if it's
3058 * INSERT ... SELECT or INSERT ... single VALUES), or in the first
3059 * expression list of the VALUES RTE (if it's INSERT ... multi VALUES). We
3060 * assume that all the expression lists will have similar indirection in
3061 * the latter case.
3063 if (values_rte)
3064 values_cell = list_head((List *) linitial(values_rte->values_lists));
3065 else
3066 values_cell = NULL;
3067 strippedexprs = NIL;
3068 sep = "";
3069 foreach(l, query->targetList)
3071 TargetEntry *tle = (TargetEntry *) lfirst(l);
3073 if (tle->resjunk)
3074 continue; /* ignore junk entries */
3076 appendStringInfoString(buf, sep);
3077 sep = ", ";
3080 * Put out name of target column; look in the catalogs, not at
3081 * tle->resname, since resname will fail to track RENAME.
3083 appendStringInfoString(buf,
3084 quote_identifier(get_relid_attribute_name(rte->relid,
3085 tle->resno)));
3088 * Print any indirection needed (subfields or subscripts), and strip
3089 * off the top-level nodes representing the indirection assignments.
3091 if (values_cell)
3093 /* we discard the stripped expression in this case */
3094 processIndirection((Node *) lfirst(values_cell), context, true);
3095 values_cell = lnext(values_cell);
3097 else
3099 /* we keep a list of the stripped expressions in this case */
3100 strippedexprs = lappend(strippedexprs,
3101 processIndirection((Node *) tle->expr,
3102 context, true));
3105 appendStringInfo(buf, ") ");
3107 if (select_rte)
3109 /* Add the SELECT */
3110 get_query_def(select_rte->subquery, buf, NIL, NULL,
3111 context->prettyFlags, context->indentLevel);
3113 else if (values_rte)
3115 /* A WITH clause is possible here */
3116 get_with_clause(query, context);
3117 /* Add the multi-VALUES expression lists */
3118 get_values_def(values_rte->values_lists, context);
3120 else
3122 /* A WITH clause is possible here */
3123 get_with_clause(query, context);
3124 /* Add the single-VALUES expression list */
3125 appendContextKeyword(context, "VALUES (",
3126 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
3127 get_rule_expr((Node *) strippedexprs, context, false);
3128 appendStringInfoChar(buf, ')');
3131 /* Add RETURNING if present */
3132 if (query->returningList)
3134 appendContextKeyword(context, " RETURNING",
3135 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3136 get_target_list(query->returningList, context, NULL);
3141 /* ----------
3142 * get_update_query_def - Parse back an UPDATE parsetree
3143 * ----------
3145 static void
3146 get_update_query_def(Query *query, deparse_context *context)
3148 StringInfo buf = context->buf;
3149 char *sep;
3150 RangeTblEntry *rte;
3151 ListCell *l;
3154 * Start the query with UPDATE relname SET
3156 rte = rt_fetch(query->resultRelation, query->rtable);
3157 Assert(rte->rtekind == RTE_RELATION);
3158 if (PRETTY_INDENT(context))
3160 appendStringInfoChar(buf, ' ');
3161 context->indentLevel += PRETTYINDENT_STD;
3163 appendStringInfo(buf, "UPDATE %s%s",
3164 only_marker(rte),
3165 generate_relation_name(rte->relid, NIL));
3166 if (rte->alias != NULL)
3167 appendStringInfo(buf, " %s",
3168 quote_identifier(rte->alias->aliasname));
3169 appendStringInfoString(buf, " SET ");
3171 /* Add the comma separated list of 'attname = value' */
3172 sep = "";
3173 foreach(l, query->targetList)
3175 TargetEntry *tle = (TargetEntry *) lfirst(l);
3176 Node *expr;
3178 if (tle->resjunk)
3179 continue; /* ignore junk entries */
3181 appendStringInfoString(buf, sep);
3182 sep = ", ";
3185 * Put out name of target column; look in the catalogs, not at
3186 * tle->resname, since resname will fail to track RENAME.
3188 appendStringInfoString(buf,
3189 quote_identifier(get_relid_attribute_name(rte->relid,
3190 tle->resno)));
3193 * Print any indirection needed (subfields or subscripts), and strip
3194 * off the top-level nodes representing the indirection assignments.
3196 expr = processIndirection((Node *) tle->expr, context, true);
3198 appendStringInfo(buf, " = ");
3200 get_rule_expr(expr, context, false);
3203 /* Add the FROM clause if needed */
3204 get_from_clause(query, " FROM ", context);
3206 /* Add a WHERE clause if given */
3207 if (query->jointree->quals != NULL)
3209 appendContextKeyword(context, " WHERE ",
3210 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3211 get_rule_expr(query->jointree->quals, context, false);
3214 /* Add RETURNING if present */
3215 if (query->returningList)
3217 appendContextKeyword(context, " RETURNING",
3218 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3219 get_target_list(query->returningList, context, NULL);
3224 /* ----------
3225 * get_delete_query_def - Parse back a DELETE parsetree
3226 * ----------
3228 static void
3229 get_delete_query_def(Query *query, deparse_context *context)
3231 StringInfo buf = context->buf;
3232 RangeTblEntry *rte;
3235 * Start the query with DELETE FROM relname
3237 rte = rt_fetch(query->resultRelation, query->rtable);
3238 Assert(rte->rtekind == RTE_RELATION);
3239 if (PRETTY_INDENT(context))
3241 appendStringInfoChar(buf, ' ');
3242 context->indentLevel += PRETTYINDENT_STD;
3244 appendStringInfo(buf, "DELETE FROM %s%s",
3245 only_marker(rte),
3246 generate_relation_name(rte->relid, NIL));
3247 if (rte->alias != NULL)
3248 appendStringInfo(buf, " %s",
3249 quote_identifier(rte->alias->aliasname));
3251 /* Add the USING clause if given */
3252 get_from_clause(query, " USING ", context);
3254 /* Add a WHERE clause if given */
3255 if (query->jointree->quals != NULL)
3257 appendContextKeyword(context, " WHERE ",
3258 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3259 get_rule_expr(query->jointree->quals, context, false);
3262 /* Add RETURNING if present */
3263 if (query->returningList)
3265 appendContextKeyword(context, " RETURNING",
3266 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
3267 get_target_list(query->returningList, context, NULL);
3272 /* ----------
3273 * get_utility_query_def - Parse back a UTILITY parsetree
3274 * ----------
3276 static void
3277 get_utility_query_def(Query *query, deparse_context *context)
3279 StringInfo buf = context->buf;
3281 if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
3283 NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;
3285 appendContextKeyword(context, "",
3286 0, PRETTYINDENT_STD, 1);
3287 appendStringInfo(buf, "NOTIFY %s",
3288 quote_identifier(stmt->conditionname));
3290 else
3292 /* Currently only NOTIFY utility commands can appear in rules */
3293 elog(ERROR, "unexpected utility statement type");
3299 * push_plan: set up deparse_namespace to recurse into the tlist of a subplan
3301 * When expanding an OUTER or INNER reference, we must push new outer/inner
3302 * subplans in case the referenced expression itself uses OUTER/INNER. We
3303 * modify the top stack entry in-place to avoid affecting levelsup issues
3304 * (although in a Plan tree there really shouldn't be any).
3306 * Caller must save and restore outer_plan and inner_plan around this.
3308 * We also use this to initialize the fields during deparse_context_for_plan.
3310 static void
3311 push_plan(deparse_namespace *dpns, Plan *subplan)
3314 * We special-case Append to pretend that the first child plan is the
3315 * OUTER referent; otherwise normal.
3317 if (IsA(subplan, Append))
3318 dpns->outer_plan = (Plan *) linitial(((Append *) subplan)->appendplans);
3319 else
3320 dpns->outer_plan = outerPlan(subplan);
3323 * For a SubqueryScan, pretend the subplan is INNER referent. (We don't
3324 * use OUTER because that could someday conflict with the normal meaning.)
3325 * Likewise, for a CteScan, pretend the subquery's plan is INNER referent.
3327 if (IsA(subplan, SubqueryScan))
3328 dpns->inner_plan = ((SubqueryScan *) subplan)->subplan;
3329 else if (IsA(subplan, CteScan))
3331 int ctePlanId = ((CteScan *) subplan)->ctePlanId;
3333 if (ctePlanId > 0 && ctePlanId <= list_length(dpns->subplans))
3334 dpns->inner_plan = list_nth(dpns->subplans, ctePlanId - 1);
3335 else
3336 dpns->inner_plan = NULL;
3338 else
3339 dpns->inner_plan = innerPlan(subplan);
3344 * Display a Var appropriately.
3346 * In some cases (currently only when recursing into an unnamed join)
3347 * the Var's varlevelsup has to be interpreted with respect to a context
3348 * above the current one; levelsup indicates the offset.
3350 * If showstar is TRUE, whole-row Vars are displayed as "foo.*";
3351 * if FALSE, merely as "foo".
3353 * Returns the attname of the Var, or NULL if not determinable.
3355 static char *
3356 get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
3358 StringInfo buf = context->buf;
3359 RangeTblEntry *rte;
3360 AttrNumber attnum;
3361 int netlevelsup;
3362 deparse_namespace *dpns;
3363 char *schemaname;
3364 char *refname;
3365 char *attname;
3367 /* Find appropriate nesting depth */
3368 netlevelsup = var->varlevelsup + levelsup;
3369 if (netlevelsup >= list_length(context->namespaces))
3370 elog(ERROR, "bogus varlevelsup: %d offset %d",
3371 var->varlevelsup, levelsup);
3372 dpns = (deparse_namespace *) list_nth(context->namespaces,
3373 netlevelsup);
3376 * Try to find the relevant RTE in this rtable. In a plan tree, it's
3377 * likely that varno is OUTER or INNER, in which case we must dig down
3378 * into the subplans.
3380 if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
3382 rte = rt_fetch(var->varno, dpns->rtable);
3383 attnum = var->varattno;
3385 else if (var->varno == OUTER && dpns->outer_plan)
3387 TargetEntry *tle;
3388 Plan *save_outer;
3389 Plan *save_inner;
3391 tle = get_tle_by_resno(dpns->outer_plan->targetlist, var->varattno);
3392 if (!tle)
3393 elog(ERROR, "bogus varattno for OUTER var: %d", var->varattno);
3395 Assert(netlevelsup == 0);
3396 save_outer = dpns->outer_plan;
3397 save_inner = dpns->inner_plan;
3398 push_plan(dpns, dpns->outer_plan);
3401 * Force parentheses because our caller probably assumed a Var is a
3402 * simple expression.
3404 if (!IsA(tle->expr, Var))
3405 appendStringInfoChar(buf, '(');
3406 get_rule_expr((Node *) tle->expr, context, true);
3407 if (!IsA(tle->expr, Var))
3408 appendStringInfoChar(buf, ')');
3410 dpns->outer_plan = save_outer;
3411 dpns->inner_plan = save_inner;
3412 return NULL;
3414 else if (var->varno == INNER && dpns->inner_plan)
3416 TargetEntry *tle;
3417 Plan *save_outer;
3418 Plan *save_inner;
3420 tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno);
3421 if (!tle)
3422 elog(ERROR, "bogus varattno for INNER var: %d", var->varattno);
3424 Assert(netlevelsup == 0);
3425 save_outer = dpns->outer_plan;
3426 save_inner = dpns->inner_plan;
3427 push_plan(dpns, dpns->inner_plan);
3430 * Force parentheses because our caller probably assumed a Var is a
3431 * simple expression.
3433 if (!IsA(tle->expr, Var))
3434 appendStringInfoChar(buf, '(');
3435 get_rule_expr((Node *) tle->expr, context, true);
3436 if (!IsA(tle->expr, Var))
3437 appendStringInfoChar(buf, ')');
3439 dpns->outer_plan = save_outer;
3440 dpns->inner_plan = save_inner;
3441 return NULL;
3443 else
3445 elog(ERROR, "bogus varno: %d", var->varno);
3446 return NULL; /* keep compiler quiet */
3449 /* Identify names to use */
3450 schemaname = NULL; /* default assumptions */
3451 refname = rte->eref->aliasname;
3453 /* Exceptions occur only if the RTE is alias-less */
3454 if (rte->alias == NULL)
3456 if (rte->rtekind == RTE_RELATION)
3459 * It's possible that use of the bare refname would find another
3460 * more-closely-nested RTE, or be ambiguous, in which case we need
3461 * to specify the schemaname to avoid these errors.
3463 if (find_rte_by_refname(rte->eref->aliasname, context) != rte)
3464 schemaname = get_namespace_name(get_rel_namespace(rte->relid));
3466 else if (rte->rtekind == RTE_JOIN)
3469 * If it's an unnamed join, look at the expansion of the alias
3470 * variable. If it's a simple reference to one of the input vars
3471 * then recursively print the name of that var, instead. (This
3472 * allows correct decompiling of cases where there are identically
3473 * named columns on both sides of the join.) When it's not a
3474 * simple reference, we have to just print the unqualified
3475 * variable name (this can only happen with columns that were
3476 * merged by USING or NATURAL clauses).
3478 * This wouldn't work in decompiling plan trees, because we don't
3479 * store joinaliasvars lists after planning; but a plan tree
3480 * should never contain a join alias variable.
3482 if (rte->joinaliasvars == NIL)
3483 elog(ERROR, "cannot decompile join alias var in plan tree");
3484 if (attnum > 0)
3486 Var *aliasvar;
3488 aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
3489 if (IsA(aliasvar, Var))
3491 return get_variable(aliasvar, var->varlevelsup + levelsup,
3492 showstar, context);
3495 /* Unnamed join has neither schemaname nor refname */
3496 refname = NULL;
3500 if (attnum == InvalidAttrNumber)
3501 attname = NULL;
3502 else
3503 attname = get_rte_attribute_name(rte, attnum);
3505 if (refname && (context->varprefix || attname == NULL))
3507 if (schemaname)
3508 appendStringInfo(buf, "%s.",
3509 quote_identifier(schemaname));
3511 if (strcmp(refname, "*NEW*") == 0)
3512 appendStringInfoString(buf, "new");
3513 else if (strcmp(refname, "*OLD*") == 0)
3514 appendStringInfoString(buf, "old");
3515 else
3516 appendStringInfoString(buf, quote_identifier(refname));
3518 if (attname || showstar)
3519 appendStringInfoChar(buf, '.');
3521 if (attname)
3522 appendStringInfoString(buf, quote_identifier(attname));
3523 else if (showstar)
3524 appendStringInfoChar(buf, '*');
3526 return attname;
3531 * Get the name of a field of an expression of composite type.
3533 * This is fairly straightforward except for the case of a Var of type RECORD.
3534 * Since no actual table or view column is allowed to have type RECORD, such
3535 * a Var must refer to a JOIN or FUNCTION RTE or to a subquery output. We
3536 * drill down to find the ultimate defining expression and attempt to infer
3537 * the field name from it. We ereport if we can't determine the name.
3539 * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
3541 static const char *
3542 get_name_for_var_field(Var *var, int fieldno,
3543 int levelsup, deparse_context *context)
3545 RangeTblEntry *rte;
3546 AttrNumber attnum;
3547 int netlevelsup;
3548 deparse_namespace *dpns;
3549 TupleDesc tupleDesc;
3550 Node *expr;
3553 * If it's a RowExpr that was expanded from a whole-row Var, use the
3554 * column names attached to it.
3556 if (IsA(var, RowExpr))
3558 RowExpr *r = (RowExpr *) var;
3560 if (fieldno > 0 && fieldno <= list_length(r->colnames))
3561 return strVal(list_nth(r->colnames, fieldno - 1));
3565 * If it's a Var of type RECORD, we have to find what the Var refers to;
3566 * if not, we can use get_expr_result_type. If that fails, we try
3567 * lookup_rowtype_tupdesc, which will probably fail too, but will ereport
3568 * an acceptable message.
3570 if (!IsA(var, Var) ||
3571 var->vartype != RECORDOID)
3573 if (get_expr_result_type((Node *) var, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
3574 tupleDesc = lookup_rowtype_tupdesc_copy(exprType((Node *) var),
3575 exprTypmod((Node *) var));
3576 Assert(tupleDesc);
3577 /* Got the tupdesc, so we can extract the field name */
3578 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
3579 return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
3582 /* Find appropriate nesting depth */
3583 netlevelsup = var->varlevelsup + levelsup;
3584 if (netlevelsup >= list_length(context->namespaces))
3585 elog(ERROR, "bogus varlevelsup: %d offset %d",
3586 var->varlevelsup, levelsup);
3587 dpns = (deparse_namespace *) list_nth(context->namespaces,
3588 netlevelsup);
3591 * Try to find the relevant RTE in this rtable. In a plan tree, it's
3592 * likely that varno is OUTER or INNER, in which case we must dig down
3593 * into the subplans.
3595 if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
3597 rte = rt_fetch(var->varno, dpns->rtable);
3598 attnum = var->varattno;
3600 else if (var->varno == OUTER && dpns->outer_plan)
3602 TargetEntry *tle;
3603 Plan *save_outer;
3604 Plan *save_inner;
3605 const char *result;
3607 tle = get_tle_by_resno(dpns->outer_plan->targetlist, var->varattno);
3608 if (!tle)
3609 elog(ERROR, "bogus varattno for OUTER var: %d", var->varattno);
3611 Assert(netlevelsup == 0);
3612 save_outer = dpns->outer_plan;
3613 save_inner = dpns->inner_plan;
3614 push_plan(dpns, dpns->outer_plan);
3616 result = get_name_for_var_field((Var *) tle->expr, fieldno,
3617 levelsup, context);
3619 dpns->outer_plan = save_outer;
3620 dpns->inner_plan = save_inner;
3621 return result;
3623 else if (var->varno == INNER && dpns->inner_plan)
3625 TargetEntry *tle;
3626 Plan *save_outer;
3627 Plan *save_inner;
3628 const char *result;
3630 tle = get_tle_by_resno(dpns->inner_plan->targetlist, var->varattno);
3631 if (!tle)
3632 elog(ERROR, "bogus varattno for INNER var: %d", var->varattno);
3634 Assert(netlevelsup == 0);
3635 save_outer = dpns->outer_plan;
3636 save_inner = dpns->inner_plan;
3637 push_plan(dpns, dpns->inner_plan);
3639 result = get_name_for_var_field((Var *) tle->expr, fieldno,
3640 levelsup, context);
3642 dpns->outer_plan = save_outer;
3643 dpns->inner_plan = save_inner;
3644 return result;
3646 else
3648 elog(ERROR, "bogus varno: %d", var->varno);
3649 return NULL; /* keep compiler quiet */
3652 if (attnum == InvalidAttrNumber)
3654 /* Var is whole-row reference to RTE, so select the right field */
3655 return get_rte_attribute_name(rte, fieldno);
3659 * This part has essentially the same logic as the parser's
3660 * expandRecordVariable() function, but we are dealing with a different
3661 * representation of the input context, and we only need one field name
3662 * not a TupleDesc. Also, we need special cases for finding subquery
3663 * and CTE subplans when deparsing Plan trees.
3665 expr = (Node *) var; /* default if we can't drill down */
3667 switch (rte->rtekind)
3669 case RTE_RELATION:
3670 case RTE_SPECIAL:
3671 case RTE_VALUES:
3674 * This case should not occur: a column of a table or values list
3675 * shouldn't have type RECORD. Fall through and fail (most
3676 * likely) at the bottom.
3678 break;
3679 case RTE_SUBQUERY:
3680 /* Subselect-in-FROM: examine sub-select's output expr */
3682 if (rte->subquery)
3684 TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
3685 attnum);
3687 if (ste == NULL || ste->resjunk)
3688 elog(ERROR, "subquery %s does not have attribute %d",
3689 rte->eref->aliasname, attnum);
3690 expr = (Node *) ste->expr;
3691 if (IsA(expr, Var))
3694 * Recurse into the sub-select to see what its Var
3695 * refers to. We have to build an additional level of
3696 * namespace to keep in step with varlevelsup in the
3697 * subselect.
3699 deparse_namespace mydpns;
3700 const char *result;
3702 mydpns.rtable = rte->subquery->rtable;
3703 mydpns.ctes = rte->subquery->cteList;
3704 mydpns.subplans = NIL;
3705 mydpns.outer_plan = mydpns.inner_plan = NULL;
3707 context->namespaces = lcons(&mydpns,
3708 context->namespaces);
3710 result = get_name_for_var_field((Var *) expr, fieldno,
3711 0, context);
3713 context->namespaces =
3714 list_delete_first(context->namespaces);
3716 return result;
3718 /* else fall through to inspect the expression */
3720 else
3723 * We're deparsing a Plan tree so we don't have complete
3724 * RTE entries (in particular, rte->subquery is NULL).
3725 * But the only place we'd see a Var directly referencing
3726 * a SUBQUERY RTE is in a SubqueryScan plan node, and we
3727 * can look into the child plan's tlist instead.
3729 TargetEntry *tle;
3730 Plan *save_outer;
3731 Plan *save_inner;
3732 const char *result;
3734 if (!dpns->inner_plan)
3735 elog(ERROR, "failed to find plan for subquery %s",
3736 rte->eref->aliasname);
3737 tle = get_tle_by_resno(dpns->inner_plan->targetlist,
3738 attnum);
3739 if (!tle)
3740 elog(ERROR, "bogus varattno for subquery var: %d",
3741 attnum);
3742 Assert(netlevelsup == 0);
3743 save_outer = dpns->outer_plan;
3744 save_inner = dpns->inner_plan;
3745 push_plan(dpns, dpns->inner_plan);
3747 result = get_name_for_var_field((Var *) tle->expr, fieldno,
3748 levelsup, context);
3750 dpns->outer_plan = save_outer;
3751 dpns->inner_plan = save_inner;
3752 return result;
3755 break;
3756 case RTE_JOIN:
3757 /* Join RTE --- recursively inspect the alias variable */
3758 if (rte->joinaliasvars == NIL)
3759 elog(ERROR, "cannot decompile join alias var in plan tree");
3760 Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));
3761 expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
3762 if (IsA(expr, Var))
3763 return get_name_for_var_field((Var *) expr, fieldno,
3764 var->varlevelsup + levelsup,
3765 context);
3766 /* else fall through to inspect the expression */
3767 break;
3768 case RTE_FUNCTION:
3771 * We couldn't get here unless a function is declared with one of
3772 * its result columns as RECORD, which is not allowed.
3774 break;
3775 case RTE_CTE:
3776 /* CTE reference: examine subquery's output expr */
3778 CommonTableExpr *cte = NULL;
3779 Index ctelevelsup;
3780 ListCell *lc;
3783 * Try to find the referenced CTE using the namespace stack.
3785 ctelevelsup = rte->ctelevelsup + netlevelsup;
3786 if (ctelevelsup >= list_length(context->namespaces))
3787 lc = NULL;
3788 else
3790 deparse_namespace *ctedpns;
3792 ctedpns = (deparse_namespace *)
3793 list_nth(context->namespaces, ctelevelsup);
3794 foreach(lc, ctedpns->ctes)
3796 cte = (CommonTableExpr *) lfirst(lc);
3797 if (strcmp(cte->ctename, rte->ctename) == 0)
3798 break;
3801 if (lc != NULL)
3803 Query *ctequery = (Query *) cte->ctequery;
3804 TargetEntry *ste = get_tle_by_resno(ctequery->targetList,
3805 attnum);
3807 if (ste == NULL || ste->resjunk)
3808 elog(ERROR, "subquery %s does not have attribute %d",
3809 rte->eref->aliasname, attnum);
3810 expr = (Node *) ste->expr;
3811 if (IsA(expr, Var))
3814 * Recurse into the CTE to see what its Var refers
3815 * to. We have to build an additional level of
3816 * namespace to keep in step with varlevelsup in the
3817 * CTE. Furthermore it could be an outer CTE, so
3818 * we may have to delete some levels of namespace.
3820 List *save_nslist = context->namespaces;
3821 List *new_nslist;
3822 deparse_namespace mydpns;
3823 const char *result;
3825 mydpns.rtable = ctequery->rtable;
3826 mydpns.ctes = ctequery->cteList;
3827 mydpns.subplans = NIL;
3828 mydpns.outer_plan = mydpns.inner_plan = NULL;
3830 new_nslist = list_copy_tail(context->namespaces,
3831 ctelevelsup);
3832 context->namespaces = lcons(&mydpns, new_nslist);
3834 result = get_name_for_var_field((Var *) expr, fieldno,
3835 0, context);
3837 context->namespaces = save_nslist;
3839 return result;
3841 /* else fall through to inspect the expression */
3843 else
3846 * We're deparsing a Plan tree so we don't have a CTE
3847 * list. But the only place we'd see a Var directly
3848 * referencing a CTE RTE is in a CteScan plan node, and
3849 * we can look into the subplan's tlist instead.
3851 TargetEntry *tle;
3852 Plan *save_outer;
3853 Plan *save_inner;
3854 const char *result;
3856 if (!dpns->inner_plan)
3857 elog(ERROR, "failed to find plan for CTE %s",
3858 rte->eref->aliasname);
3859 tle = get_tle_by_resno(dpns->inner_plan->targetlist,
3860 attnum);
3861 if (!tle)
3862 elog(ERROR, "bogus varattno for subquery var: %d",
3863 attnum);
3864 Assert(netlevelsup == 0);
3865 save_outer = dpns->outer_plan;
3866 save_inner = dpns->inner_plan;
3867 push_plan(dpns, dpns->inner_plan);
3869 result = get_name_for_var_field((Var *) tle->expr, fieldno,
3870 levelsup, context);
3872 dpns->outer_plan = save_outer;
3873 dpns->inner_plan = save_inner;
3874 return result;
3877 break;
3881 * We now have an expression we can't expand any more, so see if
3882 * get_expr_result_type() can do anything with it. If not, pass to
3883 * lookup_rowtype_tupdesc() which will probably fail, but will give an
3884 * appropriate error message while failing.
3886 if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
3887 tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr),
3888 exprTypmod(expr));
3889 Assert(tupleDesc);
3890 /* Got the tupdesc, so we can extract the field name */
3891 Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
3892 return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
3897 * find_rte_by_refname - look up an RTE by refname in a deparse context
3899 * Returns NULL if there is no matching RTE or the refname is ambiguous.
3901 * NOTE: this code is not really correct since it does not take account of
3902 * the fact that not all the RTEs in a rangetable may be visible from the
3903 * point where a Var reference appears. For the purposes we need, however,
3904 * the only consequence of a false match is that we might stick a schema
3905 * qualifier on a Var that doesn't really need it. So it seems close
3906 * enough.
3908 static RangeTblEntry *
3909 find_rte_by_refname(const char *refname, deparse_context *context)
3911 RangeTblEntry *result = NULL;
3912 ListCell *nslist;
3914 foreach(nslist, context->namespaces)
3916 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
3917 ListCell *rtlist;
3919 foreach(rtlist, dpns->rtable)
3921 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtlist);
3923 if (strcmp(rte->eref->aliasname, refname) == 0)
3925 if (result)
3926 return NULL; /* it's ambiguous */
3927 result = rte;
3930 if (result)
3931 break;
3933 return result;
3938 * get_simple_binary_op_name
3940 * helper function for isSimpleNode
3941 * will return single char binary operator name, or NULL if it's not
3943 static const char *
3944 get_simple_binary_op_name(OpExpr *expr)
3946 List *args = expr->args;
3948 if (list_length(args) == 2)
3950 /* binary operator */
3951 Node *arg1 = (Node *) linitial(args);
3952 Node *arg2 = (Node *) lsecond(args);
3953 const char *op;
3955 op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));
3956 if (strlen(op) == 1)
3957 return op;
3959 return NULL;
3964 * isSimpleNode - check if given node is simple (doesn't need parenthesizing)
3966 * true : simple in the context of parent node's type
3967 * false : not simple
3969 static bool
3970 isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
3972 if (!node)
3973 return false;
3975 switch (nodeTag(node))
3977 case T_Var:
3978 case T_Const:
3979 case T_Param:
3980 case T_CoerceToDomainValue:
3981 case T_SetToDefault:
3982 case T_CurrentOfExpr:
3983 /* single words: always simple */
3984 return true;
3986 case T_ArrayRef:
3987 case T_ArrayExpr:
3988 case T_RowExpr:
3989 case T_CoalesceExpr:
3990 case T_MinMaxExpr:
3991 case T_XmlExpr:
3992 case T_NullIfExpr:
3993 case T_Aggref:
3994 case T_WindowFunc:
3995 case T_FuncExpr:
3996 /* function-like: name(..) or name[..] */
3997 return true;
3999 /* CASE keywords act as parentheses */
4000 case T_CaseExpr:
4001 return true;
4003 case T_FieldSelect:
4006 * appears simple since . has top precedence, unless parent is
4007 * T_FieldSelect itself!
4009 return (IsA(parentNode, FieldSelect) ? false : true);
4011 case T_FieldStore:
4014 * treat like FieldSelect (probably doesn't matter)
4016 return (IsA(parentNode, FieldStore) ? false : true);
4018 case T_CoerceToDomain:
4019 /* maybe simple, check args */
4020 return isSimpleNode((Node *) ((CoerceToDomain *) node)->arg,
4021 node, prettyFlags);
4022 case T_RelabelType:
4023 return isSimpleNode((Node *) ((RelabelType *) node)->arg,
4024 node, prettyFlags);
4025 case T_CoerceViaIO:
4026 return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg,
4027 node, prettyFlags);
4028 case T_ArrayCoerceExpr:
4029 return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
4030 node, prettyFlags);
4031 case T_ConvertRowtypeExpr:
4032 return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
4033 node, prettyFlags);
4035 case T_OpExpr:
4037 /* depends on parent node type; needs further checking */
4038 if (prettyFlags & PRETTYFLAG_PAREN && IsA(parentNode, OpExpr))
4040 const char *op;
4041 const char *parentOp;
4042 bool is_lopriop;
4043 bool is_hipriop;
4044 bool is_lopriparent;
4045 bool is_hipriparent;
4047 op = get_simple_binary_op_name((OpExpr *) node);
4048 if (!op)
4049 return false;
4051 /* We know only the basic operators + - and * / % */
4052 is_lopriop = (strchr("+-", *op) != NULL);
4053 is_hipriop = (strchr("*/%", *op) != NULL);
4054 if (!(is_lopriop || is_hipriop))
4055 return false;
4057 parentOp = get_simple_binary_op_name((OpExpr *) parentNode);
4058 if (!parentOp)
4059 return false;
4061 is_lopriparent = (strchr("+-", *parentOp) != NULL);
4062 is_hipriparent = (strchr("*/%", *parentOp) != NULL);
4063 if (!(is_lopriparent || is_hipriparent))
4064 return false;
4066 if (is_hipriop && is_lopriparent)
4067 return true; /* op binds tighter than parent */
4069 if (is_lopriop && is_hipriparent)
4070 return false;
4073 * Operators are same priority --- can skip parens only if
4074 * we have (a - b) - c, not a - (b - c).
4076 if (node == (Node *) linitial(((OpExpr *) parentNode)->args))
4077 return true;
4079 return false;
4081 /* else do the same stuff as for T_SubLink et al. */
4082 /* FALL THROUGH */
4085 case T_SubLink:
4086 case T_NullTest:
4087 case T_BooleanTest:
4088 case T_DistinctExpr:
4089 switch (nodeTag(parentNode))
4091 case T_FuncExpr:
4093 /* special handling for casts */
4094 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
4096 if (type == COERCE_EXPLICIT_CAST ||
4097 type == COERCE_IMPLICIT_CAST)
4098 return false;
4099 return true; /* own parentheses */
4101 case T_BoolExpr: /* lower precedence */
4102 case T_ArrayRef: /* other separators */
4103 case T_ArrayExpr: /* other separators */
4104 case T_RowExpr: /* other separators */
4105 case T_CoalesceExpr: /* own parentheses */
4106 case T_MinMaxExpr: /* own parentheses */
4107 case T_XmlExpr: /* own parentheses */
4108 case T_NullIfExpr: /* other separators */
4109 case T_Aggref: /* own parentheses */
4110 case T_WindowFunc: /* own parentheses */
4111 case T_CaseExpr: /* other separators */
4112 return true;
4113 default:
4114 return false;
4117 case T_BoolExpr:
4118 switch (nodeTag(parentNode))
4120 case T_BoolExpr:
4121 if (prettyFlags & PRETTYFLAG_PAREN)
4123 BoolExprType type;
4124 BoolExprType parentType;
4126 type = ((BoolExpr *) node)->boolop;
4127 parentType = ((BoolExpr *) parentNode)->boolop;
4128 switch (type)
4130 case NOT_EXPR:
4131 case AND_EXPR:
4132 if (parentType == AND_EXPR || parentType == OR_EXPR)
4133 return true;
4134 break;
4135 case OR_EXPR:
4136 if (parentType == OR_EXPR)
4137 return true;
4138 break;
4141 return false;
4142 case T_FuncExpr:
4144 /* special handling for casts */
4145 CoercionForm type = ((FuncExpr *) parentNode)->funcformat;
4147 if (type == COERCE_EXPLICIT_CAST ||
4148 type == COERCE_IMPLICIT_CAST)
4149 return false;
4150 return true; /* own parentheses */
4152 case T_ArrayRef: /* other separators */
4153 case T_ArrayExpr: /* other separators */
4154 case T_RowExpr: /* other separators */
4155 case T_CoalesceExpr: /* own parentheses */
4156 case T_MinMaxExpr: /* own parentheses */
4157 case T_XmlExpr: /* own parentheses */
4158 case T_NullIfExpr: /* other separators */
4159 case T_Aggref: /* own parentheses */
4160 case T_WindowFunc: /* own parentheses */
4161 case T_CaseExpr: /* other separators */
4162 return true;
4163 default:
4164 return false;
4167 default:
4168 break;
4170 /* those we don't know: in dubio complexo */
4171 return false;
4176 * appendStringInfoSpaces - append spaces to buffer
4178 static void
4179 appendStringInfoSpaces(StringInfo buf, int count)
4181 while (count-- > 0)
4182 appendStringInfoChar(buf, ' ');
4186 * appendContextKeyword - append a keyword to buffer
4188 * If prettyPrint is enabled, perform a line break, and adjust indentation.
4189 * Otherwise, just append the keyword.
4191 static void
4192 appendContextKeyword(deparse_context *context, const char *str,
4193 int indentBefore, int indentAfter, int indentPlus)
4195 if (PRETTY_INDENT(context))
4197 context->indentLevel += indentBefore;
4199 appendStringInfoChar(context->buf, '\n');
4200 appendStringInfoSpaces(context->buf,
4201 Max(context->indentLevel, 0) + indentPlus);
4202 appendStringInfoString(context->buf, str);
4204 context->indentLevel += indentAfter;
4205 if (context->indentLevel < 0)
4206 context->indentLevel = 0;
4208 else
4209 appendStringInfoString(context->buf, str);
4213 * get_rule_expr_paren - deparse expr using get_rule_expr,
4214 * embracing the string with parentheses if necessary for prettyPrint.
4216 * Never embrace if prettyFlags=0, because it's done in the calling node.
4218 * Any node that does *not* embrace its argument node by sql syntax (with
4219 * parentheses, non-operator keywords like CASE/WHEN/ON, or comma etc) should
4220 * use get_rule_expr_paren instead of get_rule_expr so parentheses can be
4221 * added.
4223 static void
4224 get_rule_expr_paren(Node *node, deparse_context *context,
4225 bool showimplicit, Node *parentNode)
4227 bool need_paren;
4229 need_paren = PRETTY_PAREN(context) &&
4230 !isSimpleNode(node, parentNode, context->prettyFlags);
4232 if (need_paren)
4233 appendStringInfoChar(context->buf, '(');
4235 get_rule_expr(node, context, showimplicit);
4237 if (need_paren)
4238 appendStringInfoChar(context->buf, ')');
4242 /* ----------
4243 * get_rule_expr - Parse back an expression
4245 * Note: showimplicit determines whether we display any implicit cast that
4246 * is present at the top of the expression tree. It is a passed argument,
4247 * not a field of the context struct, because we change the value as we
4248 * recurse down into the expression. In general we suppress implicit casts
4249 * when the result type is known with certainty (eg, the arguments of an
4250 * OR must be boolean). We display implicit casts for arguments of functions
4251 * and operators, since this is needed to be certain that the same function
4252 * or operator will be chosen when the expression is re-parsed.
4253 * ----------
4255 static void
4256 get_rule_expr(Node *node, deparse_context *context,
4257 bool showimplicit)
4259 StringInfo buf = context->buf;
4261 if (node == NULL)
4262 return;
4265 * Each level of get_rule_expr must emit an indivisible term
4266 * (parenthesized if necessary) to ensure result is reparsed into the same
4267 * expression tree. The only exception is that when the input is a List,
4268 * we emit the component items comma-separated with no surrounding
4269 * decoration; this is convenient for most callers.
4271 switch (nodeTag(node))
4273 case T_Var:
4274 (void) get_variable((Var *) node, 0, true, context);
4275 break;
4277 case T_Const:
4278 get_const_expr((Const *) node, context, 0);
4279 break;
4281 case T_Param:
4282 appendStringInfo(buf, "$%d", ((Param *) node)->paramid);
4283 break;
4285 case T_Aggref:
4286 get_agg_expr((Aggref *) node, context);
4287 break;
4289 case T_WindowFunc:
4290 get_windowfunc_expr((WindowFunc *) node, context);
4291 break;
4293 case T_ArrayRef:
4295 ArrayRef *aref = (ArrayRef *) node;
4296 bool need_parens;
4299 * Parenthesize the argument unless it's a simple Var or a
4300 * FieldSelect. (In particular, if it's another ArrayRef, we
4301 * *must* parenthesize to avoid confusion.)
4303 need_parens = !IsA(aref->refexpr, Var) &&
4304 !IsA(aref->refexpr, FieldSelect);
4305 if (need_parens)
4306 appendStringInfoChar(buf, '(');
4307 get_rule_expr((Node *) aref->refexpr, context, showimplicit);
4308 if (need_parens)
4309 appendStringInfoChar(buf, ')');
4310 printSubscripts(aref, context);
4313 * Array assignment nodes should have been handled in
4314 * processIndirection().
4316 if (aref->refassgnexpr)
4317 elog(ERROR, "unexpected refassgnexpr");
4319 break;
4321 case T_FuncExpr:
4322 get_func_expr((FuncExpr *) node, context, showimplicit);
4323 break;
4325 case T_OpExpr:
4326 get_oper_expr((OpExpr *) node, context);
4327 break;
4329 case T_DistinctExpr:
4331 DistinctExpr *expr = (DistinctExpr *) node;
4332 List *args = expr->args;
4333 Node *arg1 = (Node *) linitial(args);
4334 Node *arg2 = (Node *) lsecond(args);
4336 if (!PRETTY_PAREN(context))
4337 appendStringInfoChar(buf, '(');
4338 get_rule_expr_paren(arg1, context, true, node);
4339 appendStringInfo(buf, " IS DISTINCT FROM ");
4340 get_rule_expr_paren(arg2, context, true, node);
4341 if (!PRETTY_PAREN(context))
4342 appendStringInfoChar(buf, ')');
4344 break;
4346 case T_ScalarArrayOpExpr:
4348 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
4349 List *args = expr->args;
4350 Node *arg1 = (Node *) linitial(args);
4351 Node *arg2 = (Node *) lsecond(args);
4353 if (!PRETTY_PAREN(context))
4354 appendStringInfoChar(buf, '(');
4355 get_rule_expr_paren(arg1, context, true, node);
4356 appendStringInfo(buf, " %s %s (",
4357 generate_operator_name(expr->opno,
4358 exprType(arg1),
4359 get_element_type(exprType(arg2))),
4360 expr->useOr ? "ANY" : "ALL");
4361 get_rule_expr_paren(arg2, context, true, node);
4362 appendStringInfoChar(buf, ')');
4363 if (!PRETTY_PAREN(context))
4364 appendStringInfoChar(buf, ')');
4366 break;
4368 case T_BoolExpr:
4370 BoolExpr *expr = (BoolExpr *) node;
4371 Node *first_arg = linitial(expr->args);
4372 ListCell *arg = lnext(list_head(expr->args));
4374 switch (expr->boolop)
4376 case AND_EXPR:
4377 if (!PRETTY_PAREN(context))
4378 appendStringInfoChar(buf, '(');
4379 get_rule_expr_paren(first_arg, context,
4380 false, node);
4381 while (arg)
4383 appendStringInfo(buf, " AND ");
4384 get_rule_expr_paren((Node *) lfirst(arg), context,
4385 false, node);
4386 arg = lnext(arg);
4388 if (!PRETTY_PAREN(context))
4389 appendStringInfoChar(buf, ')');
4390 break;
4392 case OR_EXPR:
4393 if (!PRETTY_PAREN(context))
4394 appendStringInfoChar(buf, '(');
4395 get_rule_expr_paren(first_arg, context,
4396 false, node);
4397 while (arg)
4399 appendStringInfo(buf, " OR ");
4400 get_rule_expr_paren((Node *) lfirst(arg), context,
4401 false, node);
4402 arg = lnext(arg);
4404 if (!PRETTY_PAREN(context))
4405 appendStringInfoChar(buf, ')');
4406 break;
4408 case NOT_EXPR:
4409 if (!PRETTY_PAREN(context))
4410 appendStringInfoChar(buf, '(');
4411 appendStringInfo(buf, "NOT ");
4412 get_rule_expr_paren(first_arg, context,
4413 false, node);
4414 if (!PRETTY_PAREN(context))
4415 appendStringInfoChar(buf, ')');
4416 break;
4418 default:
4419 elog(ERROR, "unrecognized boolop: %d",
4420 (int) expr->boolop);
4423 break;
4425 case T_SubLink:
4426 get_sublink_expr((SubLink *) node, context);
4427 break;
4429 case T_SubPlan:
4431 SubPlan *subplan = (SubPlan *) node;
4434 * We cannot see an already-planned subplan in rule deparsing,
4435 * only while EXPLAINing a query plan. We don't try to
4436 * reconstruct the original SQL, just reference the subplan
4437 * that appears elsewhere in EXPLAIN's result.
4439 if (subplan->useHashTable)
4440 appendStringInfo(buf, "(hashed %s)", subplan->plan_name);
4441 else
4442 appendStringInfo(buf, "(%s)", subplan->plan_name);
4444 break;
4446 case T_AlternativeSubPlan:
4448 AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
4449 ListCell *lc;
4451 /* As above, this can only happen during EXPLAIN */
4452 appendStringInfo(buf, "(alternatives: ");
4453 foreach(lc, asplan->subplans)
4455 SubPlan *splan = (SubPlan *) lfirst(lc);
4457 Assert(IsA(splan, SubPlan));
4458 if (splan->useHashTable)
4459 appendStringInfo(buf, "hashed %s", splan->plan_name);
4460 else
4461 appendStringInfo(buf, "%s", splan->plan_name);
4462 if (lnext(lc))
4463 appendStringInfo(buf, " or ");
4465 appendStringInfo(buf, ")");
4467 break;
4469 case T_FieldSelect:
4471 FieldSelect *fselect = (FieldSelect *) node;
4472 Node *arg = (Node *) fselect->arg;
4473 int fno = fselect->fieldnum;
4474 const char *fieldname;
4475 bool need_parens;
4478 * Parenthesize the argument unless it's an ArrayRef or
4479 * another FieldSelect. Note in particular that it would be
4480 * WRONG to not parenthesize a Var argument; simplicity is not
4481 * the issue here, having the right number of names is.
4483 need_parens = !IsA(arg, ArrayRef) &&!IsA(arg, FieldSelect);
4484 if (need_parens)
4485 appendStringInfoChar(buf, '(');
4486 get_rule_expr(arg, context, true);
4487 if (need_parens)
4488 appendStringInfoChar(buf, ')');
4491 * Get and print the field name.
4493 fieldname = get_name_for_var_field((Var *) arg, fno,
4494 0, context);
4495 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
4497 break;
4499 case T_FieldStore:
4502 * We shouldn't see FieldStore here; it should have been stripped
4503 * off by processIndirection().
4505 elog(ERROR, "unexpected FieldStore");
4506 break;
4508 case T_RelabelType:
4510 RelabelType *relabel = (RelabelType *) node;
4511 Node *arg = (Node *) relabel->arg;
4513 if (relabel->relabelformat == COERCE_IMPLICIT_CAST &&
4514 !showimplicit)
4516 /* don't show the implicit cast */
4517 get_rule_expr_paren(arg, context, false, node);
4519 else
4521 get_coercion_expr(arg, context,
4522 relabel->resulttype,
4523 relabel->resulttypmod,
4524 node);
4527 break;
4529 case T_CoerceViaIO:
4531 CoerceViaIO *iocoerce = (CoerceViaIO *) node;
4532 Node *arg = (Node *) iocoerce->arg;
4534 if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST &&
4535 !showimplicit)
4537 /* don't show the implicit cast */
4538 get_rule_expr_paren(arg, context, false, node);
4540 else
4542 get_coercion_expr(arg, context,
4543 iocoerce->resulttype,
4545 node);
4548 break;
4550 case T_ArrayCoerceExpr:
4552 ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
4553 Node *arg = (Node *) acoerce->arg;
4555 if (acoerce->coerceformat == COERCE_IMPLICIT_CAST &&
4556 !showimplicit)
4558 /* don't show the implicit cast */
4559 get_rule_expr_paren(arg, context, false, node);
4561 else
4563 get_coercion_expr(arg, context,
4564 acoerce->resulttype,
4565 acoerce->resulttypmod,
4566 node);
4569 break;
4571 case T_ConvertRowtypeExpr:
4573 ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
4574 Node *arg = (Node *) convert->arg;
4576 if (convert->convertformat == COERCE_IMPLICIT_CAST &&
4577 !showimplicit)
4579 /* don't show the implicit cast */
4580 get_rule_expr_paren(arg, context, false, node);
4582 else
4584 get_coercion_expr(arg, context,
4585 convert->resulttype, -1,
4586 node);
4589 break;
4591 case T_CaseExpr:
4593 CaseExpr *caseexpr = (CaseExpr *) node;
4594 ListCell *temp;
4596 appendContextKeyword(context, "CASE",
4597 0, PRETTYINDENT_VAR, 0);
4598 if (caseexpr->arg)
4600 appendStringInfoChar(buf, ' ');
4601 get_rule_expr((Node *) caseexpr->arg, context, true);
4603 foreach(temp, caseexpr->args)
4605 CaseWhen *when = (CaseWhen *) lfirst(temp);
4606 Node *w = (Node *) when->expr;
4608 if (!PRETTY_INDENT(context))
4609 appendStringInfoChar(buf, ' ');
4610 appendContextKeyword(context, "WHEN ",
4611 0, 0, 0);
4612 if (caseexpr->arg)
4615 * The parser should have produced WHEN clauses of the
4616 * form "CaseTestExpr = RHS"; we want to show just the
4617 * RHS. If the user wrote something silly like "CASE
4618 * boolexpr WHEN TRUE THEN ...", then the optimizer's
4619 * simplify_boolean_equality() may have reduced this
4620 * to just "CaseTestExpr" or "NOT CaseTestExpr", for
4621 * which we have to show "TRUE" or "FALSE". Also,
4622 * depending on context the original CaseTestExpr
4623 * might have been reduced to a Const (but we won't
4624 * see "WHEN Const"). We have also to consider the
4625 * possibility that an implicit coercion was inserted
4626 * between the CaseTestExpr and the operator.
4628 if (IsA(w, OpExpr))
4630 List *args = ((OpExpr *) w)->args;
4631 Node *lhs;
4632 Node *rhs;
4634 Assert(list_length(args) == 2);
4635 lhs = strip_implicit_coercions(linitial(args));
4636 Assert(IsA(lhs, CaseTestExpr) ||
4637 IsA(lhs, Const));
4638 rhs = (Node *) lsecond(args);
4639 get_rule_expr(rhs, context, false);
4641 else if (IsA(strip_implicit_coercions(w),
4642 CaseTestExpr))
4643 appendStringInfo(buf, "TRUE");
4644 else if (not_clause(w))
4646 Assert(IsA(strip_implicit_coercions((Node *) get_notclausearg((Expr *) w)),
4647 CaseTestExpr));
4648 appendStringInfo(buf, "FALSE");
4650 else
4651 elog(ERROR, "unexpected CASE WHEN clause: %d",
4652 (int) nodeTag(w));
4654 else
4655 get_rule_expr(w, context, false);
4656 appendStringInfo(buf, " THEN ");
4657 get_rule_expr((Node *) when->result, context, true);
4659 if (!PRETTY_INDENT(context))
4660 appendStringInfoChar(buf, ' ');
4661 appendContextKeyword(context, "ELSE ",
4662 0, 0, 0);
4663 get_rule_expr((Node *) caseexpr->defresult, context, true);
4664 if (!PRETTY_INDENT(context))
4665 appendStringInfoChar(buf, ' ');
4666 appendContextKeyword(context, "END",
4667 -PRETTYINDENT_VAR, 0, 0);
4669 break;
4671 case T_ArrayExpr:
4673 ArrayExpr *arrayexpr = (ArrayExpr *) node;
4675 appendStringInfo(buf, "ARRAY[");
4676 get_rule_expr((Node *) arrayexpr->elements, context, true);
4677 appendStringInfoChar(buf, ']');
4679 * If the array isn't empty, we assume its elements are
4680 * coerced to the desired type. If it's empty, though, we
4681 * need an explicit coercion to the array type.
4683 if (arrayexpr->elements == NIL)
4684 appendStringInfo(buf, "::%s",
4685 format_type_with_typemod(arrayexpr->array_typeid, -1));
4687 break;
4689 case T_RowExpr:
4691 RowExpr *rowexpr = (RowExpr *) node;
4692 TupleDesc tupdesc = NULL;
4693 ListCell *arg;
4694 int i;
4695 char *sep;
4698 * If it's a named type and not RECORD, we may have to skip
4699 * dropped columns and/or claim there are NULLs for added
4700 * columns.
4702 if (rowexpr->row_typeid != RECORDOID)
4704 tupdesc = lookup_rowtype_tupdesc(rowexpr->row_typeid, -1);
4705 Assert(list_length(rowexpr->args) <= tupdesc->natts);
4709 * SQL99 allows "ROW" to be omitted when there is more than
4710 * one column, but for simplicity we always print it.
4712 appendStringInfo(buf, "ROW(");
4713 sep = "";
4714 i = 0;
4715 foreach(arg, rowexpr->args)
4717 Node *e = (Node *) lfirst(arg);
4719 if (tupdesc == NULL ||
4720 !tupdesc->attrs[i]->attisdropped)
4722 appendStringInfoString(buf, sep);
4723 get_rule_expr(e, context, true);
4724 sep = ", ";
4726 i++;
4728 if (tupdesc != NULL)
4730 while (i < tupdesc->natts)
4732 if (!tupdesc->attrs[i]->attisdropped)
4734 appendStringInfoString(buf, sep);
4735 appendStringInfo(buf, "NULL");
4736 sep = ", ";
4738 i++;
4741 ReleaseTupleDesc(tupdesc);
4743 appendStringInfo(buf, ")");
4744 if (rowexpr->row_format == COERCE_EXPLICIT_CAST)
4745 appendStringInfo(buf, "::%s",
4746 format_type_with_typemod(rowexpr->row_typeid, -1));
4748 break;
4750 case T_RowCompareExpr:
4752 RowCompareExpr *rcexpr = (RowCompareExpr *) node;
4753 ListCell *arg;
4754 char *sep;
4757 * SQL99 allows "ROW" to be omitted when there is more than
4758 * one column, but for simplicity we always print it.
4760 appendStringInfo(buf, "(ROW(");
4761 sep = "";
4762 foreach(arg, rcexpr->largs)
4764 Node *e = (Node *) lfirst(arg);
4766 appendStringInfoString(buf, sep);
4767 get_rule_expr(e, context, true);
4768 sep = ", ";
4772 * We assume that the name of the first-column operator will
4773 * do for all the rest too. This is definitely open to
4774 * failure, eg if some but not all operators were renamed
4775 * since the construct was parsed, but there seems no way to
4776 * be perfect.
4778 appendStringInfo(buf, ") %s ROW(",
4779 generate_operator_name(linitial_oid(rcexpr->opnos),
4780 exprType(linitial(rcexpr->largs)),
4781 exprType(linitial(rcexpr->rargs))));
4782 sep = "";
4783 foreach(arg, rcexpr->rargs)
4785 Node *e = (Node *) lfirst(arg);
4787 appendStringInfoString(buf, sep);
4788 get_rule_expr(e, context, true);
4789 sep = ", ";
4791 appendStringInfo(buf, "))");
4793 break;
4795 case T_CoalesceExpr:
4797 CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
4799 appendStringInfo(buf, "COALESCE(");
4800 get_rule_expr((Node *) coalesceexpr->args, context, true);
4801 appendStringInfoChar(buf, ')');
4803 break;
4805 case T_MinMaxExpr:
4807 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
4809 switch (minmaxexpr->op)
4811 case IS_GREATEST:
4812 appendStringInfo(buf, "GREATEST(");
4813 break;
4814 case IS_LEAST:
4815 appendStringInfo(buf, "LEAST(");
4816 break;
4818 get_rule_expr((Node *) minmaxexpr->args, context, true);
4819 appendStringInfoChar(buf, ')');
4821 break;
4823 case T_XmlExpr:
4825 XmlExpr *xexpr = (XmlExpr *) node;
4826 bool needcomma = false;
4827 ListCell *arg;
4828 ListCell *narg;
4829 Const *con;
4831 switch (xexpr->op)
4833 case IS_XMLCONCAT:
4834 appendStringInfoString(buf, "XMLCONCAT(");
4835 break;
4836 case IS_XMLELEMENT:
4837 appendStringInfoString(buf, "XMLELEMENT(");
4838 break;
4839 case IS_XMLFOREST:
4840 appendStringInfoString(buf, "XMLFOREST(");
4841 break;
4842 case IS_XMLPARSE:
4843 appendStringInfoString(buf, "XMLPARSE(");
4844 break;
4845 case IS_XMLPI:
4846 appendStringInfoString(buf, "XMLPI(");
4847 break;
4848 case IS_XMLROOT:
4849 appendStringInfoString(buf, "XMLROOT(");
4850 break;
4851 case IS_XMLSERIALIZE:
4852 appendStringInfoString(buf, "XMLSERIALIZE(");
4853 break;
4854 case IS_DOCUMENT:
4855 break;
4857 if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
4859 if (xexpr->xmloption == XMLOPTION_DOCUMENT)
4860 appendStringInfoString(buf, "DOCUMENT ");
4861 else
4862 appendStringInfoString(buf, "CONTENT ");
4864 if (xexpr->name)
4866 appendStringInfo(buf, "NAME %s",
4867 quote_identifier(map_xml_name_to_sql_identifier(xexpr->name)));
4868 needcomma = true;
4870 if (xexpr->named_args)
4872 if (xexpr->op != IS_XMLFOREST)
4874 if (needcomma)
4875 appendStringInfoString(buf, ", ");
4876 appendStringInfoString(buf, "XMLATTRIBUTES(");
4877 needcomma = false;
4879 forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
4881 Node *e = (Node *) lfirst(arg);
4882 char *argname = strVal(lfirst(narg));
4884 if (needcomma)
4885 appendStringInfoString(buf, ", ");
4886 get_rule_expr((Node *) e, context, true);
4887 appendStringInfo(buf, " AS %s",
4888 quote_identifier(map_xml_name_to_sql_identifier(argname)));
4889 needcomma = true;
4891 if (xexpr->op != IS_XMLFOREST)
4892 appendStringInfoChar(buf, ')');
4894 if (xexpr->args)
4896 if (needcomma)
4897 appendStringInfoString(buf, ", ");
4898 switch (xexpr->op)
4900 case IS_XMLCONCAT:
4901 case IS_XMLELEMENT:
4902 case IS_XMLFOREST:
4903 case IS_XMLPI:
4904 case IS_XMLSERIALIZE:
4905 /* no extra decoration needed */
4906 get_rule_expr((Node *) xexpr->args, context, true);
4907 break;
4908 case IS_XMLPARSE:
4909 Assert(list_length(xexpr->args) == 2);
4911 get_rule_expr((Node *) linitial(xexpr->args),
4912 context, true);
4914 con = (Const *) lsecond(xexpr->args);
4915 Assert(IsA(con, Const));
4916 Assert(!con->constisnull);
4917 if (DatumGetBool(con->constvalue))
4918 appendStringInfoString(buf,
4919 " PRESERVE WHITESPACE");
4920 else
4921 appendStringInfoString(buf,
4922 " STRIP WHITESPACE");
4923 break;
4924 case IS_XMLROOT:
4925 Assert(list_length(xexpr->args) == 3);
4927 get_rule_expr((Node *) linitial(xexpr->args),
4928 context, true);
4930 appendStringInfoString(buf, ", VERSION ");
4931 con = (Const *) lsecond(xexpr->args);
4932 if (IsA(con, Const) &&
4933 con->constisnull)
4934 appendStringInfoString(buf, "NO VALUE");
4935 else
4936 get_rule_expr((Node *) con, context, false);
4938 con = (Const *) lthird(xexpr->args);
4939 Assert(IsA(con, Const));
4940 if (con->constisnull)
4941 /* suppress STANDALONE NO VALUE */ ;
4942 else
4944 switch (DatumGetInt32(con->constvalue))
4946 case XML_STANDALONE_YES:
4947 appendStringInfoString(buf,
4948 ", STANDALONE YES");
4949 break;
4950 case XML_STANDALONE_NO:
4951 appendStringInfoString(buf,
4952 ", STANDALONE NO");
4953 break;
4954 case XML_STANDALONE_NO_VALUE:
4955 appendStringInfoString(buf,
4956 ", STANDALONE NO VALUE");
4957 break;
4958 default:
4959 break;
4962 break;
4963 case IS_DOCUMENT:
4964 get_rule_expr_paren((Node *) xexpr->args, context, false, node);
4965 break;
4969 if (xexpr->op == IS_XMLSERIALIZE)
4970 appendStringInfo(buf, " AS %s", format_type_with_typemod(xexpr->type,
4971 xexpr->typmod));
4972 if (xexpr->op == IS_DOCUMENT)
4973 appendStringInfoString(buf, " IS DOCUMENT");
4974 else
4975 appendStringInfoChar(buf, ')');
4977 break;
4979 case T_NullIfExpr:
4981 NullIfExpr *nullifexpr = (NullIfExpr *) node;
4983 appendStringInfo(buf, "NULLIF(");
4984 get_rule_expr((Node *) nullifexpr->args, context, true);
4985 appendStringInfoChar(buf, ')');
4987 break;
4989 case T_NullTest:
4991 NullTest *ntest = (NullTest *) node;
4993 if (!PRETTY_PAREN(context))
4994 appendStringInfoChar(buf, '(');
4995 get_rule_expr_paren((Node *) ntest->arg, context, true, node);
4996 switch (ntest->nulltesttype)
4998 case IS_NULL:
4999 appendStringInfo(buf, " IS NULL");
5000 break;
5001 case IS_NOT_NULL:
5002 appendStringInfo(buf, " IS NOT NULL");
5003 break;
5004 default:
5005 elog(ERROR, "unrecognized nulltesttype: %d",
5006 (int) ntest->nulltesttype);
5008 if (!PRETTY_PAREN(context))
5009 appendStringInfoChar(buf, ')');
5011 break;
5013 case T_BooleanTest:
5015 BooleanTest *btest = (BooleanTest *) node;
5017 if (!PRETTY_PAREN(context))
5018 appendStringInfoChar(buf, '(');
5019 get_rule_expr_paren((Node *) btest->arg, context, false, node);
5020 switch (btest->booltesttype)
5022 case IS_TRUE:
5023 appendStringInfo(buf, " IS TRUE");
5024 break;
5025 case IS_NOT_TRUE:
5026 appendStringInfo(buf, " IS NOT TRUE");
5027 break;
5028 case IS_FALSE:
5029 appendStringInfo(buf, " IS FALSE");
5030 break;
5031 case IS_NOT_FALSE:
5032 appendStringInfo(buf, " IS NOT FALSE");
5033 break;
5034 case IS_UNKNOWN:
5035 appendStringInfo(buf, " IS UNKNOWN");
5036 break;
5037 case IS_NOT_UNKNOWN:
5038 appendStringInfo(buf, " IS NOT UNKNOWN");
5039 break;
5040 default:
5041 elog(ERROR, "unrecognized booltesttype: %d",
5042 (int) btest->booltesttype);
5044 if (!PRETTY_PAREN(context))
5045 appendStringInfoChar(buf, ')');
5047 break;
5049 case T_CoerceToDomain:
5051 CoerceToDomain *ctest = (CoerceToDomain *) node;
5052 Node *arg = (Node *) ctest->arg;
5054 if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
5055 !showimplicit)
5057 /* don't show the implicit cast */
5058 get_rule_expr(arg, context, false);
5060 else
5062 get_coercion_expr(arg, context,
5063 ctest->resulttype,
5064 ctest->resulttypmod,
5065 node);
5068 break;
5070 case T_CoerceToDomainValue:
5071 appendStringInfo(buf, "VALUE");
5072 break;
5074 case T_SetToDefault:
5075 appendStringInfo(buf, "DEFAULT");
5076 break;
5078 case T_CurrentOfExpr:
5080 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
5082 if (cexpr->cursor_name)
5083 appendStringInfo(buf, "CURRENT OF %s",
5084 quote_identifier(cexpr->cursor_name));
5085 else
5086 appendStringInfo(buf, "CURRENT OF $%d",
5087 cexpr->cursor_param);
5089 break;
5091 case T_List:
5093 char *sep;
5094 ListCell *l;
5096 sep = "";
5097 foreach(l, (List *) node)
5099 appendStringInfoString(buf, sep);
5100 get_rule_expr((Node *) lfirst(l), context, showimplicit);
5101 sep = ", ";
5104 break;
5106 default:
5107 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
5108 break;
5114 * get_oper_expr - Parse back an OpExpr node
5116 static void
5117 get_oper_expr(OpExpr *expr, deparse_context *context)
5119 StringInfo buf = context->buf;
5120 Oid opno = expr->opno;
5121 List *args = expr->args;
5123 if (!PRETTY_PAREN(context))
5124 appendStringInfoChar(buf, '(');
5125 if (list_length(args) == 2)
5127 /* binary operator */
5128 Node *arg1 = (Node *) linitial(args);
5129 Node *arg2 = (Node *) lsecond(args);
5131 get_rule_expr_paren(arg1, context, true, (Node *) expr);
5132 appendStringInfo(buf, " %s ",
5133 generate_operator_name(opno,
5134 exprType(arg1),
5135 exprType(arg2)));
5136 get_rule_expr_paren(arg2, context, true, (Node *) expr);
5138 else
5140 /* unary operator --- but which side? */
5141 Node *arg = (Node *) linitial(args);
5142 HeapTuple tp;
5143 Form_pg_operator optup;
5145 tp = SearchSysCache(OPEROID,
5146 ObjectIdGetDatum(opno),
5147 0, 0, 0);
5148 if (!HeapTupleIsValid(tp))
5149 elog(ERROR, "cache lookup failed for operator %u", opno);
5150 optup = (Form_pg_operator) GETSTRUCT(tp);
5151 switch (optup->oprkind)
5153 case 'l':
5154 appendStringInfo(buf, "%s ",
5155 generate_operator_name(opno,
5156 InvalidOid,
5157 exprType(arg)));
5158 get_rule_expr_paren(arg, context, true, (Node *) expr);
5159 break;
5160 case 'r':
5161 get_rule_expr_paren(arg, context, true, (Node *) expr);
5162 appendStringInfo(buf, " %s",
5163 generate_operator_name(opno,
5164 exprType(arg),
5165 InvalidOid));
5166 break;
5167 default:
5168 elog(ERROR, "bogus oprkind: %d", optup->oprkind);
5170 ReleaseSysCache(tp);
5172 if (!PRETTY_PAREN(context))
5173 appendStringInfoChar(buf, ')');
5177 * get_func_expr - Parse back a FuncExpr node
5179 static void
5180 get_func_expr(FuncExpr *expr, deparse_context *context,
5181 bool showimplicit)
5183 StringInfo buf = context->buf;
5184 Oid funcoid = expr->funcid;
5185 Oid argtypes[FUNC_MAX_ARGS];
5186 int nargs;
5187 bool is_variadic;
5188 ListCell *l;
5191 * If the function call came from an implicit coercion, then just show the
5192 * first argument --- unless caller wants to see implicit coercions.
5194 if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
5196 get_rule_expr_paren((Node *) linitial(expr->args), context,
5197 false, (Node *) expr);
5198 return;
5202 * If the function call came from a cast, then show the first argument
5203 * plus an explicit cast operation.
5205 if (expr->funcformat == COERCE_EXPLICIT_CAST ||
5206 expr->funcformat == COERCE_IMPLICIT_CAST)
5208 Node *arg = linitial(expr->args);
5209 Oid rettype = expr->funcresulttype;
5210 int32 coercedTypmod;
5212 /* Get the typmod if this is a length-coercion function */
5213 (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
5215 get_coercion_expr(arg, context,
5216 rettype, coercedTypmod,
5217 (Node *) expr);
5219 return;
5223 * Normal function: display as proname(args). First we need to extract
5224 * the argument datatypes.
5226 if (list_length(expr->args) > FUNC_MAX_ARGS)
5227 ereport(ERROR,
5228 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5229 errmsg("too many arguments")));
5230 nargs = 0;
5231 foreach(l, expr->args)
5233 argtypes[nargs] = exprType((Node *) lfirst(l));
5234 nargs++;
5237 appendStringInfo(buf, "%s(",
5238 generate_function_name(funcoid, nargs, argtypes,
5239 &is_variadic));
5240 nargs = 0;
5241 foreach(l, expr->args)
5243 if (nargs++ > 0)
5244 appendStringInfoString(buf, ", ");
5245 if (is_variadic && lnext(l) == NULL)
5246 appendStringInfoString(buf, "VARIADIC ");
5247 get_rule_expr((Node *) lfirst(l), context, true);
5249 appendStringInfoChar(buf, ')');
5253 * get_agg_expr - Parse back an Aggref node
5255 static void
5256 get_agg_expr(Aggref *aggref, deparse_context *context)
5258 StringInfo buf = context->buf;
5259 Oid argtypes[FUNC_MAX_ARGS];
5260 int nargs;
5261 ListCell *l;
5263 if (list_length(aggref->args) > FUNC_MAX_ARGS)
5264 ereport(ERROR,
5265 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5266 errmsg("too many arguments")));
5267 nargs = 0;
5268 foreach(l, aggref->args)
5270 argtypes[nargs] = exprType((Node *) lfirst(l));
5271 nargs++;
5274 appendStringInfo(buf, "%s(%s",
5275 generate_function_name(aggref->aggfnoid,
5276 nargs, argtypes, NULL),
5277 aggref->aggdistinct ? "DISTINCT " : "");
5278 /* aggstar can be set only in zero-argument aggregates */
5279 if (aggref->aggstar)
5280 appendStringInfoChar(buf, '*');
5281 else
5282 get_rule_expr((Node *) aggref->args, context, true);
5283 appendStringInfoChar(buf, ')');
5287 * get_windowfunc_expr - Parse back a WindowFunc node
5289 static void
5290 get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
5292 StringInfo buf = context->buf;
5293 Oid argtypes[FUNC_MAX_ARGS];
5294 int nargs;
5295 ListCell *l;
5297 if (list_length(wfunc->args) > FUNC_MAX_ARGS)
5298 ereport(ERROR,
5299 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
5300 errmsg("too many arguments")));
5301 nargs = 0;
5302 foreach(l, wfunc->args)
5304 argtypes[nargs] = exprType((Node *) lfirst(l));
5305 nargs++;
5308 appendStringInfo(buf, "%s(%s",
5309 generate_function_name(wfunc->winfnoid,
5310 nargs, argtypes, NULL), "");
5311 /* winstar can be set only in zero-argument aggregates */
5312 if (wfunc->winstar)
5313 appendStringInfoChar(buf, '*');
5314 else
5315 get_rule_expr((Node *) wfunc->args, context, true);
5316 appendStringInfoString(buf, ") OVER ");
5318 foreach(l, context->windowClause)
5320 WindowClause *wc = (WindowClause *) lfirst(l);
5322 if (wc->winref == wfunc->winref)
5324 if (wc->name)
5325 appendStringInfoString(buf, quote_identifier(wc->name));
5326 else
5327 get_rule_windowspec(wc, context->windowTList, context);
5328 break;
5331 if (l == NULL)
5333 if (context->windowClause)
5334 elog(ERROR, "could not find window clause for winref %u",
5335 wfunc->winref);
5337 * In EXPLAIN, we don't have window context information available,
5338 * so we have to settle for this:
5340 appendStringInfoString(buf, "(?)");
5344 /* ----------
5345 * get_coercion_expr
5347 * Make a string representation of a value coerced to a specific type
5348 * ----------
5350 static void
5351 get_coercion_expr(Node *arg, deparse_context *context,
5352 Oid resulttype, int32 resulttypmod,
5353 Node *parentNode)
5355 StringInfo buf = context->buf;
5358 * Since parse_coerce.c doesn't immediately collapse application of
5359 * length-coercion functions to constants, what we'll typically see in
5360 * such cases is a Const with typmod -1 and a length-coercion function
5361 * right above it. Avoid generating redundant output. However, beware of
5362 * suppressing casts when the user actually wrote something like
5363 * 'foo'::text::char(3).
5365 if (arg && IsA(arg, Const) &&
5366 ((Const *) arg)->consttype == resulttype &&
5367 ((Const *) arg)->consttypmod == -1)
5369 /* Show the constant without normal ::typename decoration */
5370 get_const_expr((Const *) arg, context, -1);
5372 else
5374 if (!PRETTY_PAREN(context))
5375 appendStringInfoChar(buf, '(');
5376 get_rule_expr_paren(arg, context, false, parentNode);
5377 if (!PRETTY_PAREN(context))
5378 appendStringInfoChar(buf, ')');
5380 appendStringInfo(buf, "::%s",
5381 format_type_with_typemod(resulttype, resulttypmod));
5384 /* ----------
5385 * get_const_expr
5387 * Make a string representation of a Const
5389 * showtype can be -1 to never show "::typename" decoration, or +1 to always
5390 * show it, or 0 to show it only if the constant wouldn't be assumed to be
5391 * the right type by default.
5392 * ----------
5394 static void
5395 get_const_expr(Const *constval, deparse_context *context, int showtype)
5397 StringInfo buf = context->buf;
5398 Oid typoutput;
5399 bool typIsVarlena;
5400 char *extval;
5401 bool isfloat = false;
5402 bool needlabel;
5404 if (constval->constisnull)
5407 * Always label the type of a NULL constant to prevent misdecisions
5408 * about type when reparsing.
5410 appendStringInfo(buf, "NULL");
5411 if (showtype >= 0)
5412 appendStringInfo(buf, "::%s",
5413 format_type_with_typemod(constval->consttype,
5414 constval->consttypmod));
5415 return;
5418 getTypeOutputInfo(constval->consttype,
5419 &typoutput, &typIsVarlena);
5421 extval = OidOutputFunctionCall(typoutput, constval->constvalue);
5423 switch (constval->consttype)
5425 case INT2OID:
5426 case INT4OID:
5427 case INT8OID:
5428 case OIDOID:
5429 case FLOAT4OID:
5430 case FLOAT8OID:
5431 case NUMERICOID:
5434 * These types are printed without quotes unless they contain
5435 * values that aren't accepted by the scanner unquoted (e.g.,
5436 * 'NaN'). Note that strtod() and friends might accept NaN,
5437 * so we can't use that to test.
5439 * In reality we only need to defend against infinity and NaN,
5440 * so we need not get too crazy about pattern matching here.
5442 * There is a special-case gotcha: if the constant is signed,
5443 * we need to parenthesize it, else the parser might see a
5444 * leading plus/minus as binding less tightly than adjacent
5445 * operators --- particularly, the cast that we might attach
5446 * below.
5448 if (strspn(extval, "0123456789+-eE.") == strlen(extval))
5450 if (extval[0] == '+' || extval[0] == '-')
5451 appendStringInfo(buf, "(%s)", extval);
5452 else
5453 appendStringInfoString(buf, extval);
5454 if (strcspn(extval, "eE.") != strlen(extval))
5455 isfloat = true; /* it looks like a float */
5457 else
5458 appendStringInfo(buf, "'%s'", extval);
5460 break;
5462 case BITOID:
5463 case VARBITOID:
5464 appendStringInfo(buf, "B'%s'", extval);
5465 break;
5467 case BOOLOID:
5468 if (strcmp(extval, "t") == 0)
5469 appendStringInfo(buf, "true");
5470 else
5471 appendStringInfo(buf, "false");
5472 break;
5474 default:
5475 simple_quote_literal(buf, extval);
5476 break;
5479 pfree(extval);
5481 if (showtype < 0)
5482 return;
5485 * For showtype == 0, append ::typename unless the constant will be
5486 * implicitly typed as the right type when it is read in.
5488 * XXX this code has to be kept in sync with the behavior of the parser,
5489 * especially make_const.
5491 switch (constval->consttype)
5493 case BOOLOID:
5494 case INT4OID:
5495 case UNKNOWNOID:
5496 /* These types can be left unlabeled */
5497 needlabel = false;
5498 break;
5499 case NUMERICOID:
5502 * Float-looking constants will be typed as numeric, but if
5503 * there's a specific typmod we need to show it.
5505 needlabel = !isfloat || (constval->consttypmod >= 0);
5506 break;
5507 default:
5508 needlabel = true;
5509 break;
5511 if (needlabel || showtype > 0)
5512 appendStringInfo(buf, "::%s",
5513 format_type_with_typemod(constval->consttype,
5514 constval->consttypmod));
5518 * simple_quote_literal - Format a string as a SQL literal, append to buf
5520 static void
5521 simple_quote_literal(StringInfo buf, const char *val)
5523 const char *valptr;
5526 * We form the string literal according to the prevailing setting
5527 * of standard_conforming_strings; we never use E''. User is
5528 * responsible for making sure result is used correctly.
5530 appendStringInfoChar(buf, '\'');
5531 for (valptr = val; *valptr; valptr++)
5533 char ch = *valptr;
5535 if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
5536 appendStringInfoChar(buf, ch);
5537 appendStringInfoChar(buf, ch);
5539 appendStringInfoChar(buf, '\'');
5543 /* ----------
5544 * get_sublink_expr - Parse back a sublink
5545 * ----------
5547 static void
5548 get_sublink_expr(SubLink *sublink, deparse_context *context)
5550 StringInfo buf = context->buf;
5551 Query *query = (Query *) (sublink->subselect);
5552 char *opname = NULL;
5553 bool need_paren;
5555 if (sublink->subLinkType == ARRAY_SUBLINK)
5556 appendStringInfo(buf, "ARRAY(");
5557 else
5558 appendStringInfoChar(buf, '(');
5561 * Note that we print the name of only the first operator, when there are
5562 * multiple combining operators. This is an approximation that could go
5563 * wrong in various scenarios (operators in different schemas, renamed
5564 * operators, etc) but there is not a whole lot we can do about it, since
5565 * the syntax allows only one operator to be shown.
5567 if (sublink->testexpr)
5569 if (IsA(sublink->testexpr, OpExpr))
5571 /* single combining operator */
5572 OpExpr *opexpr = (OpExpr *) sublink->testexpr;
5574 get_rule_expr(linitial(opexpr->args), context, true);
5575 opname = generate_operator_name(opexpr->opno,
5576 exprType(linitial(opexpr->args)),
5577 exprType(lsecond(opexpr->args)));
5579 else if (IsA(sublink->testexpr, BoolExpr))
5581 /* multiple combining operators, = or <> cases */
5582 char *sep;
5583 ListCell *l;
5585 appendStringInfoChar(buf, '(');
5586 sep = "";
5587 foreach(l, ((BoolExpr *) sublink->testexpr)->args)
5589 OpExpr *opexpr = (OpExpr *) lfirst(l);
5591 Assert(IsA(opexpr, OpExpr));
5592 appendStringInfoString(buf, sep);
5593 get_rule_expr(linitial(opexpr->args), context, true);
5594 if (!opname)
5595 opname = generate_operator_name(opexpr->opno,
5596 exprType(linitial(opexpr->args)),
5597 exprType(lsecond(opexpr->args)));
5598 sep = ", ";
5600 appendStringInfoChar(buf, ')');
5602 else if (IsA(sublink->testexpr, RowCompareExpr))
5604 /* multiple combining operators, < <= > >= cases */
5605 RowCompareExpr *rcexpr = (RowCompareExpr *) sublink->testexpr;
5607 appendStringInfoChar(buf, '(');
5608 get_rule_expr((Node *) rcexpr->largs, context, true);
5609 opname = generate_operator_name(linitial_oid(rcexpr->opnos),
5610 exprType(linitial(rcexpr->largs)),
5611 exprType(linitial(rcexpr->rargs)));
5612 appendStringInfoChar(buf, ')');
5614 else
5615 elog(ERROR, "unrecognized testexpr type: %d",
5616 (int) nodeTag(sublink->testexpr));
5619 need_paren = true;
5621 switch (sublink->subLinkType)
5623 case EXISTS_SUBLINK:
5624 appendStringInfo(buf, "EXISTS ");
5625 break;
5627 case ANY_SUBLINK:
5628 if (strcmp(opname, "=") == 0) /* Represent = ANY as IN */
5629 appendStringInfo(buf, " IN ");
5630 else
5631 appendStringInfo(buf, " %s ANY ", opname);
5632 break;
5634 case ALL_SUBLINK:
5635 appendStringInfo(buf, " %s ALL ", opname);
5636 break;
5638 case ROWCOMPARE_SUBLINK:
5639 appendStringInfo(buf, " %s ", opname);
5640 break;
5642 case EXPR_SUBLINK:
5643 case ARRAY_SUBLINK:
5644 need_paren = false;
5645 break;
5647 case CTE_SUBLINK: /* shouldn't occur in a SubLink */
5648 default:
5649 elog(ERROR, "unrecognized sublink type: %d",
5650 (int) sublink->subLinkType);
5651 break;
5654 if (need_paren)
5655 appendStringInfoChar(buf, '(');
5657 get_query_def(query, buf, context->namespaces, NULL,
5658 context->prettyFlags, context->indentLevel);
5660 if (need_paren)
5661 appendStringInfo(buf, "))");
5662 else
5663 appendStringInfoChar(buf, ')');
5667 /* ----------
5668 * get_from_clause - Parse back a FROM clause
5670 * "prefix" is the keyword that denotes the start of the list of FROM
5671 * elements. It is FROM when used to parse back SELECT and UPDATE, but
5672 * is USING when parsing back DELETE.
5673 * ----------
5675 static void
5676 get_from_clause(Query *query, const char *prefix, deparse_context *context)
5678 StringInfo buf = context->buf;
5679 bool first = true;
5680 ListCell *l;
5683 * We use the query's jointree as a guide to what to print. However, we
5684 * must ignore auto-added RTEs that are marked not inFromCl. (These can
5685 * only appear at the top level of the jointree, so it's sufficient to
5686 * check here.) This check also ensures we ignore the rule pseudo-RTEs
5687 * for NEW and OLD.
5689 foreach(l, query->jointree->fromlist)
5691 Node *jtnode = (Node *) lfirst(l);
5693 if (IsA(jtnode, RangeTblRef))
5695 int varno = ((RangeTblRef *) jtnode)->rtindex;
5696 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
5698 if (!rte->inFromCl)
5699 continue;
5702 if (first)
5704 appendContextKeyword(context, prefix,
5705 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
5706 first = false;
5708 else
5709 appendStringInfoString(buf, ", ");
5711 get_from_clause_item(jtnode, query, context);
5715 static void
5716 get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
5718 StringInfo buf = context->buf;
5720 if (IsA(jtnode, RangeTblRef))
5722 int varno = ((RangeTblRef *) jtnode)->rtindex;
5723 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
5724 bool gavealias = false;
5726 switch (rte->rtekind)
5728 case RTE_RELATION:
5729 /* Normal relation RTE */
5730 appendStringInfo(buf, "%s%s",
5731 only_marker(rte),
5732 generate_relation_name(rte->relid,
5733 context->namespaces));
5734 break;
5735 case RTE_SUBQUERY:
5736 /* Subquery RTE */
5737 appendStringInfoChar(buf, '(');
5738 get_query_def(rte->subquery, buf, context->namespaces, NULL,
5739 context->prettyFlags, context->indentLevel);
5740 appendStringInfoChar(buf, ')');
5741 break;
5742 case RTE_FUNCTION:
5743 /* Function RTE */
5744 get_rule_expr(rte->funcexpr, context, true);
5745 break;
5746 case RTE_VALUES:
5747 /* Values list RTE */
5748 get_values_def(rte->values_lists, context);
5749 break;
5750 case RTE_CTE:
5751 appendStringInfoString(buf, quote_identifier(rte->ctename));
5752 break;
5753 default:
5754 elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
5755 break;
5758 if (rte->alias != NULL)
5760 appendStringInfo(buf, " %s",
5761 quote_identifier(rte->alias->aliasname));
5762 gavealias = true;
5764 else if (rte->rtekind == RTE_RELATION &&
5765 strcmp(rte->eref->aliasname, get_rel_name(rte->relid)) != 0)
5768 * Apparently the rel has been renamed since the rule was made.
5769 * Emit a fake alias clause so that variable references will still
5770 * work. This is not a 100% solution but should work in most
5771 * reasonable situations.
5773 appendStringInfo(buf, " %s",
5774 quote_identifier(rte->eref->aliasname));
5775 gavealias = true;
5777 else if (rte->rtekind == RTE_FUNCTION)
5780 * For a function RTE, always give an alias. This covers possible
5781 * renaming of the function and/or instability of the
5782 * FigureColname rules for things that aren't simple functions.
5784 appendStringInfo(buf, " %s",
5785 quote_identifier(rte->eref->aliasname));
5786 gavealias = true;
5789 if (rte->rtekind == RTE_FUNCTION)
5791 if (rte->funccoltypes != NIL)
5793 /* Function returning RECORD, reconstruct the columndefs */
5794 if (!gavealias)
5795 appendStringInfo(buf, " AS ");
5796 get_from_clause_coldeflist(rte->eref->colnames,
5797 rte->funccoltypes,
5798 rte->funccoltypmods,
5799 context);
5801 else
5804 * For a function RTE, always emit a complete column alias
5805 * list; this is to protect against possible instability of
5806 * the default column names (eg, from altering parameter
5807 * names).
5809 get_from_clause_alias(rte->eref, rte, context);
5812 else
5815 * For non-function RTEs, just report whatever the user originally
5816 * gave as column aliases.
5818 get_from_clause_alias(rte->alias, rte, context);
5821 else if (IsA(jtnode, JoinExpr))
5823 JoinExpr *j = (JoinExpr *) jtnode;
5824 bool need_paren_on_right;
5826 need_paren_on_right = PRETTY_PAREN(context) &&
5827 !IsA(j->rarg, RangeTblRef) &&
5828 !(IsA(j->rarg, JoinExpr) &&((JoinExpr *) j->rarg)->alias != NULL);
5830 if (!PRETTY_PAREN(context) || j->alias != NULL)
5831 appendStringInfoChar(buf, '(');
5833 get_from_clause_item(j->larg, query, context);
5835 if (j->isNatural)
5837 if (!PRETTY_INDENT(context))
5838 appendStringInfoChar(buf, ' ');
5839 switch (j->jointype)
5841 case JOIN_INNER:
5842 appendContextKeyword(context, "NATURAL JOIN ",
5843 -PRETTYINDENT_JOIN,
5844 PRETTYINDENT_JOIN, 0);
5845 break;
5846 case JOIN_LEFT:
5847 appendContextKeyword(context, "NATURAL LEFT JOIN ",
5848 -PRETTYINDENT_JOIN,
5849 PRETTYINDENT_JOIN, 0);
5850 break;
5851 case JOIN_FULL:
5852 appendContextKeyword(context, "NATURAL FULL JOIN ",
5853 -PRETTYINDENT_JOIN,
5854 PRETTYINDENT_JOIN, 0);
5855 break;
5856 case JOIN_RIGHT:
5857 appendContextKeyword(context, "NATURAL RIGHT JOIN ",
5858 -PRETTYINDENT_JOIN,
5859 PRETTYINDENT_JOIN, 0);
5860 break;
5861 default:
5862 elog(ERROR, "unrecognized join type: %d",
5863 (int) j->jointype);
5866 else
5868 switch (j->jointype)
5870 case JOIN_INNER:
5871 if (j->quals)
5872 appendContextKeyword(context, " JOIN ",
5873 -PRETTYINDENT_JOIN,
5874 PRETTYINDENT_JOIN, 2);
5875 else
5876 appendContextKeyword(context, " CROSS JOIN ",
5877 -PRETTYINDENT_JOIN,
5878 PRETTYINDENT_JOIN, 1);
5879 break;
5880 case JOIN_LEFT:
5881 appendContextKeyword(context, " LEFT JOIN ",
5882 -PRETTYINDENT_JOIN,
5883 PRETTYINDENT_JOIN, 2);
5884 break;
5885 case JOIN_FULL:
5886 appendContextKeyword(context, " FULL JOIN ",
5887 -PRETTYINDENT_JOIN,
5888 PRETTYINDENT_JOIN, 2);
5889 break;
5890 case JOIN_RIGHT:
5891 appendContextKeyword(context, " RIGHT JOIN ",
5892 -PRETTYINDENT_JOIN,
5893 PRETTYINDENT_JOIN, 2);
5894 break;
5895 default:
5896 elog(ERROR, "unrecognized join type: %d",
5897 (int) j->jointype);
5901 if (need_paren_on_right)
5902 appendStringInfoChar(buf, '(');
5903 get_from_clause_item(j->rarg, query, context);
5904 if (need_paren_on_right)
5905 appendStringInfoChar(buf, ')');
5907 context->indentLevel -= PRETTYINDENT_JOIN_ON;
5909 if (!j->isNatural)
5911 if (j->using)
5913 ListCell *col;
5915 appendStringInfo(buf, " USING (");
5916 foreach(col, j->using)
5918 if (col != list_head(j->using))
5919 appendStringInfo(buf, ", ");
5920 appendStringInfoString(buf,
5921 quote_identifier(strVal(lfirst(col))));
5923 appendStringInfoChar(buf, ')');
5925 else if (j->quals)
5927 appendStringInfo(buf, " ON ");
5928 if (!PRETTY_PAREN(context))
5929 appendStringInfoChar(buf, '(');
5930 get_rule_expr(j->quals, context, false);
5931 if (!PRETTY_PAREN(context))
5932 appendStringInfoChar(buf, ')');
5935 if (!PRETTY_PAREN(context) || j->alias != NULL)
5936 appendStringInfoChar(buf, ')');
5938 /* Yes, it's correct to put alias after the right paren ... */
5939 if (j->alias != NULL)
5941 appendStringInfo(buf, " %s",
5942 quote_identifier(j->alias->aliasname));
5943 get_from_clause_alias(j->alias,
5944 rt_fetch(j->rtindex, query->rtable),
5945 context);
5948 else
5949 elog(ERROR, "unrecognized node type: %d",
5950 (int) nodeTag(jtnode));
5954 * get_from_clause_alias - reproduce column alias list
5956 * This is tricky because we must ignore dropped columns.
5958 static void
5959 get_from_clause_alias(Alias *alias, RangeTblEntry *rte,
5960 deparse_context *context)
5962 StringInfo buf = context->buf;
5963 ListCell *col;
5964 AttrNumber attnum;
5965 bool first = true;
5967 if (alias == NULL || alias->colnames == NIL)
5968 return; /* definitely nothing to do */
5970 attnum = 0;
5971 foreach(col, alias->colnames)
5973 attnum++;
5974 if (get_rte_attribute_is_dropped(rte, attnum))
5975 continue;
5976 if (first)
5978 appendStringInfoChar(buf, '(');
5979 first = false;
5981 else
5982 appendStringInfo(buf, ", ");
5983 appendStringInfoString(buf,
5984 quote_identifier(strVal(lfirst(col))));
5986 if (!first)
5987 appendStringInfoChar(buf, ')');
5991 * get_from_clause_coldeflist - reproduce FROM clause coldeflist
5993 * The coldeflist is appended immediately (no space) to buf. Caller is
5994 * responsible for ensuring that an alias or AS is present before it.
5996 static void
5997 get_from_clause_coldeflist(List *names, List *types, List *typmods,
5998 deparse_context *context)
6000 StringInfo buf = context->buf;
6001 ListCell *l1;
6002 ListCell *l2;
6003 ListCell *l3;
6004 int i = 0;
6006 appendStringInfoChar(buf, '(');
6008 l2 = list_head(types);
6009 l3 = list_head(typmods);
6010 foreach(l1, names)
6012 char *attname = strVal(lfirst(l1));
6013 Oid atttypid;
6014 int32 atttypmod;
6016 atttypid = lfirst_oid(l2);
6017 l2 = lnext(l2);
6018 atttypmod = lfirst_int(l3);
6019 l3 = lnext(l3);
6021 if (i > 0)
6022 appendStringInfo(buf, ", ");
6023 appendStringInfo(buf, "%s %s",
6024 quote_identifier(attname),
6025 format_type_with_typemod(atttypid, atttypmod));
6026 i++;
6029 appendStringInfoChar(buf, ')');
6033 * get_opclass_name - fetch name of an index operator class
6035 * The opclass name is appended (after a space) to buf.
6037 * Output is suppressed if the opclass is the default for the given
6038 * actual_datatype. (If you don't want this behavior, just pass
6039 * InvalidOid for actual_datatype.)
6041 static void
6042 get_opclass_name(Oid opclass, Oid actual_datatype,
6043 StringInfo buf)
6045 HeapTuple ht_opc;
6046 Form_pg_opclass opcrec;
6047 char *opcname;
6048 char *nspname;
6050 ht_opc = SearchSysCache(CLAOID,
6051 ObjectIdGetDatum(opclass),
6052 0, 0, 0);
6053 if (!HeapTupleIsValid(ht_opc))
6054 elog(ERROR, "cache lookup failed for opclass %u", opclass);
6055 opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
6057 if (!OidIsValid(actual_datatype) ||
6058 GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
6060 /* Okay, we need the opclass name. Do we need to qualify it? */
6061 opcname = NameStr(opcrec->opcname);
6062 if (OpclassIsVisible(opclass))
6063 appendStringInfo(buf, " %s", quote_identifier(opcname));
6064 else
6066 nspname = get_namespace_name(opcrec->opcnamespace);
6067 appendStringInfo(buf, " %s.%s",
6068 quote_identifier(nspname),
6069 quote_identifier(opcname));
6072 ReleaseSysCache(ht_opc);
6076 * processIndirection - take care of array and subfield assignment
6078 * We strip any top-level FieldStore or assignment ArrayRef nodes that
6079 * appear in the input, and return the subexpression that's to be assigned.
6080 * If printit is true, we also print out the appropriate decoration for the
6081 * base column name (that the caller just printed).
6083 static Node *
6084 processIndirection(Node *node, deparse_context *context, bool printit)
6086 StringInfo buf = context->buf;
6088 for (;;)
6090 if (node == NULL)
6091 break;
6092 if (IsA(node, FieldStore))
6094 FieldStore *fstore = (FieldStore *) node;
6095 Oid typrelid;
6096 char *fieldname;
6098 /* lookup tuple type */
6099 typrelid = get_typ_typrelid(fstore->resulttype);
6100 if (!OidIsValid(typrelid))
6101 elog(ERROR, "argument type %s of FieldStore is not a tuple type",
6102 format_type_be(fstore->resulttype));
6105 * Print the field name. Note we assume here that there's only
6106 * one field being assigned to. This is okay in stored rules but
6107 * could be wrong in executable target lists. Presently no
6108 * problem since explain.c doesn't print plan targetlists, but
6109 * someday may have to think of something ...
6111 fieldname = get_relid_attribute_name(typrelid,
6112 linitial_int(fstore->fieldnums));
6113 if (printit)
6114 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
6117 * We ignore arg since it should be an uninteresting reference to
6118 * the target column or subcolumn.
6120 node = (Node *) linitial(fstore->newvals);
6122 else if (IsA(node, ArrayRef))
6124 ArrayRef *aref = (ArrayRef *) node;
6126 if (aref->refassgnexpr == NULL)
6127 break;
6128 if (printit)
6129 printSubscripts(aref, context);
6132 * We ignore refexpr since it should be an uninteresting reference
6133 * to the target column or subcolumn.
6135 node = (Node *) aref->refassgnexpr;
6137 else
6138 break;
6141 return node;
6144 static void
6145 printSubscripts(ArrayRef *aref, deparse_context *context)
6147 StringInfo buf = context->buf;
6148 ListCell *lowlist_item;
6149 ListCell *uplist_item;
6151 lowlist_item = list_head(aref->reflowerindexpr); /* could be NULL */
6152 foreach(uplist_item, aref->refupperindexpr)
6154 appendStringInfoChar(buf, '[');
6155 if (lowlist_item)
6157 get_rule_expr((Node *) lfirst(lowlist_item), context, false);
6158 appendStringInfoChar(buf, ':');
6159 lowlist_item = lnext(lowlist_item);
6161 get_rule_expr((Node *) lfirst(uplist_item), context, false);
6162 appendStringInfoChar(buf, ']');
6167 * quote_identifier - Quote an identifier only if needed
6169 * When quotes are needed, we palloc the required space; slightly
6170 * space-wasteful but well worth it for notational simplicity.
6172 const char *
6173 quote_identifier(const char *ident)
6176 * Can avoid quoting if ident starts with a lowercase letter or underscore
6177 * and contains only lowercase letters, digits, and underscores, *and* is
6178 * not any SQL keyword. Otherwise, supply quotes.
6180 int nquotes = 0;
6181 bool safe;
6182 const char *ptr;
6183 char *result;
6184 char *optr;
6187 * would like to use <ctype.h> macros here, but they might yield unwanted
6188 * locale-specific results...
6190 safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
6192 for (ptr = ident; *ptr; ptr++)
6194 char ch = *ptr;
6196 if ((ch >= 'a' && ch <= 'z') ||
6197 (ch >= '0' && ch <= '9') ||
6198 (ch == '_'))
6200 /* okay */
6202 else
6204 safe = false;
6205 if (ch == '"')
6206 nquotes++;
6210 if (safe)
6213 * Check for keyword. We quote keywords except for unreserved ones.
6214 * (In some cases we could avoid quoting a col_name or type_func_name
6215 * keyword, but it seems much harder than it's worth to tell that.)
6217 * Note: ScanKeywordLookup() does case-insensitive comparison, but
6218 * that's fine, since we already know we have all-lower-case.
6220 const ScanKeyword *keyword = ScanKeywordLookup(ident);
6222 if (keyword != NULL && keyword->category != UNRESERVED_KEYWORD)
6223 safe = false;
6226 if (safe)
6227 return ident; /* no change needed */
6229 result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
6231 optr = result;
6232 *optr++ = '"';
6233 for (ptr = ident; *ptr; ptr++)
6235 char ch = *ptr;
6237 if (ch == '"')
6238 *optr++ = '"';
6239 *optr++ = ch;
6241 *optr++ = '"';
6242 *optr = '\0';
6244 return result;
6248 * quote_qualified_identifier - Quote a possibly-qualified identifier
6250 * Return a name of the form namespace.ident, or just ident if namespace
6251 * is NULL, quoting each component if necessary. The result is palloc'd.
6253 char *
6254 quote_qualified_identifier(const char *namespace,
6255 const char *ident)
6257 StringInfoData buf;
6259 initStringInfo(&buf);
6260 if (namespace)
6261 appendStringInfo(&buf, "%s.", quote_identifier(namespace));
6262 appendStringInfoString(&buf, quote_identifier(ident));
6263 return buf.data;
6267 * generate_relation_name
6268 * Compute the name to display for a relation specified by OID
6270 * The result includes all necessary quoting and schema-prefixing.
6272 * If namespaces isn't NIL, it must be a list of deparse_namespace nodes.
6273 * We will forcibly qualify the relation name if it equals any CTE name
6274 * visible in the namespace list.
6276 static char *
6277 generate_relation_name(Oid relid, List *namespaces)
6279 HeapTuple tp;
6280 Form_pg_class reltup;
6281 bool need_qual;
6282 ListCell *nslist;
6283 char *relname;
6284 char *nspname;
6285 char *result;
6287 tp = SearchSysCache(RELOID,
6288 ObjectIdGetDatum(relid),
6289 0, 0, 0);
6290 if (!HeapTupleIsValid(tp))
6291 elog(ERROR, "cache lookup failed for relation %u", relid);
6292 reltup = (Form_pg_class) GETSTRUCT(tp);
6293 relname = NameStr(reltup->relname);
6295 /* Check for conflicting CTE name */
6296 need_qual = false;
6297 foreach(nslist, namespaces)
6299 deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
6300 ListCell *ctlist;
6302 foreach(ctlist, dpns->ctes)
6304 CommonTableExpr *cte = (CommonTableExpr *) lfirst(ctlist);
6306 if (strcmp(cte->ctename, relname) == 0)
6308 need_qual = true;
6309 break;
6312 if (need_qual)
6313 break;
6316 /* Otherwise, qualify the name if not visible in search path */
6317 if (!need_qual)
6318 need_qual = !RelationIsVisible(relid);
6320 if (need_qual)
6321 nspname = get_namespace_name(reltup->relnamespace);
6322 else
6323 nspname = NULL;
6325 result = quote_qualified_identifier(nspname, relname);
6327 ReleaseSysCache(tp);
6329 return result;
6333 * generate_function_name
6334 * Compute the name to display for a function specified by OID,
6335 * given that it is being called with the specified actual arg types.
6336 * (Arg types matter because of ambiguous-function resolution rules.)
6338 * The result includes all necessary quoting and schema-prefixing. We can
6339 * also pass back an indication of whether the function is variadic.
6341 static char *
6342 generate_function_name(Oid funcid, int nargs, Oid *argtypes,
6343 bool *is_variadic)
6345 HeapTuple proctup;
6346 Form_pg_proc procform;
6347 char *proname;
6348 char *nspname;
6349 char *result;
6350 FuncDetailCode p_result;
6351 Oid p_funcid;
6352 Oid p_rettype;
6353 bool p_retset;
6354 int p_nvargs;
6355 Oid *p_true_typeids;
6357 proctup = SearchSysCache(PROCOID,
6358 ObjectIdGetDatum(funcid),
6359 0, 0, 0);
6360 if (!HeapTupleIsValid(proctup))
6361 elog(ERROR, "cache lookup failed for function %u", funcid);
6362 procform = (Form_pg_proc) GETSTRUCT(proctup);
6363 proname = NameStr(procform->proname);
6366 * The idea here is to schema-qualify only if the parser would fail to
6367 * resolve the correct function given the unqualified func name with the
6368 * specified argtypes.
6370 p_result = func_get_detail(list_make1(makeString(proname)),
6371 NIL, nargs, argtypes, false, true,
6372 &p_funcid, &p_rettype,
6373 &p_retset, &p_nvargs, &p_true_typeids, NULL);
6374 if ((p_result == FUNCDETAIL_NORMAL ||
6375 p_result == FUNCDETAIL_AGGREGATE ||
6376 p_result == FUNCDETAIL_WINDOWFUNC) &&
6377 p_funcid == funcid)
6378 nspname = NULL;
6379 else
6380 nspname = get_namespace_name(procform->pronamespace);
6382 result = quote_qualified_identifier(nspname, proname);
6384 /* Check variadic-ness if caller cares */
6385 if (is_variadic)
6387 /* "any" variadics are not treated as variadics for listing */
6388 if (OidIsValid(procform->provariadic) &&
6389 procform->provariadic != ANYOID)
6390 *is_variadic = true;
6391 else
6392 *is_variadic = false;
6395 ReleaseSysCache(proctup);
6397 return result;
6401 * generate_operator_name
6402 * Compute the name to display for an operator specified by OID,
6403 * given that it is being called with the specified actual arg types.
6404 * (Arg types matter because of ambiguous-operator resolution rules.
6405 * Pass InvalidOid for unused arg of a unary operator.)
6407 * The result includes all necessary quoting and schema-prefixing,
6408 * plus the OPERATOR() decoration needed to use a qualified operator name
6409 * in an expression.
6411 static char *
6412 generate_operator_name(Oid operid, Oid arg1, Oid arg2)
6414 StringInfoData buf;
6415 HeapTuple opertup;
6416 Form_pg_operator operform;
6417 char *oprname;
6418 char *nspname;
6419 Operator p_result;
6421 initStringInfo(&buf);
6423 opertup = SearchSysCache(OPEROID,
6424 ObjectIdGetDatum(operid),
6425 0, 0, 0);
6426 if (!HeapTupleIsValid(opertup))
6427 elog(ERROR, "cache lookup failed for operator %u", operid);
6428 operform = (Form_pg_operator) GETSTRUCT(opertup);
6429 oprname = NameStr(operform->oprname);
6432 * The idea here is to schema-qualify only if the parser would fail to
6433 * resolve the correct operator given the unqualified op name with the
6434 * specified argtypes.
6436 switch (operform->oprkind)
6438 case 'b':
6439 p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
6440 true, -1);
6441 break;
6442 case 'l':
6443 p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
6444 true, -1);
6445 break;
6446 case 'r':
6447 p_result = right_oper(NULL, list_make1(makeString(oprname)), arg1,
6448 true, -1);
6449 break;
6450 default:
6451 elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
6452 p_result = NULL; /* keep compiler quiet */
6453 break;
6456 if (p_result != NULL && oprid(p_result) == operid)
6457 nspname = NULL;
6458 else
6460 nspname = get_namespace_name(operform->oprnamespace);
6461 appendStringInfo(&buf, "OPERATOR(%s.", quote_identifier(nspname));
6464 appendStringInfoString(&buf, oprname);
6466 if (nspname)
6467 appendStringInfoChar(&buf, ')');
6469 if (p_result != NULL)
6470 ReleaseSysCache(p_result);
6472 ReleaseSysCache(opertup);
6474 return buf.data;
6478 * Given a C string, produce a TEXT datum.
6480 * We assume that the input was palloc'd and may be freed.
6482 static text *
6483 string_to_text(char *str)
6485 text *result;
6487 result = cstring_to_text(str);
6488 pfree(str);
6489 return result;
6493 * Generate a C string representing a relation's reloptions, or NULL if none.
6495 static char *
6496 flatten_reloptions(Oid relid)
6498 char *result = NULL;
6499 HeapTuple tuple;
6500 Datum reloptions;
6501 bool isnull;
6503 tuple = SearchSysCache(RELOID,
6504 ObjectIdGetDatum(relid),
6505 0, 0, 0);
6506 if (!HeapTupleIsValid(tuple))
6507 elog(ERROR, "cache lookup failed for relation %u", relid);
6509 reloptions = SysCacheGetAttr(RELOID, tuple,
6510 Anum_pg_class_reloptions, &isnull);
6511 if (!isnull)
6513 Datum sep,
6514 txt;
6517 * We want to use array_to_text(reloptions, ', ') --- but
6518 * DirectFunctionCall2(array_to_text) does not work, because
6519 * array_to_text() relies on flinfo to be valid. So use
6520 * OidFunctionCall2.
6522 sep = CStringGetTextDatum(", ");
6523 txt = OidFunctionCall2(F_ARRAY_TO_TEXT, reloptions, sep);
6524 result = TextDatumGetCString(txt);
6527 ReleaseSysCache(tuple);
6529 return result;