1 /**********************************************************************
2 * ruleutils.c - Functions to convert stored expressions/querytrees
6 * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.66 2000/10/05 21:52:08 tgl Exp $
8 * This software is copyrighted by Jan Wieck - Hamburg.
10 * The author hereby grants permission to use, copy, modify,
11 * distribute, and license this software and its documentation
12 * for any purpose, provided that existing copyright notices are
13 * retained in all copies and that this notice is included
14 * verbatim in any distributions. No written agreement, license,
15 * or royalty fee is required for any of the authorized uses.
16 * Modifications to this software may be copyrighted by their
17 * author and need not follow the licensing terms described
18 * here, provided that the new terms are clearly indicated on
19 * the first page of each file where they apply.
21 * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
22 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
23 * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
24 * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
25 * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
28 * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
31 * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON
32 * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO
33 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
34 * ENHANCEMENTS, OR MODIFICATIONS.
36 **********************************************************************/
43 #include "catalog/pg_index.h"
44 #include "catalog/pg_operator.h"
45 #include "catalog/pg_shadow.h"
46 #include "commands/view.h"
47 #include "executor/spi.h"
48 #include "lib/stringinfo.h"
49 #include "optimizer/clauses.h"
50 #include "optimizer/tlist.h"
51 #include "parser/keywords.h"
52 #include "parser/parse_expr.h"
53 #include "parser/parsetree.h"
54 #include "rewrite/rewriteManip.h"
55 #include "utils/lsyscache.h"
64 StringInfo buf; /* output buffer to append to */
65 List *rangetables; /* List of List of RangeTblEntry */
66 bool varprefix; /* TRUE to print prefixes on Vars */
74 static char *rulename = NULL;
75 static void *plan_getrule = NULL;
76 static char *query_getrule = "SELECT * FROM pg_rewrite WHERE rulename = $1";
77 static void *plan_getview = NULL;
78 static char *query_getview = "SELECT * FROM pg_rewrite WHERE rulename = $1";
79 static void *plan_getam = NULL;
80 static char *query_getam = "SELECT * FROM pg_am WHERE oid = $1";
81 static void *plan_getopclass = NULL;
82 static char *query_getopclass = "SELECT * FROM pg_opclass WHERE oid = $1";
88 * Most of these functions used to use fixed-size buffers to build their
89 * results. Now, they take an (already initialized) StringInfo object
90 * as a parameter, and append their text output to its contents.
93 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
94 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
95 static void get_query_def(Query *query, StringInfo buf, List *parentrtables);
96 static void get_select_query_def(Query *query, deparse_context *context);
97 static void get_insert_query_def(Query *query, deparse_context *context);
98 static void get_update_query_def(Query *query, deparse_context *context);
99 static void get_delete_query_def(Query *query, deparse_context *context);
100 static void get_basic_select_query(Query *query, deparse_context *context);
101 static void get_setop_query(Node *setOp, Query *query,
102 deparse_context *context, bool toplevel);
103 static bool simple_distinct(List *distinctClause, List *targetList);
104 static RangeTblEntry *get_rte_for_var(Var *var, deparse_context *context);
105 static void get_rule_expr(Node *node, deparse_context *context);
106 static void get_func_expr(Expr *expr, deparse_context *context);
107 static void get_tle_expr(TargetEntry *tle, deparse_context *context);
108 static void get_const_expr(Const *constval, deparse_context *context);
109 static void get_sublink_expr(Node *node, deparse_context *context);
110 static void get_from_clause(Query *query, deparse_context *context);
111 static void get_from_clause_item(Node *jtnode, Query *query,
112 deparse_context *context);
113 static bool tleIsArrayAssign(TargetEntry *tle);
114 static char *quote_identifier(char *ident);
115 static char *get_relation_name(Oid relid);
116 static char *get_relid_attribute_name(Oid relid, AttrNumber attnum);
118 #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
122 * get_ruledef - Do it all and return a text
123 * that could be used as a statement
124 * to recreate the rule
128 pg_get_ruledef(PG_FUNCTION_ARGS)
130 Name rname = PG_GETARG_NAME(0);
141 * We need the rules name somewhere deep down: rulename is global
144 rulename = pstrdup(NameStr(*rname));
147 * Connect to SPI manager
150 if (SPI_connect() != SPI_OK_CONNECT)
151 elog(ERROR, "get_ruledef: cannot connect to SPI manager");
154 * On the first call prepare the plan to lookup pg_proc.
155 * We read pg_proc over the SPI manager instead of using
156 * the syscache to be checked for read access on pg_proc.
159 if (plan_getrule == NULL)
164 argtypes[0] = NAMEOID;
165 plan = SPI_prepare(query_getrule, 1, argtypes);
167 elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getrule);
168 plan_getrule = SPI_saveplan(plan);
172 * Get the pg_rewrite tuple for this rule
175 args[0] = PointerGetDatum(rulename);
176 nulls[0] = (rulename == NULL) ? 'n' : ' ';
178 spirc = SPI_execp(plan_getrule, args, nulls, 1);
179 if (spirc != SPI_OK_SELECT)
180 elog(ERROR, "failed to get pg_rewrite tuple for %s", rulename);
181 if (SPI_processed != 1)
183 if (SPI_finish() != SPI_OK_FINISH)
184 elog(ERROR, "get_ruledef: SPI_finish() failed");
185 ruledef = palloc(VARHDRSZ + 1);
186 VARATT_SIZEP(ruledef) = VARHDRSZ + 1;
187 VARDATA(ruledef)[0] = '-';
188 PG_RETURN_TEXT_P(ruledef);
191 ruletup = SPI_tuptable->vals[0];
192 rulettc = SPI_tuptable->tupdesc;
195 * Get the rules definition and put it into executors memory
198 initStringInfo(&buf);
199 make_ruledef(&buf, ruletup, rulettc);
200 len = buf.len + VARHDRSZ;
201 ruledef = SPI_palloc(len);
202 VARATT_SIZEP(ruledef) = len;
203 memcpy(VARDATA(ruledef), buf.data, buf.len);
207 * Disconnect from SPI manager
210 if (SPI_finish() != SPI_OK_FINISH)
211 elog(ERROR, "get_ruledef: SPI_finish() failed");
217 PG_RETURN_TEXT_P(ruledef);
222 * get_viewdef - Mainly the same thing, but we
223 * only return the SELECT part of a view
227 pg_get_viewdef(PG_FUNCTION_ARGS)
229 Name vname = PG_GETARG_NAME(0);
241 * We need the view name somewhere deep down
244 rulename = pstrdup(NameStr(*vname));
247 * Connect to SPI manager
250 if (SPI_connect() != SPI_OK_CONNECT)
251 elog(ERROR, "get_viewdef: cannot connect to SPI manager");
254 * On the first call prepare the plan to lookup pg_proc.
255 * We read pg_proc over the SPI manager instead of using
256 * the syscache to be checked for read access on pg_proc.
259 if (plan_getview == NULL)
264 argtypes[0] = NAMEOID;
265 plan = SPI_prepare(query_getview, 1, argtypes);
267 elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getview);
268 plan_getview = SPI_saveplan(plan);
272 * Get the pg_rewrite tuple for this rule: rulename is actually viewname here
275 name = MakeRetrieveViewRuleName(rulename);
276 args[0] = PointerGetDatum(name);
278 spirc = SPI_execp(plan_getview, args, nulls, 1);
279 if (spirc != SPI_OK_SELECT)
280 elog(ERROR, "failed to get pg_rewrite tuple for view %s", rulename);
281 initStringInfo(&buf);
282 if (SPI_processed != 1)
283 appendStringInfo(&buf, "Not a view");
287 * Get the rules definition and put it into executors memory
290 ruletup = SPI_tuptable->vals[0];
291 rulettc = SPI_tuptable->tupdesc;
292 make_viewdef(&buf, ruletup, rulettc);
294 len = buf.len + VARHDRSZ;
295 ruledef = SPI_palloc(len);
296 VARATT_SIZEP(ruledef) = len;
297 memcpy(VARDATA(ruledef), buf.data, buf.len);
302 * Disconnect from SPI manager
305 if (SPI_finish() != SPI_OK_FINISH)
306 elog(ERROR, "get_viewdef: SPI_finish() failed");
312 PG_RETURN_TEXT_P(ruledef);
317 * get_indexdef - Get the definition of an index
321 pg_get_indexdef(PG_FUNCTION_ARGS)
323 Oid indexrelid = PG_GETARG_OID(0);
331 Form_pg_index idxrec;
332 Form_pg_class idxrelrec;
333 Form_pg_class indrelrec;
340 StringInfoData keybuf;
344 * Connect to SPI manager
347 if (SPI_connect() != SPI_OK_CONNECT)
348 elog(ERROR, "get_indexdef: cannot connect to SPI manager");
351 * On the first call prepare the plans to lookup pg_am
355 if (plan_getam == NULL)
360 argtypes[0] = OIDOID;
361 plan = SPI_prepare(query_getam, 1, argtypes);
363 elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getam);
364 plan_getam = SPI_saveplan(plan);
366 argtypes[0] = OIDOID;
367 plan = SPI_prepare(query_getopclass, 1, argtypes);
369 elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getopclass);
370 plan_getopclass = SPI_saveplan(plan);
374 * Fetch the pg_index tuple by the Oid of the index
377 ht_idx = SearchSysCacheTuple(INDEXRELID,
378 ObjectIdGetDatum(indexrelid), 0, 0, 0);
379 if (!HeapTupleIsValid(ht_idx))
380 elog(ERROR, "syscache lookup for index %u failed", indexrelid);
381 idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
384 * Fetch the pg_class tuple of the index relation
387 ht_idxrel = SearchSysCacheTuple(RELOID,
388 ObjectIdGetDatum(idxrec->indexrelid), 0, 0, 0);
389 if (!HeapTupleIsValid(ht_idxrel))
390 elog(ERROR, "syscache lookup for relid %u failed", idxrec->indexrelid);
391 idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
394 * Fetch the pg_class tuple of the indexed relation
397 ht_indrel = SearchSysCacheTuple(RELOID,
398 ObjectIdGetDatum(idxrec->indrelid), 0, 0, 0);
399 if (!HeapTupleIsValid(ht_indrel))
400 elog(ERROR, "syscache lookup for relid %u failed", idxrec->indrelid);
401 indrelrec = (Form_pg_class) GETSTRUCT(ht_indrel);
404 * Get the am name for the index relation
407 spi_args[0] = ObjectIdGetDatum(idxrelrec->relam);
410 spirc = SPI_execp(plan_getam, spi_args, spi_nulls, 1);
411 if (spirc != SPI_OK_SELECT)
412 elog(ERROR, "failed to get pg_am tuple for index %s",
413 NameStr(idxrelrec->relname));
414 if (SPI_processed != 1)
415 elog(ERROR, "failed to get pg_am tuple for index %s",
416 NameStr(idxrelrec->relname));
417 spi_tup = SPI_tuptable->vals[0];
418 spi_ttc = SPI_tuptable->tupdesc;
419 spi_fno = SPI_fnumber(spi_ttc, "amname");
422 * Start the index definition
425 initStringInfo(&buf);
426 appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
427 idxrec->indisunique ? "UNIQUE " : "",
428 quote_identifier(pstrdup(NameStr(idxrelrec->relname))),
429 quote_identifier(pstrdup(NameStr(indrelrec->relname))),
430 quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
434 * Collect the indexed attributes
437 initStringInfo(&keybuf);
439 for (keyno = 0; keyno < INDEX_MAX_KEYS; keyno++)
441 if (idxrec->indkey[keyno] == InvalidAttrNumber)
444 appendStringInfo(&keybuf, sep);
448 * Add the indexed field name
451 appendStringInfo(&keybuf, "%s",
452 quote_identifier(get_relid_attribute_name(idxrec->indrelid,
453 idxrec->indkey[keyno])));
456 * If not a functional index, add the operator class name
459 if (idxrec->indproc == InvalidOid)
461 spi_args[0] = ObjectIdGetDatum(idxrec->indclass[keyno]);
464 spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
465 if (spirc != SPI_OK_SELECT)
466 elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[keyno]);
467 if (SPI_processed != 1)
468 elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[keyno]);
469 spi_tup = SPI_tuptable->vals[0];
470 spi_ttc = SPI_tuptable->tupdesc;
471 spi_fno = SPI_fnumber(spi_ttc, "opcname");
472 appendStringInfo(&keybuf, " %s",
473 quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
479 * For functional index say 'func (attrs) opclass'
482 if (idxrec->indproc != InvalidOid)
485 Form_pg_proc procStruct;
487 proctup = SearchSysCacheTuple(PROCOID,
488 ObjectIdGetDatum(idxrec->indproc), 0, 0, 0);
489 if (!HeapTupleIsValid(proctup))
490 elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc);
492 procStruct = (Form_pg_proc) GETSTRUCT(proctup);
493 appendStringInfo(&buf, "%s(%s) ",
494 quote_identifier(pstrdup(NameStr(procStruct->proname))),
497 spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]);
500 spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
501 if (spirc != SPI_OK_SELECT)
502 elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[0]);
503 if (SPI_processed != 1)
504 elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[0]);
505 spi_tup = SPI_tuptable->vals[0];
506 spi_ttc = SPI_tuptable->tupdesc;
507 spi_fno = SPI_fnumber(spi_ttc, "opcname");
508 appendStringInfo(&buf, "%s",
509 quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
514 * For the others say 'attr opclass [, ...]'
517 appendStringInfo(&buf, "%s", keybuf.data);
523 appendStringInfo(&buf, ")");
526 * Create the result in upper executor memory
529 len = buf.len + VARHDRSZ;
530 indexdef = SPI_palloc(len);
531 VARATT_SIZEP(indexdef) = len;
532 memcpy(VARDATA(indexdef), buf.data, buf.len);
537 * Disconnect from SPI manager
540 if (SPI_finish() != SPI_OK_FINISH)
541 elog(ERROR, "get_viewdef: SPI_finish() failed");
543 PG_RETURN_TEXT_P(indexdef);
548 * get_userbyid - Get a user name by usesysid and
549 * fallback to 'unknown (UID=n)'
553 pg_get_userbyid(PG_FUNCTION_ARGS)
555 int32 uid = PG_GETARG_INT32(0);
558 Form_pg_shadow user_rec;
561 * Allocate space for the result
564 result = (Name) palloc(NAMEDATALEN);
565 memset(NameStr(*result), 0, NAMEDATALEN);
568 * Get the pg_shadow entry and print the result
571 usertup = SearchSysCacheTuple(SHADOWSYSID,
572 ObjectIdGetDatum(uid),
574 if (HeapTupleIsValid(usertup))
576 user_rec = (Form_pg_shadow) GETSTRUCT(usertup);
577 StrNCpy(NameStr(*result), NameStr(user_rec->usename), NAMEDATALEN);
580 sprintf(NameStr(*result), "unknown (UID=%d)", uid);
582 PG_RETURN_NAME(result);
586 * deparse_expression - General utility for deparsing expressions
588 * expr is the node tree to be deparsed. It must be a transformed expression
589 * tree (ie, not the raw output of gram.y).
591 * rangetables is a List of Lists of RangeTblEntry nodes: first sublist is for
592 * varlevelsup = 0, next for varlevelsup = 1, etc. In each sublist the first
593 * item is for varno = 1, next varno = 2, etc. (Each sublist has the same
594 * format as the rtable list of a parsetree or query.)
596 * forceprefix is TRUE to force all Vars to be prefixed with their table names.
597 * Otherwise, a prefix is printed only if there's more than one table involved
598 * (and someday the code might try to print one only if there's ambiguity).
600 * The result is a palloc'd string.
604 deparse_expression(Node *expr, List *rangetables, bool forceprefix)
607 deparse_context context;
609 initStringInfo(&buf);
611 context.rangetables = rangetables;
612 context.varprefix = (forceprefix ||
613 length(rangetables) != 1 ||
614 length((List *) lfirst(rangetables)) != 1);
616 rulename = ""; /* in case of errors */
618 get_rule_expr(expr, &context);
624 * make_ruledef - reconstruct the CREATE RULE command
625 * for a given pg_rewrite tuple
629 make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
642 * Get the attribute values from the rules tuple
645 fno = SPI_fnumber(rulettc, "ev_type");
646 ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
648 fno = SPI_fnumber(rulettc, "ev_class");
649 ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull);
651 fno = SPI_fnumber(rulettc, "ev_attr");
652 ev_attr = (int2) SPI_getbinval(ruletup, rulettc, fno, &isnull);
654 fno = SPI_fnumber(rulettc, "is_instead");
655 is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);
657 fno = SPI_fnumber(rulettc, "ev_qual");
658 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
660 fno = SPI_fnumber(rulettc, "ev_action");
661 ev_action = SPI_getvalue(ruletup, rulettc, fno);
662 if (ev_action != NULL)
663 actions = (List *) stringToNode(ev_action);
667 * Build the rules definition text
670 appendStringInfo(buf, "CREATE RULE %s AS ON ",
671 quote_identifier(rulename));
673 /* The event the rule is fired for */
677 appendStringInfo(buf, "SELECT");
681 appendStringInfo(buf, "UPDATE");
685 appendStringInfo(buf, "INSERT");
689 appendStringInfo(buf, "DELETE");
693 elog(ERROR, "get_ruledef: rule %s has unsupported event type %d",
698 /* The relation the rule is fired on */
699 appendStringInfo(buf, " TO %s",
700 quote_identifier(get_relation_name(ev_class)));
702 appendStringInfo(buf, ".%s",
703 quote_identifier(get_relid_attribute_name(ev_class,
706 /* If the rule has an event qualification, add it */
709 if (strlen(ev_qual) > 0 && strcmp(ev_qual, "<>") != 0)
713 deparse_context context;
715 appendStringInfo(buf, " WHERE ");
717 qual = stringToNode(ev_qual);
718 query = (Query *) lfirst(actions);
721 context.rangetables = makeList1(query->rtable);
722 context.varprefix = (length(query->rtable) != 1);
724 get_rule_expr(qual, &context);
727 appendStringInfo(buf, " DO ");
729 /* The INSTEAD keyword (if so) */
731 appendStringInfo(buf, "INSTEAD ");
733 /* Finally the rules actions */
734 if (length(actions) > 1)
739 appendStringInfo(buf, "(");
740 foreach(action, actions)
742 query = (Query *) lfirst(action);
743 get_query_def(query, buf, NIL);
744 appendStringInfo(buf, "; ");
746 appendStringInfo(buf, ");");
750 if (length(actions) == 0)
752 appendStringInfo(buf, "NOTHING;");
758 query = (Query *) lfirst(actions);
759 get_query_def(query, buf, NIL);
760 appendStringInfo(buf, ";");
767 * make_viewdef - reconstruct the SELECT part of a
772 make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
786 * Get the attribute values from the rules tuple
789 fno = SPI_fnumber(rulettc, "ev_type");
790 ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
792 fno = SPI_fnumber(rulettc, "ev_class");
793 ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull);
795 fno = SPI_fnumber(rulettc, "ev_attr");
796 ev_attr = (int2) SPI_getbinval(ruletup, rulettc, fno, &isnull);
798 fno = SPI_fnumber(rulettc, "is_instead");
799 is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);
801 fno = SPI_fnumber(rulettc, "ev_qual");
802 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
804 fno = SPI_fnumber(rulettc, "ev_action");
805 ev_action = SPI_getvalue(ruletup, rulettc, fno);
806 if (ev_action != NULL)
807 actions = (List *) stringToNode(ev_action);
809 if (length(actions) != 1)
811 appendStringInfo(buf, "Not a view");
815 query = (Query *) lfirst(actions);
817 if (ev_type != '1' || ev_attr >= 0 || !is_instead ||
818 strcmp(ev_qual, "<>") != 0)
820 appendStringInfo(buf, "Not a view");
824 get_query_def(query, buf, NIL);
825 appendStringInfo(buf, ";");
830 * get_query_def - Parse back one action from
831 * the parsetree in the actions
836 get_query_def(Query *query, StringInfo buf, List *parentrtables)
838 deparse_context context;
841 context.rangetables = lcons(query->rtable, parentrtables);
842 context.varprefix = (parentrtables != NIL ||
843 length(query->rtable) != 1);
845 switch (query->commandType)
848 get_select_query_def(query, &context);
852 get_update_query_def(query, &context);
856 get_insert_query_def(query, &context);
860 get_delete_query_def(query, &context);
864 appendStringInfo(buf, "NOTHING");
868 elog(ERROR, "get_ruledef of %s: query command type %d not implemented yet",
869 rulename, query->commandType);
876 * get_select_query_def - Parse back a SELECT parsetree
880 get_select_query_def(Query *query, deparse_context *context)
882 StringInfo buf = context->buf;
883 bool shortform_orderby;
888 * If the Query node has a setOperations tree, then it's the top
889 * level of a UNION/INTERSECT/EXCEPT query; only the ORDER BY field
890 * is interesting in the top query itself.
893 if (query->setOperations)
895 get_setop_query(query->setOperations, query, context, true);
896 /* ORDER BY clauses must be simple in this case */
897 shortform_orderby = true;
901 get_basic_select_query(query, context);
902 shortform_orderby = false;
905 /* Add the ORDER BY clause if given */
906 if (query->sortClause != NIL)
908 appendStringInfo(buf, " ORDER BY ");
910 foreach(l, query->sortClause)
912 SortClause *srt = (SortClause *) lfirst(l);
913 TargetEntry *sorttle;
916 sorttle = get_sortgroupclause_tle(srt,
918 appendStringInfo(buf, sep);
919 if (shortform_orderby)
920 appendStringInfo(buf, "%d", sorttle->resdom->resno);
922 get_rule_expr(sorttle->expr, context);
923 opname = get_opname(srt->sortop);
924 if (strcmp(opname, "<") != 0)
926 if (strcmp(opname, ">") == 0)
927 appendStringInfo(buf, " DESC");
929 appendStringInfo(buf, " USING %s", opname);
937 get_basic_select_query(Query *query, deparse_context *context)
939 StringInfo buf = context->buf;
944 * Build up the query string - first we say SELECT
947 appendStringInfo(buf, "SELECT");
949 /* Add the DISTINCT clause if given */
950 if (query->distinctClause != NIL)
952 if (simple_distinct(query->distinctClause, query->targetList))
954 appendStringInfo(buf, " DISTINCT");
958 appendStringInfo(buf, " DISTINCT ON (");
960 foreach(l, query->distinctClause)
962 SortClause *srt = (SortClause *) lfirst(l);
965 sortexpr = get_sortgroupclause_expr(srt,
967 appendStringInfo(buf, sep);
968 get_rule_expr(sortexpr, context);
971 appendStringInfo(buf, ")");
975 /* Then we tell what to select (the targetlist) */
977 foreach(l, query->targetList)
979 TargetEntry *tle = (TargetEntry *) lfirst(l);
980 bool tell_as = false;
982 if (tle->resdom->resjunk)
983 continue; /* ignore junk entries */
985 appendStringInfo(buf, sep);
988 /* Do NOT use get_tle_expr here; see its comments! */
989 get_rule_expr(tle->expr, context);
991 /* Check if we must say AS ... */
992 if (!IsA(tle->expr, Var))
993 tell_as = (strcmp(tle->resdom->resname, "?column?") != 0);
996 Var *var = (Var *) (tle->expr);
1000 rte = get_rte_for_var(var, context);
1001 attname = get_rte_attribute_name(rte, var->varattno);
1002 tell_as = (strcmp(attname, tle->resdom->resname) != 0);
1007 appendStringInfo(buf, " AS %s",
1008 quote_identifier(tle->resdom->resname));
1011 /* Add the FROM clause if needed */
1012 get_from_clause(query, context);
1014 /* Add the WHERE clause if given */
1015 if (query->jointree->quals != NULL)
1017 appendStringInfo(buf, " WHERE ");
1018 get_rule_expr(query->jointree->quals, context);
1021 /* Add the GROUP BY clause if given */
1022 if (query->groupClause != NULL)
1024 appendStringInfo(buf, " GROUP BY ");
1026 foreach(l, query->groupClause)
1028 GroupClause *grp = (GroupClause *) lfirst(l);
1031 groupexpr = get_sortgroupclause_expr(grp,
1033 appendStringInfo(buf, sep);
1034 get_rule_expr(groupexpr, context);
1039 /* Add the HAVING clause if given */
1040 if (query->havingQual != NULL)
1042 appendStringInfo(buf, " HAVING ");
1043 get_rule_expr(query->havingQual, context);
1048 get_setop_query(Node *setOp, Query *query, deparse_context *context,
1051 StringInfo buf = context->buf;
1053 if (IsA(setOp, RangeTblRef))
1055 RangeTblRef *rtr = (RangeTblRef *) setOp;
1056 RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
1057 Query *subquery = rte->subquery;
1059 Assert(subquery != NULL);
1060 get_query_def(subquery, buf, context->rangetables);
1062 else if (IsA(setOp, SetOperationStmt))
1064 SetOperationStmt *op = (SetOperationStmt *) setOp;
1066 /* Must suppress parens at top level of a setop tree because
1067 * of grammar limitations...
1070 appendStringInfo(buf, "(");
1071 get_setop_query(op->larg, query, context, false);
1075 appendStringInfo(buf, " UNION ");
1077 case SETOP_INTERSECT:
1078 appendStringInfo(buf, " INTERSECT ");
1081 appendStringInfo(buf, " EXCEPT ");
1084 elog(ERROR, "get_setop_query: unexpected set op %d",
1088 appendStringInfo(buf, "ALL ");
1089 get_setop_query(op->rarg, query, context, false);
1091 appendStringInfo(buf, ")");
1095 elog(ERROR, "get_setop_query: unexpected node %d",
1096 (int) nodeTag(setOp));
1101 * Detect whether a DISTINCT list can be represented as just DISTINCT
1102 * or needs DISTINCT ON. It's simple if it contains exactly the nonjunk
1106 simple_distinct(List *distinctClause, List *targetList)
1110 TargetEntry *tle = (TargetEntry *) lfirst(targetList);
1112 if (! tle->resdom->resjunk)
1114 if (distinctClause == NIL)
1116 if (((SortClause *) lfirst(distinctClause))->tleSortGroupRef !=
1117 tle->resdom->ressortgroupref)
1119 distinctClause = lnext(distinctClause);
1121 targetList = lnext(targetList);
1123 if (distinctClause != NIL)
1130 * get_insert_query_def - Parse back an INSERT parsetree
1134 get_insert_query_def(Query *query, deparse_context *context)
1136 StringInfo buf = context->buf;
1137 RangeTblEntry *select_rte = NULL;
1143 * If it's an INSERT ... SELECT there will be a single subquery RTE
1147 foreach(l, query->rtable)
1149 rte = (RangeTblEntry *) lfirst(l);
1150 if (rte->subquery == NULL)
1153 elog(ERROR, "get_insert_query_def: too many RTEs in INSERT!");
1158 * Start the query with INSERT INTO relname
1161 rte = rt_fetch(query->resultRelation, query->rtable);
1162 appendStringInfo(buf, "INSERT INTO %s",
1163 quote_identifier(rte->relname));
1165 /* Add the insert-column-names list */
1167 foreach(l, query->targetList)
1169 TargetEntry *tle = (TargetEntry *) lfirst(l);
1171 if (tle->resdom->resjunk)
1172 continue; /* ignore junk entries */
1174 appendStringInfo(buf, sep);
1176 appendStringInfo(buf, "%s", quote_identifier(tle->resdom->resname));
1178 appendStringInfo(buf, ") ");
1180 /* Add the VALUES or the SELECT */
1181 if (select_rte == NULL)
1183 appendStringInfo(buf, "VALUES (");
1185 foreach(l, query->targetList)
1187 TargetEntry *tle = (TargetEntry *) lfirst(l);
1189 if (tle->resdom->resjunk)
1190 continue; /* ignore junk entries */
1192 appendStringInfo(buf, sep);
1194 get_tle_expr(tle, context);
1196 appendStringInfoChar(buf, ')');
1200 get_query_def(select_rte->subquery, buf, NIL);
1206 * get_update_query_def - Parse back an UPDATE parsetree
1210 get_update_query_def(Query *query, deparse_context *context)
1212 StringInfo buf = context->buf;
1218 * Start the query with UPDATE relname SET
1221 rte = rt_fetch(query->resultRelation, query->rtable);
1222 appendStringInfo(buf, "UPDATE %s%s SET ",
1224 quote_identifier(rte->relname));
1226 /* Add the comma separated list of 'attname = value' */
1228 foreach(l, query->targetList)
1230 TargetEntry *tle = (TargetEntry *) lfirst(l);
1232 if (tle->resdom->resjunk)
1233 continue; /* ignore junk entries */
1235 appendStringInfo(buf, sep);
1238 * If the update expression is an array assignment, we mustn't
1239 * put out "attname =" here; it will come out of the display
1240 * of the ArrayRef node instead.
1242 if (! tleIsArrayAssign(tle))
1243 appendStringInfo(buf, "%s = ",
1244 quote_identifier(tle->resdom->resname));
1245 get_tle_expr(tle, context);
1248 /* Add the FROM clause if needed */
1249 get_from_clause(query, context);
1251 /* Finally add a WHERE clause if given */
1252 if (query->jointree->quals != NULL)
1254 appendStringInfo(buf, " WHERE ");
1255 get_rule_expr(query->jointree->quals, context);
1261 * get_delete_query_def - Parse back a DELETE parsetree
1265 get_delete_query_def(Query *query, deparse_context *context)
1267 StringInfo buf = context->buf;
1271 * Start the query with DELETE FROM relname
1274 rte = rt_fetch(query->resultRelation, query->rtable);
1275 appendStringInfo(buf, "DELETE FROM %s%s",
1277 quote_identifier(rte->relname));
1279 /* Add a WHERE clause if given */
1280 if (query->jointree->quals != NULL)
1282 appendStringInfo(buf, " WHERE ");
1283 get_rule_expr(query->jointree->quals, context);
1288 * Find the RTE referenced by a (possibly nonlocal) Var.
1290 static RangeTblEntry *
1291 get_rte_for_var(Var *var, deparse_context *context)
1293 List *rtlist = context->rangetables;
1294 int sup = var->varlevelsup;
1297 rtlist = lnext(rtlist);
1299 return rt_fetch(var->varno, (List *) lfirst(rtlist));
1304 * get_rule_expr - Parse back an expression
1308 get_rule_expr(Node *node, deparse_context *context)
1310 StringInfo buf = context->buf;
1316 * Each level of get_rule_expr must emit an indivisible term
1317 * (parenthesized if necessary) to ensure result is reparsed into
1318 * the same expression tree.
1320 * There might be some work left here to support additional node types.
1321 * Can we ever see Param nodes here?
1324 switch (nodeTag(node))
1327 get_const_expr((Const *) node, context);
1332 Var *var = (Var *) node;
1333 RangeTblEntry *rte = get_rte_for_var(var, context);
1335 if (context->varprefix)
1337 if (strcmp(rte->eref->relname, "*NEW*") == 0)
1338 appendStringInfo(buf, "new.");
1339 else if (strcmp(rte->eref->relname, "*OLD*") == 0)
1340 appendStringInfo(buf, "old.");
1342 appendStringInfo(buf, "%s.",
1343 quote_identifier(rte->eref->relname));
1345 appendStringInfo(buf, "%s",
1346 quote_identifier(get_rte_attribute_name(rte,
1353 Expr *expr = (Expr *) node;
1354 List *args = expr->args;
1357 * Expr nodes have to be handled a bit detailed
1360 switch (expr->opType)
1363 appendStringInfoChar(buf, '(');
1364 if (length(args) == 2)
1366 /* binary operator */
1367 get_rule_expr((Node *) lfirst(args), context);
1368 appendStringInfo(buf, " %s ",
1369 get_opname(((Oper *) expr->oper)->opno));
1370 get_rule_expr((Node *) lsecond(args), context);
1374 /* unary operator --- but which side? */
1375 Oid opno = ((Oper *) expr->oper)->opno;
1377 Form_pg_operator optup;
1379 tp = SearchSysCacheTuple(OPEROID,
1380 ObjectIdGetDatum(opno),
1382 Assert(HeapTupleIsValid(tp));
1383 optup = (Form_pg_operator) GETSTRUCT(tp);
1384 switch (optup->oprkind)
1387 appendStringInfo(buf, "%s ",
1389 get_rule_expr((Node *) lfirst(args),
1393 get_rule_expr((Node *) lfirst(args),
1395 appendStringInfo(buf, " %s",
1399 elog(ERROR, "get_rule_expr: bogus oprkind");
1402 appendStringInfoChar(buf, ')');
1406 appendStringInfoChar(buf, '(');
1407 get_rule_expr((Node *) lfirst(args), context);
1408 while ((args = lnext(args)) != NIL)
1410 appendStringInfo(buf, " OR ");
1411 get_rule_expr((Node *) lfirst(args), context);
1413 appendStringInfoChar(buf, ')');
1417 appendStringInfoChar(buf, '(');
1418 get_rule_expr((Node *) lfirst(args), context);
1419 while ((args = lnext(args)) != NIL)
1421 appendStringInfo(buf, " AND ");
1422 get_rule_expr((Node *) lfirst(args), context);
1424 appendStringInfoChar(buf, ')');
1428 appendStringInfo(buf, "(NOT ");
1429 get_rule_expr((Node *) lfirst(args), context);
1430 appendStringInfoChar(buf, ')');
1434 get_func_expr((Expr *) node, context);
1438 elog(ERROR, "get_rule_expr: expr opType %d not supported",
1446 Aggref *aggref = (Aggref *) node;
1448 appendStringInfo(buf, "%s(%s",
1449 quote_identifier(aggref->aggname),
1450 aggref->aggdistinct ? "DISTINCT " : "");
1451 if (aggref->aggstar)
1452 appendStringInfo(buf, "*");
1454 get_rule_expr(aggref->target, context);
1455 appendStringInfoChar(buf, ')');
1460 get_rule_expr(((Iter *) node)->iterexpr, context);
1465 ArrayRef *aref = (ArrayRef *) node;
1466 bool savevarprefix = context->varprefix;
1471 * If we are doing UPDATE array[n] = expr, we need to
1472 * suppress any prefix on the array name. Currently,
1473 * that is the only context in which we will see a non-null
1474 * refassgnexpr --- but someday a smarter test may be needed.
1476 if (aref->refassgnexpr)
1477 context->varprefix = false;
1478 get_rule_expr(aref->refexpr, context);
1479 context->varprefix = savevarprefix;
1480 lowlist = aref->reflowerindexpr;
1481 foreach(uplist, aref->refupperindexpr)
1483 appendStringInfo(buf, "[");
1486 get_rule_expr((Node *) lfirst(lowlist), context);
1487 appendStringInfo(buf, ":");
1488 lowlist = lnext(lowlist);
1490 get_rule_expr((Node *) lfirst(uplist), context);
1491 appendStringInfo(buf, "]");
1493 if (aref->refassgnexpr)
1495 appendStringInfo(buf, " = ");
1496 get_rule_expr(aref->refassgnexpr, context);
1503 FieldSelect *fselect = (FieldSelect *) node;
1505 Form_pg_type typeStruct;
1509 /* we do NOT parenthesize the arg expression, for now */
1510 get_rule_expr(fselect->arg, context);
1511 typetup = SearchSysCacheTuple(TYPEOID,
1512 ObjectIdGetDatum(exprType(fselect->arg)),
1514 if (!HeapTupleIsValid(typetup))
1515 elog(ERROR, "cache lookup of type %u failed",
1516 exprType(fselect->arg));
1517 typeStruct = (Form_pg_type) GETSTRUCT(typetup);
1518 typrelid = typeStruct->typrelid;
1519 if (!OidIsValid(typrelid))
1520 elog(ERROR, "Argument type %s of FieldSelect is not a tuple type",
1521 NameStr(typeStruct->typname));
1522 fieldname = get_relid_attribute_name(typrelid,
1524 appendStringInfo(buf, ".%s", quote_identifier(fieldname));
1530 RelabelType *relabel = (RelabelType *) node;
1532 Form_pg_type typeStruct;
1535 appendStringInfoChar(buf, '(');
1536 get_rule_expr(relabel->arg, context);
1537 typetup = SearchSysCacheTuple(TYPEOID,
1538 ObjectIdGetDatum(relabel->resulttype),
1540 if (!HeapTupleIsValid(typetup))
1541 elog(ERROR, "cache lookup of type %u failed",
1542 relabel->resulttype);
1543 typeStruct = (Form_pg_type) GETSTRUCT(typetup);
1544 extval = pstrdup(NameStr(typeStruct->typname));
1545 appendStringInfo(buf, ")::%s", quote_identifier(extval));
1552 CaseExpr *caseexpr = (CaseExpr *) node;
1555 appendStringInfo(buf, "CASE");
1556 foreach(temp, caseexpr->args)
1558 CaseWhen *when = (CaseWhen *) lfirst(temp);
1560 appendStringInfo(buf, " WHEN ");
1561 get_rule_expr(when->expr, context);
1562 appendStringInfo(buf, " THEN ");
1563 get_rule_expr(when->result, context);
1565 appendStringInfo(buf, " ELSE ");
1566 get_rule_expr(caseexpr->defresult, context);
1567 appendStringInfo(buf, " END");
1572 get_sublink_expr(node, context);
1576 printf("\n%s\n", nodeToString(node));
1577 elog(ERROR, "get_ruledef of %s: unknown node type %d in get_rule_expr()",
1578 rulename, nodeTag(node));
1585 * get_func_expr - Parse back a Func node
1589 get_func_expr(Expr *expr, deparse_context *context)
1591 StringInfo buf = context->buf;
1592 Func *func = (Func *) (expr->oper);
1594 Form_pg_proc procStruct;
1596 int32 coercedTypmod;
1601 * Get the functions pg_proc tuple
1603 proctup = SearchSysCacheTuple(PROCOID,
1604 ObjectIdGetDatum(func->funcid),
1606 if (!HeapTupleIsValid(proctup))
1607 elog(ERROR, "cache lookup for proc %u failed", func->funcid);
1609 procStruct = (Form_pg_proc) GETSTRUCT(proctup);
1610 proname = pstrdup(NameStr(procStruct->proname));
1613 * nullvalue() and nonnullvalue() should get turned into special
1616 if (procStruct->pronargs == 1 && procStruct->proargtypes[0] == InvalidOid)
1618 if (strcmp(proname, "nullvalue") == 0)
1620 appendStringInfoChar(buf, '(');
1621 get_rule_expr((Node *) lfirst(expr->args), context);
1622 appendStringInfo(buf, " ISNULL)");
1625 if (strcmp(proname, "nonnullvalue") == 0)
1627 appendStringInfoChar(buf, '(');
1628 get_rule_expr((Node *) lfirst(expr->args), context);
1629 appendStringInfo(buf, " NOTNULL)");
1635 * Check to see if function is a length-coercion function for some
1636 * datatype. If so, display the operation as a type cast.
1638 if (exprIsLengthCoercion((Node *) expr, &coercedTypmod))
1640 Node *arg = lfirst(expr->args);
1643 * Strip off any RelabelType on the input, so we don't print
1644 * redundancies like x::bpchar::char(8). XXX Are there any cases
1645 * where this is a bad idea?
1647 if (IsA(arg, RelabelType))
1648 arg = ((RelabelType *) arg)->arg;
1649 appendStringInfoChar(buf, '(');
1650 get_rule_expr(arg, context);
1651 appendStringInfo(buf, ")::");
1654 * Show typename with appropriate length decoration. Note that
1655 * since exprIsLengthCoercion succeeded, the function name is the
1656 * same as its output type name.
1658 if (strcmp(proname, "bpchar") == 0)
1660 if (coercedTypmod > (int32) VARHDRSZ)
1661 appendStringInfo(buf, "char(%d)", coercedTypmod - VARHDRSZ);
1663 appendStringInfo(buf, "char");
1665 else if (strcmp(proname, "varchar") == 0)
1667 if (coercedTypmod > (int32) VARHDRSZ)
1668 appendStringInfo(buf, "varchar(%d)", coercedTypmod - VARHDRSZ);
1670 appendStringInfo(buf, "varchar");
1672 else if (strcmp(proname, "numeric") == 0)
1674 if (coercedTypmod >= (int32) VARHDRSZ)
1675 appendStringInfo(buf, "numeric(%d,%d)",
1676 ((coercedTypmod - VARHDRSZ) >> 16) & 0xffff,
1677 (coercedTypmod - VARHDRSZ) & 0xffff);
1679 appendStringInfo(buf, "numeric");
1682 appendStringInfo(buf, "%s", quote_identifier(proname));
1687 * Normal function: display as proname(args)
1689 appendStringInfo(buf, "%s(", quote_identifier(proname));
1691 foreach(l, expr->args)
1693 appendStringInfo(buf, sep);
1695 get_rule_expr((Node *) lfirst(l), context);
1697 appendStringInfoChar(buf, ')');
1704 * In an INSERT or UPDATE targetlist item, the parser may have inserted
1705 * a length-coercion function call to coerce the value to the right
1706 * length for the target column. We want to suppress the output of
1707 * that function call, otherwise dump/reload/dump... would blow up the
1708 * expression by adding more and more layers of length-coercion calls.
1710 * As of 7.0, this hack is no longer absolutely essential, because the parser
1711 * is now smart enough not to add a redundant length coercion function call.
1712 * But we still suppress the function call just for neatness of displayed
1715 * Note that this hack must NOT be applied to SELECT targetlist items;
1716 * any length coercion appearing there is something the user actually wrote.
1720 get_tle_expr(TargetEntry *tle, deparse_context *context)
1722 Expr *expr = (Expr *) (tle->expr);
1723 int32 coercedTypmod;
1726 * If top level is a length coercion to the correct length, suppress
1727 * it; else dump the expression normally.
1729 if (tle->resdom->restypmod >= 0 &&
1730 exprIsLengthCoercion((Node *) expr, &coercedTypmod) &&
1731 coercedTypmod == tle->resdom->restypmod)
1732 get_rule_expr((Node *) lfirst(expr->args), context);
1734 get_rule_expr(tle->expr, context);
1741 * Make a string representation of a Const
1745 get_const_expr(Const *constval, deparse_context *context)
1747 StringInfo buf = context->buf;
1749 Form_pg_type typeStruct;
1753 typetup = SearchSysCacheTuple(TYPEOID,
1754 ObjectIdGetDatum(constval->consttype),
1756 if (!HeapTupleIsValid(typetup))
1757 elog(ERROR, "cache lookup of type %u failed", constval->consttype);
1759 typeStruct = (Form_pg_type) GETSTRUCT(typetup);
1761 if (constval->constisnull)
1765 * Always label the type of a NULL constant. This not only
1766 * prevents misdecisions about the type, but it ensures that our
1767 * output is a valid b_expr.
1769 extval = pstrdup(NameStr(typeStruct->typname));
1770 appendStringInfo(buf, "NULL::%s", quote_identifier(extval));
1775 extval = DatumGetCString(OidFunctionCall3(typeStruct->typoutput,
1776 constval->constvalue,
1777 ObjectIdGetDatum(typeStruct->typelem),
1778 Int32GetDatum(-1)));
1780 switch (constval->consttype)
1784 case OIDOID: /* int types */
1786 case FLOAT8OID: /* float types */
1787 /* These types are printed without quotes */
1788 appendStringInfo(buf, extval);
1793 * We must quote any funny characters in the constant's
1794 * representation. XXX Any MULTIBYTE considerations here?
1796 appendStringInfoChar(buf, '\'');
1797 for (valptr = extval; *valptr; valptr++)
1801 if (ch == '\'' || ch == '\\')
1803 appendStringInfoChar(buf, '\\');
1804 appendStringInfoChar(buf, ch);
1806 else if (ch >= 0 && ch < ' ')
1807 appendStringInfo(buf, "\\%03o", (int) ch);
1809 appendStringInfoChar(buf, ch);
1811 appendStringInfoChar(buf, '\'');
1817 switch (constval->consttype)
1822 /* These types can be left unlabeled */
1825 extval = pstrdup(NameStr(typeStruct->typname));
1826 appendStringInfo(buf, "::%s", quote_identifier(extval));
1834 * get_sublink_expr - Parse back a sublink
1838 get_sublink_expr(Node *node, deparse_context *context)
1840 StringInfo buf = context->buf;
1841 SubLink *sublink = (SubLink *) node;
1842 Query *query = (Query *) (sublink->subselect);
1848 appendStringInfoChar(buf, '(');
1850 if (sublink->lefthand != NIL)
1852 need_paren = (length(sublink->lefthand) > 1);
1854 appendStringInfoChar(buf, '(');
1857 foreach(l, sublink->lefthand)
1859 appendStringInfo(buf, sep);
1861 get_rule_expr((Node *) lfirst(l), context);
1865 appendStringInfo(buf, ") ");
1867 appendStringInfoChar(buf, ' ');
1872 switch (sublink->subLinkType)
1874 case EXISTS_SUBLINK:
1875 appendStringInfo(buf, "EXISTS ");
1879 oper = (Oper *) lfirst(sublink->oper);
1880 appendStringInfo(buf, "%s ANY ", get_opname(oper->opno));
1884 oper = (Oper *) lfirst(sublink->oper);
1885 appendStringInfo(buf, "%s ALL ", get_opname(oper->opno));
1888 case MULTIEXPR_SUBLINK:
1889 oper = (Oper *) lfirst(sublink->oper);
1890 appendStringInfo(buf, "%s ", get_opname(oper->opno));
1898 elog(ERROR, "get_sublink_expr: unsupported sublink type %d",
1899 sublink->subLinkType);
1904 appendStringInfoChar(buf, '(');
1906 get_query_def(query, buf, context->rangetables);
1909 appendStringInfo(buf, "))");
1911 appendStringInfoChar(buf, ')');
1916 * get_from_clause - Parse back a FROM clause
1920 get_from_clause(Query *query, deparse_context *context)
1922 StringInfo buf = context->buf;
1927 * We use the query's jointree as a guide to what to print. However,
1928 * we must ignore auto-added RTEs that are marked not inFromCl.
1929 * (These can only appear at the top level of the jointree, so it's
1930 * sufficient to check here.)
1931 * Also ignore the rule pseudo-RTEs for NEW and OLD.
1935 foreach(l, query->jointree->fromlist)
1937 Node *jtnode = (Node *) lfirst(l);
1939 if (IsA(jtnode, RangeTblRef))
1941 int varno = ((RangeTblRef *) jtnode)->rtindex;
1942 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
1946 if (strcmp(rte->eref->relname, "*NEW*") == 0)
1948 if (strcmp(rte->eref->relname, "*OLD*") == 0)
1952 appendStringInfo(buf, sep);
1953 get_from_clause_item(jtnode, query, context);
1959 get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
1961 StringInfo buf = context->buf;
1963 if (IsA(jtnode, RangeTblRef))
1965 int varno = ((RangeTblRef *) jtnode)->rtindex;
1966 RangeTblEntry *rte = rt_fetch(varno, query->rtable);
1970 /* Normal relation RTE */
1971 appendStringInfo(buf, "%s%s",
1973 quote_identifier(rte->relname));
1978 Assert(rte->subquery != NULL);
1979 appendStringInfoChar(buf, '(');
1980 get_query_def(rte->subquery, buf, context->rangetables);
1981 appendStringInfoChar(buf, ')');
1983 if (rte->alias != NULL)
1985 appendStringInfo(buf, " %s",
1986 quote_identifier(rte->alias->relname));
1987 if (rte->alias->attrs != NIL)
1991 appendStringInfo(buf, " (");
1992 foreach(col, rte->alias->attrs)
1994 if (col != rte->alias->attrs)
1995 appendStringInfo(buf, ", ");
1996 appendStringInfo(buf, "%s",
1997 quote_identifier(strVal(lfirst(col))));
1999 appendStringInfoChar(buf, ')');
2003 else if (IsA(jtnode, JoinExpr))
2005 JoinExpr *j = (JoinExpr *) jtnode;
2007 appendStringInfoChar(buf, '(');
2008 get_from_clause_item(j->larg, query, context);
2010 appendStringInfo(buf, " NATURAL");
2011 switch (j->jointype)
2015 appendStringInfo(buf, " JOIN ");
2017 appendStringInfo(buf, " CROSS JOIN ");
2020 appendStringInfo(buf, " LEFT JOIN ");
2023 appendStringInfo(buf, " FULL JOIN ");
2026 appendStringInfo(buf, " RIGHT JOIN ");
2029 appendStringInfo(buf, " UNION JOIN ");
2032 elog(ERROR, "get_from_clause_item: unknown join type %d",
2035 get_from_clause_item(j->rarg, query, context);
2042 appendStringInfo(buf, " USING (");
2043 foreach(col, j->using)
2045 if (col != j->using)
2046 appendStringInfo(buf, ", ");
2047 appendStringInfo(buf, "%s",
2048 quote_identifier(strVal(lfirst(col))));
2050 appendStringInfoChar(buf, ')');
2054 appendStringInfo(buf, " ON (");
2055 get_rule_expr(j->quals, context);
2056 appendStringInfoChar(buf, ')');
2059 appendStringInfoChar(buf, ')');
2060 /* Yes, it's correct to put alias after the right paren ... */
2061 if (j->alias != NULL)
2063 appendStringInfo(buf, " %s",
2064 quote_identifier(j->alias->relname));
2065 if (j->alias->attrs != NIL)
2069 appendStringInfo(buf, " (");
2070 foreach(col, j->alias->attrs)
2072 if (col != j->alias->attrs)
2073 appendStringInfo(buf, ", ");
2074 appendStringInfo(buf, "%s",
2075 quote_identifier(strVal(lfirst(col))));
2077 appendStringInfoChar(buf, ')');
2082 elog(ERROR, "get_from_clause_item: unexpected node type %d",
2088 * tleIsArrayAssign - check for array assignment
2092 tleIsArrayAssign(TargetEntry *tle)
2096 if (tle->expr == NULL || !IsA(tle->expr, ArrayRef))
2098 aref = (ArrayRef *) tle->expr;
2099 if (aref->refassgnexpr == NULL)
2102 * Currently, it should only be possible to see non-null refassgnexpr
2103 * if we are indeed looking at an "UPDATE array[n] = expr" situation.
2104 * So aref->refexpr ought to match the tle's target.
2106 if (aref->refexpr == NULL || !IsA(aref->refexpr, Var) ||
2107 ((Var *) aref->refexpr)->varattno != tle->resdom->resno)
2108 elog(NOTICE, "tleIsArrayAssign: I'm confused ...");
2113 * quote_identifier - Quote an identifier only if needed
2115 * When quotes are needed, we palloc the required space; slightly
2116 * space-wasteful but well worth it for notational simplicity.
2120 quote_identifier(char *ident)
2124 * Can avoid quoting if ident starts with a lowercase letter and
2125 * contains only lowercase letters, digits, and underscores, *and* is
2126 * not any SQL keyword. Otherwise, supply quotes.
2132 * would like to use <ctype.h> macros here, but they might yield
2133 * unwanted locale-specific results...
2135 safe = (ident[0] >= 'a' && ident[0] <= 'z');
2140 for (ptr = ident + 1; *ptr; ptr++)
2144 safe = ((ch >= 'a' && ch <= 'z') ||
2145 (ch >= '0' && ch <= '9') ||
2156 * Check for keyword. This test is overly strong, since many of
2157 * the "keywords" known to the parser are usable as column names,
2158 * but the parser doesn't provide any easy way to test for whether
2159 * an identifier is safe or not... so be safe not sorry.
2161 * Note: ScanKeywordLookup() expects an all-lower-case input, but
2162 * we've already checked we have that.
2164 if (ScanKeywordLookup(ident) != NULL)
2169 return ident; /* no change needed */
2171 result = (char *) palloc(strlen(ident) + 2 + 1);
2172 sprintf(result, "\"%s\"", ident);
2177 * get_relation_name - Get a relation name by Oid
2181 get_relation_name(Oid relid)
2184 Form_pg_class classStruct;
2186 classtup = SearchSysCacheTuple(RELOID,
2187 ObjectIdGetDatum(relid), 0, 0, 0);
2188 if (!HeapTupleIsValid(classtup))
2189 elog(ERROR, "cache lookup of relation %u failed", relid);
2191 classStruct = (Form_pg_class) GETSTRUCT(classtup);
2192 return pstrdup(NameStr(classStruct->relname));
2197 * get_relid_attribute_name
2198 * Get an attribute name by its relations Oid and its attnum
2200 * Same as underlying syscache routine get_attname(), except that error
2201 * is handled by elog() instead of returning NULL.
2205 get_relid_attribute_name(Oid relid, AttrNumber attnum)
2209 attname = get_attname(relid, attnum);
2210 if (attname == NULL)
2211 elog(ERROR, "cache lookup of attribute %d in relation %u failed",