1 /**********************************************************************
2 * get_ruledef.c - Function to get a rules definition text
6 * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.51 2000/06/09 01:11:09 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 "executor/spi.h"
47 #include "lib/stringinfo.h"
48 #include "optimizer/clauses.h"
49 #include "optimizer/tlist.h"
50 #include "parser/keywords.h"
51 #include "parser/parse_expr.h"
52 #include "parser/parsetree.h"
53 #include "utils/lsyscache.h"
62 StringInfo buf; /* output buffer to append to */
63 List *rangetables; /* List of List of RangeTblEntry */
64 bool varprefix; /* TRUE to print prefixes on Vars */
71 } check_if_rte_used_context;
78 static char *rulename = NULL;
79 static void *plan_getrule = NULL;
80 static char *query_getrule = "SELECT * FROM pg_rewrite WHERE rulename = $1";
81 static void *plan_getview = NULL;
82 static char *query_getview = "SELECT * FROM pg_rewrite WHERE rulename = $1 or rulename = $2";
83 static void *plan_getam = NULL;
84 static char *query_getam = "SELECT * FROM pg_am WHERE oid = $1";
85 static void *plan_getopclass = NULL;
86 static char *query_getopclass = "SELECT * FROM pg_opclass WHERE oid = $1";
92 * Most of these functions used to use fixed-size buffers to build their
93 * results. Now, they take an (already initialized) StringInfo object
94 * as a parameter, and append their text output to its contents.
97 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
98 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc);
99 static void get_query_def(Query *query, StringInfo buf, List *parentrtables);
100 static void get_select_query_def(Query *query, deparse_context *context);
101 static void get_insert_query_def(Query *query, deparse_context *context);
102 static void get_update_query_def(Query *query, deparse_context *context);
103 static void get_delete_query_def(Query *query, deparse_context *context);
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 char *quote_identifier(char *ident);
111 static char *get_relation_name(Oid relid);
112 static char *get_attribute_name(Oid relid, int2 attnum);
113 static bool check_if_rte_used(Node *node, Index rt_index, int levelsup);
114 static bool check_if_rte_used_walker(Node *node,
115 check_if_rte_used_context *context);
117 #define inherit_marker(rte) ((rte)->inh ? "*" : "")
121 * get_ruledef - Do it all and return a text
122 * that could be used as a statement
123 * to recreate the rule
127 pg_get_ruledef(NameData *rname)
139 * We need the rules name somewhere deep down
142 rulename = pstrdup(NameStr(*rname));
145 * Connect to SPI manager
148 if (SPI_connect() != SPI_OK_CONNECT)
149 elog(ERROR, "get_ruledef: cannot connect to SPI manager");
152 * On the first call prepare the plan to lookup pg_proc.
153 * We read pg_proc over the SPI manager instead of using
154 * the syscache to be checked for read access on pg_proc.
157 if (plan_getrule == NULL)
162 argtypes[0] = NAMEOID;
163 plan = SPI_prepare(query_getrule, 1, argtypes);
165 elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getrule);
166 plan_getrule = SPI_saveplan(plan);
170 * Get the pg_rewrite tuple for this rule
173 args[0] = PointerGetDatum(rulename);
174 nulls[0] = (rulename == NULL) ? 'n' : ' ';
176 spirc = SPI_execp(plan_getrule, args, nulls, 1);
177 if (spirc != SPI_OK_SELECT)
178 elog(ERROR, "failed to get pg_rewrite tuple for %s", rulename);
179 if (SPI_processed != 1)
181 if (SPI_finish() != SPI_OK_FINISH)
182 elog(ERROR, "get_ruledef: SPI_finish() failed");
183 ruledef = SPI_palloc(VARHDRSZ + 1);
184 VARSIZE(ruledef) = VARHDRSZ + 1;
185 VARDATA(ruledef)[0] = '-';
189 ruletup = SPI_tuptable->vals[0];
190 rulettc = SPI_tuptable->tupdesc;
193 * Get the rules definition and put it into executors memory
196 initStringInfo(&buf);
197 make_ruledef(&buf, ruletup, rulettc);
198 len = buf.len + VARHDRSZ;
199 ruledef = SPI_palloc(len);
200 VARSIZE(ruledef) = len;
201 memcpy(VARDATA(ruledef), buf.data, buf.len);
205 * Disconnect from SPI manager
208 if (SPI_finish() != SPI_OK_FINISH)
209 elog(ERROR, "get_ruledef: SPI_finish() failed");
220 * get_viewdef - Mainly the same thing, but we
221 * only return the SELECT part of a view
225 pg_get_viewdef(NameData *rname)
235 char name1[NAMEDATALEN + 5];
236 char name2[NAMEDATALEN + 5];
239 * We need the rules name somewhere deep down
242 rulename = pstrdup(NameStr(*rname));
245 * Connect to SPI manager
248 if (SPI_connect() != SPI_OK_CONNECT)
249 elog(ERROR, "get_viewdef: cannot connect to SPI manager");
252 * On the first call prepare the plan to lookup pg_proc.
253 * We read pg_proc over the SPI manager instead of using
254 * the syscache to be checked for read access on pg_proc.
257 if (plan_getview == NULL)
262 argtypes[0] = NAMEOID;
263 argtypes[1] = NAMEOID;
264 plan = SPI_prepare(query_getview, 2, argtypes);
266 elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getview);
267 plan_getview = SPI_saveplan(plan);
271 * Get the pg_rewrite tuple for this rule
274 sprintf(name1, "_RET%s", rulename);
275 sprintf(name2, "_ret%s", rulename);
276 args[0] = PointerGetDatum(name1);
277 args[1] = PointerGetDatum(name2);
281 spirc = SPI_execp(plan_getview, args, nulls, 1);
282 if (spirc != SPI_OK_SELECT)
283 elog(ERROR, "failed to get pg_rewrite tuple for view %s", rulename);
284 initStringInfo(&buf);
285 if (SPI_processed != 1)
286 appendStringInfo(&buf, "Not a view");
290 * Get the rules definition and put it into executors memory
293 ruletup = SPI_tuptable->vals[0];
294 rulettc = SPI_tuptable->tupdesc;
295 make_viewdef(&buf, ruletup, rulettc);
297 len = buf.len + VARHDRSZ;
298 ruledef = SPI_palloc(len);
299 VARSIZE(ruledef) = len;
300 memcpy(VARDATA(ruledef), buf.data, buf.len);
304 * Disconnect from SPI manager
307 if (SPI_finish() != SPI_OK_FINISH)
308 elog(ERROR, "get_viewdef: SPI_finish() failed");
319 * get_indexdef - Get the definition of an index
323 pg_get_indexdef(PG_FUNCTION_ARGS)
325 Oid indexrelid = PG_GETARG_OID(0);
333 Form_pg_index idxrec;
334 Form_pg_class idxrelrec;
335 Form_pg_class indrelrec;
342 StringInfoData keybuf;
346 * Connect to SPI manager
349 if (SPI_connect() != SPI_OK_CONNECT)
350 elog(ERROR, "get_indexdef: cannot connect to SPI manager");
353 * On the first call prepare the plans to lookup pg_am
357 if (plan_getam == NULL)
362 argtypes[0] = OIDOID;
363 plan = SPI_prepare(query_getam, 1, argtypes);
365 elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getam);
366 plan_getam = SPI_saveplan(plan);
368 argtypes[0] = OIDOID;
369 plan = SPI_prepare(query_getopclass, 1, argtypes);
371 elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getopclass);
372 plan_getopclass = SPI_saveplan(plan);
376 * Fetch the pg_index tuple by the Oid of the index
379 ht_idx = SearchSysCacheTuple(INDEXRELID,
380 ObjectIdGetDatum(indexrelid), 0, 0, 0);
381 if (!HeapTupleIsValid(ht_idx))
382 elog(ERROR, "syscache lookup for index %u failed", indexrelid);
383 idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
386 * Fetch the pg_class tuple of the index relation
389 ht_idxrel = SearchSysCacheTuple(RELOID,
390 ObjectIdGetDatum(idxrec->indexrelid), 0, 0, 0);
391 if (!HeapTupleIsValid(ht_idxrel))
392 elog(ERROR, "syscache lookup for relid %u failed", idxrec->indexrelid);
393 idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
396 * Fetch the pg_class tuple of the indexed relation
399 ht_indrel = SearchSysCacheTuple(RELOID,
400 ObjectIdGetDatum(idxrec->indrelid), 0, 0, 0);
401 if (!HeapTupleIsValid(ht_indrel))
402 elog(ERROR, "syscache lookup for relid %u failed", idxrec->indrelid);
403 indrelrec = (Form_pg_class) GETSTRUCT(ht_indrel);
406 * Get the am name for the index relation
409 spi_args[0] = ObjectIdGetDatum(idxrelrec->relam);
412 spirc = SPI_execp(plan_getam, spi_args, spi_nulls, 1);
413 if (spirc != SPI_OK_SELECT)
414 elog(ERROR, "failed to get pg_am tuple for index %s",
415 NameStr(idxrelrec->relname));
416 if (SPI_processed != 1)
417 elog(ERROR, "failed to get pg_am tuple for index %s",
418 NameStr(idxrelrec->relname));
419 spi_tup = SPI_tuptable->vals[0];
420 spi_ttc = SPI_tuptable->tupdesc;
421 spi_fno = SPI_fnumber(spi_ttc, "amname");
424 * Start the index definition
427 initStringInfo(&buf);
428 appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
429 idxrec->indisunique ? "UNIQUE " : "",
430 quote_identifier(pstrdup(NameStr(idxrelrec->relname))),
431 quote_identifier(pstrdup(NameStr(indrelrec->relname))),
432 quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
436 * Collect the indexed attributes
439 initStringInfo(&keybuf);
441 for (keyno = 0; keyno < INDEX_MAX_KEYS; keyno++)
443 if (idxrec->indkey[keyno] == InvalidAttrNumber)
446 appendStringInfo(&keybuf, sep);
450 * Add the indexed field name
453 appendStringInfo(&keybuf, "%s",
454 quote_identifier(get_attribute_name(idxrec->indrelid,
455 idxrec->indkey[keyno])));
458 * If not a functional index, add the operator class name
461 if (idxrec->indproc == InvalidOid)
463 spi_args[0] = ObjectIdGetDatum(idxrec->indclass[keyno]);
466 spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
467 if (spirc != SPI_OK_SELECT)
468 elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[keyno]);
469 if (SPI_processed != 1)
470 elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[keyno]);
471 spi_tup = SPI_tuptable->vals[0];
472 spi_ttc = SPI_tuptable->tupdesc;
473 spi_fno = SPI_fnumber(spi_ttc, "opcname");
474 appendStringInfo(&keybuf, " %s",
475 quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
481 * For functional index say 'func (attrs) opclass'
484 if (idxrec->indproc != InvalidOid)
487 Form_pg_proc procStruct;
489 proctup = SearchSysCacheTuple(PROCOID,
490 ObjectIdGetDatum(idxrec->indproc), 0, 0, 0);
491 if (!HeapTupleIsValid(proctup))
492 elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc);
494 procStruct = (Form_pg_proc) GETSTRUCT(proctup);
495 appendStringInfo(&buf, "%s(%s) ",
496 quote_identifier(pstrdup(NameStr(procStruct->proname))),
499 spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]);
502 spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
503 if (spirc != SPI_OK_SELECT)
504 elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[0]);
505 if (SPI_processed != 1)
506 elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[0]);
507 spi_tup = SPI_tuptable->vals[0];
508 spi_ttc = SPI_tuptable->tupdesc;
509 spi_fno = SPI_fnumber(spi_ttc, "opcname");
510 appendStringInfo(&buf, "%s",
511 quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
516 * For the others say 'attr opclass [, ...]'
519 appendStringInfo(&buf, "%s", keybuf.data);
525 appendStringInfo(&buf, ")");
528 * Create the result in upper executor memory
531 len = buf.len + VARHDRSZ;
532 indexdef = SPI_palloc(len);
533 VARSIZE(indexdef) = len;
534 memcpy(VARDATA(indexdef), buf.data, buf.len);
539 * Disconnect from SPI manager
542 if (SPI_finish() != SPI_OK_FINISH)
543 elog(ERROR, "get_viewdef: SPI_finish() failed");
545 PG_RETURN_TEXT_P(indexdef);
550 * get_userbyid - Get a user name by usesysid and
551 * fallback to 'unknown (UID=n)'
555 pg_get_userbyid(int32 uid)
558 Form_pg_shadow user_rec;
562 * Allocate space for the result
565 result = (NameData *) palloc(NAMEDATALEN);
566 memset(NameStr(*result), 0, NAMEDATALEN);
569 * Get the pg_shadow entry and print the result
572 usertup = SearchSysCacheTuple(SHADOWSYSID,
573 ObjectIdGetDatum(uid), 0, 0, 0);
574 if (HeapTupleIsValid(usertup))
576 user_rec = (Form_pg_shadow) GETSTRUCT(usertup);
577 StrNCpy(NameStr(*result), NameStr(user_rec->usename), NAMEDATALEN);
580 sprintf((char *) result, "unknown (UID=%d)", uid);
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_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 = lcons(query->rtable, NIL);
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 || strcmp(ev_qual, "<>"))
819 appendStringInfo(buf, "Not a view");
823 get_query_def(query, buf, NIL);
824 appendStringInfo(buf, ";");
829 * get_query_def - Parse back one action from
830 * the parsetree in the actions
835 get_query_def(Query *query, StringInfo buf, List *parentrtables)
837 deparse_context context;
840 context.rangetables = lcons(query->rtable, parentrtables);
841 context.varprefix = (parentrtables != NIL ||
842 length(query->rtable) != 1);
844 switch (query->commandType)
847 get_select_query_def(query, &context);
851 get_update_query_def(query, &context);
855 get_insert_query_def(query, &context);
859 get_delete_query_def(query, &context);
863 appendStringInfo(buf, "NOTHING");
867 elog(ERROR, "get_ruledef of %s: query command type %d not implemented yet",
868 rulename, query->commandType);
875 * get_select_query_def - Parse back a SELECT parsetree
879 get_select_query_def(Query *query, deparse_context *context)
881 StringInfo buf = context->buf;
888 bool rt_constonly = TRUE;
893 * First we need to know which and how many of the
894 * range table entries in the query are used in the target list
895 * or queries qualification
898 rt_length = length(query->rtable);
899 rt_used = palloc(sizeof(bool) * rt_length);
900 for (i = 0; i < rt_length; i++)
902 if (check_if_rte_used((Node *) (query->targetList), i + 1, 0) ||
903 check_if_rte_used(query->qual, i + 1, 0) ||
904 check_if_rte_used(query->havingQual, i + 1, 0))
914 * Now check if any of the used rangetable entries is different
915 * from *NEW* and *CURRENT*. If so we must provide the FROM clause
920 foreach(l, query->rtable)
925 rte = (RangeTblEntry *) lfirst(l);
926 if (rte->ref == NULL)
928 if (!strcmp(rte->ref->relname, "*NEW*"))
930 if (!strcmp(rte->ref->relname, "*CURRENT*"))
933 rt_constonly = FALSE;
938 * Build up the query string - first we say SELECT
941 appendStringInfo(buf, "SELECT");
943 /* Then we tell what to select (the targetlist) */
945 foreach(l, query->targetList)
947 bool tell_as = FALSE;
949 tle = (TargetEntry *) lfirst(l);
950 appendStringInfo(buf, sep);
953 /* Do NOT use get_tle_expr here; see its comments! */
954 get_rule_expr(tle->expr, context);
956 /* Check if we must say AS ... */
957 if (!IsA(tle->expr, Var))
958 tell_as = strcmp(tle->resdom->resname, "?column?");
961 Var *var = (Var *) (tle->expr);
964 rte = get_rte_for_var(var, context);
965 attname = get_attribute_name(rte->relid, var->varattno);
966 if (strcmp(attname, tle->resdom->resname))
972 appendStringInfo(buf, " AS %s",
973 quote_identifier(tle->resdom->resname));
976 /* If we need other tables than *NEW* or *CURRENT* add the FROM clause */
977 if (!rt_constonly && rt_numused > 0)
981 foreach(l, query->rtable)
985 rte = (RangeTblEntry *) lfirst(l);
987 if (rte->ref == NULL)
989 if (!strcmp(rte->ref->relname, "*NEW*"))
991 if (!strcmp(rte->ref->relname, "*CURRENT*"))
994 appendStringInfo(buf, sep);
996 appendStringInfo(buf, "%s%s",
997 quote_identifier(rte->relname),
998 inherit_marker(rte));
1001 * NOTE: SQL92 says you can't write column aliases unless
1002 * you write a table alias --- so, if there's an alias
1003 * list, make sure we emit a table alias even if it's the
1004 * same as the table's real name.
1006 if ((rte->ref != NULL)
1007 && ((strcmp(rte->relname, rte->ref->relname) != 0)
1008 || (rte->ref->attrs != NIL)))
1010 appendStringInfo(buf, " %s",
1011 quote_identifier(rte->ref->relname));
1012 if (rte->ref->attrs != NIL)
1016 appendStringInfo(buf, " (");
1017 foreach(col, rte->ref->attrs)
1019 if (col != rte->ref->attrs)
1020 appendStringInfo(buf, ", ");
1021 appendStringInfo(buf, "%s",
1022 quote_identifier(strVal(lfirst(col))));
1024 appendStringInfoChar(buf, ')');
1031 /* Add the WHERE clause if given */
1032 if (query->qual != NULL)
1034 appendStringInfo(buf, " WHERE ");
1035 get_rule_expr(query->qual, context);
1038 /* Add the GROUP BY CLAUSE */
1039 if (query->groupClause != NULL)
1041 appendStringInfo(buf, " GROUP BY ");
1043 foreach(l, query->groupClause)
1045 GroupClause *grp = (GroupClause *) lfirst(l);
1048 groupexpr = get_sortgroupclause_expr(grp,
1050 appendStringInfo(buf, sep);
1051 get_rule_expr(groupexpr, context);
1059 * get_insert_query_def - Parse back an INSERT parsetree
1063 get_insert_query_def(Query *query, deparse_context *context)
1065 StringInfo buf = context->buf;
1072 bool rt_constonly = TRUE;
1077 * We need to know if other tables than *NEW* or *CURRENT*
1078 * are used in the query. If not, it's an INSERT ... VALUES,
1079 * otherwise an INSERT ... SELECT.
1082 rt_length = length(query->rtable);
1083 rt_used = palloc(sizeof(bool) * rt_length);
1084 for (i = 0; i < rt_length; i++)
1086 if (check_if_rte_used((Node *) (query->targetList), i + 1, 0) ||
1087 check_if_rte_used(query->qual, i + 1, 0) ||
1088 check_if_rte_used(query->havingQual, i + 1, 0))
1098 foreach(l, query->rtable)
1103 rte = (RangeTblEntry *) lfirst(l);
1104 if (rte->ref == NULL)
1106 if (!strcmp(rte->ref->relname, "*NEW*"))
1108 if (!strcmp(rte->ref->relname, "*CURRENT*"))
1111 rt_constonly = FALSE;
1116 * Start the query with INSERT INTO relname
1119 rte = rt_fetch(query->resultRelation, query->rtable);
1120 appendStringInfo(buf, "INSERT INTO %s",
1121 quote_identifier(rte->relname));
1123 /* Add the target list */
1125 foreach(l, query->targetList)
1127 tle = (TargetEntry *) lfirst(l);
1129 appendStringInfo(buf, sep);
1131 appendStringInfo(buf, "%s", quote_identifier(tle->resdom->resname));
1133 appendStringInfo(buf, ") ");
1135 /* Add the VALUES or the SELECT */
1136 if (rt_constonly && query->qual == NULL)
1138 appendStringInfo(buf, "VALUES (");
1140 foreach(l, query->targetList)
1142 tle = (TargetEntry *) lfirst(l);
1144 appendStringInfo(buf, sep);
1146 get_tle_expr(tle, context);
1148 appendStringInfoChar(buf, ')');
1151 get_select_query_def(query, context);
1156 * get_update_query_def - Parse back an UPDATE parsetree
1160 get_update_query_def(Query *query, deparse_context *context)
1162 StringInfo buf = context->buf;
1169 * Start the query with UPDATE relname SET
1172 rte = rt_fetch(query->resultRelation, query->rtable);
1173 appendStringInfo(buf, "UPDATE %s%s SET ",
1174 quote_identifier(rte->relname),
1175 inherit_marker(rte));
1177 /* Add the comma separated list of 'attname = value' */
1179 foreach(l, query->targetList)
1181 tle = (TargetEntry *) lfirst(l);
1183 appendStringInfo(buf, sep);
1185 appendStringInfo(buf, "%s = ",
1186 quote_identifier(tle->resdom->resname));
1187 get_tle_expr(tle, context);
1190 /* Finally add a WHERE clause if given */
1191 if (query->qual != NULL)
1193 appendStringInfo(buf, " WHERE ");
1194 get_rule_expr(query->qual, context);
1200 * get_delete_query_def - Parse back a DELETE parsetree
1204 get_delete_query_def(Query *query, deparse_context *context)
1206 StringInfo buf = context->buf;
1210 * Start the query with DELETE FROM relname
1213 rte = rt_fetch(query->resultRelation, query->rtable);
1214 appendStringInfo(buf, "DELETE FROM %s%s",
1215 quote_identifier(rte->relname),
1216 inherit_marker(rte));
1218 /* Add a WHERE clause if given */
1219 if (query->qual != NULL)
1221 appendStringInfo(buf, " WHERE ");
1222 get_rule_expr(query->qual, context);
1227 * Find the RTE referenced by a (possibly nonlocal) Var.
1229 static RangeTblEntry *
1230 get_rte_for_var(Var *var, deparse_context *context)
1232 List *rtlist = context->rangetables;
1233 int sup = var->varlevelsup;
1236 rtlist = lnext(rtlist);
1238 return rt_fetch(var->varno, (List *) lfirst(rtlist));
1243 * get_rule_expr - Parse back an expression
1247 get_rule_expr(Node *node, deparse_context *context)
1249 StringInfo buf = context->buf;
1255 * Each level of get_rule_expr must emit an indivisible term
1256 * (parenthesized if necessary) to ensure result is reparsed into
1257 * the same expression tree.
1259 * There might be some work left here to support additional node types.
1260 * Can we ever see Param nodes here?
1263 switch (nodeTag(node))
1266 get_const_expr((Const *) node, context);
1271 Var *var = (Var *) node;
1272 RangeTblEntry *rte = get_rte_for_var(var, context);
1274 if (context->varprefix)
1276 if (rte->ref == NULL)
1277 appendStringInfo(buf, "%s.",
1278 quote_identifier(rte->relname));
1279 else if (!strcmp(rte->ref->relname, "*NEW*"))
1280 appendStringInfo(buf, "new.");
1281 else if (!strcmp(rte->ref->relname, "*CURRENT*"))
1282 appendStringInfo(buf, "old.");
1284 appendStringInfo(buf, "%s.",
1285 quote_identifier(rte->ref->relname));
1287 appendStringInfo(buf, "%s",
1288 quote_identifier(get_attribute_name(rte->relid,
1295 Expr *expr = (Expr *) node;
1296 List *args = expr->args;
1299 * Expr nodes have to be handled a bit detailed
1302 switch (expr->opType)
1305 appendStringInfoChar(buf, '(');
1306 if (length(args) == 2)
1308 /* binary operator */
1309 get_rule_expr((Node *) lfirst(args), context);
1310 appendStringInfo(buf, " %s ",
1311 get_opname(((Oper *) expr->oper)->opno));
1312 get_rule_expr((Node *) lsecond(args), context);
1316 /* unary operator --- but which side? */
1317 Oid opno = ((Oper *) expr->oper)->opno;
1319 Form_pg_operator optup;
1321 tp = SearchSysCacheTuple(OPEROID,
1322 ObjectIdGetDatum(opno),
1324 Assert(HeapTupleIsValid(tp));
1325 optup = (Form_pg_operator) GETSTRUCT(tp);
1326 switch (optup->oprkind)
1329 appendStringInfo(buf, "%s ",
1331 get_rule_expr((Node *) lfirst(args),
1335 get_rule_expr((Node *) lfirst(args),
1337 appendStringInfo(buf, " %s",
1341 elog(ERROR, "get_rule_expr: bogus oprkind");
1344 appendStringInfoChar(buf, ')');
1348 appendStringInfoChar(buf, '(');
1349 get_rule_expr((Node *) lfirst(args), context);
1350 while ((args = lnext(args)) != NIL)
1352 appendStringInfo(buf, " OR ");
1353 get_rule_expr((Node *) lfirst(args), context);
1355 appendStringInfoChar(buf, ')');
1359 appendStringInfoChar(buf, '(');
1360 get_rule_expr((Node *) lfirst(args), context);
1361 while ((args = lnext(args)) != NIL)
1363 appendStringInfo(buf, " AND ");
1364 get_rule_expr((Node *) lfirst(args), context);
1366 appendStringInfoChar(buf, ')');
1370 appendStringInfo(buf, "(NOT ");
1371 get_rule_expr((Node *) lfirst(args), context);
1372 appendStringInfoChar(buf, ')');
1376 get_func_expr((Expr *) node, context);
1380 elog(ERROR, "get_rule_expr: expr opType %d not supported",
1388 Aggref *aggref = (Aggref *) node;
1390 appendStringInfo(buf, "%s(%s",
1391 quote_identifier(aggref->aggname),
1392 aggref->aggdistinct ? "DISTINCT " : "");
1393 if (aggref->aggstar)
1394 appendStringInfo(buf, "*");
1396 get_rule_expr(aggref->target, context);
1397 appendStringInfoChar(buf, ')');
1402 get_rule_expr(((Iter *) node)->iterexpr, context);
1407 ArrayRef *aref = (ArrayRef *) node;
1411 get_rule_expr(aref->refexpr, context);
1412 lowlist = aref->reflowerindexpr;
1413 foreach(uplist, aref->refupperindexpr)
1415 appendStringInfo(buf, "[");
1418 get_rule_expr((Node *) lfirst(lowlist), context);
1419 appendStringInfo(buf, ":");
1420 lowlist = lnext(lowlist);
1422 get_rule_expr((Node *) lfirst(uplist), context);
1423 appendStringInfo(buf, "]");
1425 /* XXX need to do anything with refassgnexpr? */
1431 RelabelType *relabel = (RelabelType *) node;
1433 Form_pg_type typeStruct;
1436 appendStringInfoChar(buf, '(');
1437 get_rule_expr(relabel->arg, context);
1438 typetup = SearchSysCacheTuple(TYPEOID,
1439 ObjectIdGetDatum(relabel->resulttype),
1441 if (!HeapTupleIsValid(typetup))
1442 elog(ERROR, "cache lookup of type %u failed",
1443 relabel->resulttype);
1444 typeStruct = (Form_pg_type) GETSTRUCT(typetup);
1445 extval = pstrdup(NameStr(typeStruct->typname));
1446 appendStringInfo(buf, ")::%s", quote_identifier(extval));
1453 CaseExpr *caseexpr = (CaseExpr *) node;
1456 appendStringInfo(buf, "CASE");
1457 foreach(temp, caseexpr->args)
1459 CaseWhen *when = (CaseWhen *) lfirst(temp);
1461 appendStringInfo(buf, " WHEN ");
1462 get_rule_expr(when->expr, context);
1463 appendStringInfo(buf, " THEN ");
1464 get_rule_expr(when->result, context);
1466 appendStringInfo(buf, " ELSE ");
1467 get_rule_expr(caseexpr->defresult, context);
1468 appendStringInfo(buf, " END");
1473 get_sublink_expr(node, context);
1477 printf("\n%s\n", nodeToString(node));
1478 elog(ERROR, "get_ruledef of %s: unknown node type %d in get_rule_expr()",
1479 rulename, nodeTag(node));
1486 * get_func_expr - Parse back a Func node
1490 get_func_expr(Expr *expr, deparse_context *context)
1492 StringInfo buf = context->buf;
1493 Func *func = (Func *) (expr->oper);
1495 Form_pg_proc procStruct;
1497 int32 coercedTypmod;
1502 * Get the functions pg_proc tuple
1504 proctup = SearchSysCacheTuple(PROCOID,
1505 ObjectIdGetDatum(func->funcid),
1507 if (!HeapTupleIsValid(proctup))
1508 elog(ERROR, "cache lookup for proc %u failed", func->funcid);
1510 procStruct = (Form_pg_proc) GETSTRUCT(proctup);
1511 proname = pstrdup(NameStr(procStruct->proname));
1514 * nullvalue() and nonnullvalue() should get turned into special
1517 if (procStruct->pronargs == 1 && procStruct->proargtypes[0] == InvalidOid)
1519 if (!strcmp(proname, "nullvalue"))
1521 appendStringInfoChar(buf, '(');
1522 get_rule_expr((Node *) lfirst(expr->args), context);
1523 appendStringInfo(buf, " ISNULL)");
1526 if (!strcmp(proname, "nonnullvalue"))
1528 appendStringInfoChar(buf, '(');
1529 get_rule_expr((Node *) lfirst(expr->args), context);
1530 appendStringInfo(buf, " NOTNULL)");
1536 * Check to see if function is a length-coercion function for some
1537 * datatype. If so, display the operation as a type cast.
1539 if (exprIsLengthCoercion((Node *) expr, &coercedTypmod))
1541 Node *arg = lfirst(expr->args);
1544 * Strip off any RelabelType on the input, so we don't print
1545 * redundancies like x::bpchar::char(8). XXX Are there any cases
1546 * where this is a bad idea?
1548 if (IsA(arg, RelabelType))
1549 arg = ((RelabelType *) arg)->arg;
1550 appendStringInfoChar(buf, '(');
1551 get_rule_expr(arg, context);
1552 appendStringInfo(buf, ")::");
1555 * Show typename with appropriate length decoration. Note that
1556 * since exprIsLengthCoercion succeeded, the function name is the
1557 * same as its output type name.
1559 if (strcmp(proname, "bpchar") == 0)
1561 if (coercedTypmod > (int32) VARHDRSZ)
1562 appendStringInfo(buf, "char(%d)", coercedTypmod - VARHDRSZ);
1564 appendStringInfo(buf, "char");
1566 else if (strcmp(proname, "varchar") == 0)
1568 if (coercedTypmod > (int32) VARHDRSZ)
1569 appendStringInfo(buf, "varchar(%d)", coercedTypmod - VARHDRSZ);
1571 appendStringInfo(buf, "varchar");
1573 else if (strcmp(proname, "numeric") == 0)
1575 if (coercedTypmod >= (int32) VARHDRSZ)
1576 appendStringInfo(buf, "numeric(%d,%d)",
1577 ((coercedTypmod - VARHDRSZ) >> 16) & 0xffff,
1578 (coercedTypmod - VARHDRSZ) & 0xffff);
1580 appendStringInfo(buf, "numeric");
1583 appendStringInfo(buf, "%s", quote_identifier(proname));
1588 * Normal function: display as proname(args)
1590 appendStringInfo(buf, "%s(", quote_identifier(proname));
1592 foreach(l, expr->args)
1594 appendStringInfo(buf, sep);
1596 get_rule_expr((Node *) lfirst(l), context);
1598 appendStringInfoChar(buf, ')');
1605 * In an INSERT or UPDATE targetlist item, the parser may have inserted
1606 * a length-coercion function call to coerce the value to the right
1607 * length for the target column. We want to suppress the output of
1608 * that function call, otherwise dump/reload/dump... would blow up the
1609 * expression by adding more and more layers of length-coercion calls.
1611 * As of 7.0, this hack is no longer absolutely essential, because the parser
1612 * is now smart enough not to add a redundant length coercion function call.
1613 * But we still suppress the function call just for neatness of displayed
1616 * Note that this hack must NOT be applied to SELECT targetlist items;
1617 * any length coercion appearing there is something the user actually wrote.
1621 get_tle_expr(TargetEntry *tle, deparse_context *context)
1623 Expr *expr = (Expr *) (tle->expr);
1624 int32 coercedTypmod;
1627 * If top level is a length coercion to the correct length, suppress
1628 * it; else dump the expression normally.
1630 if (tle->resdom->restypmod >= 0 &&
1631 exprIsLengthCoercion((Node *) expr, &coercedTypmod) &&
1632 coercedTypmod == tle->resdom->restypmod)
1633 get_rule_expr((Node *) lfirst(expr->args), context);
1635 get_rule_expr(tle->expr, context);
1642 * Make a string representation of a Const
1646 get_const_expr(Const *constval, deparse_context *context)
1648 StringInfo buf = context->buf;
1650 Form_pg_type typeStruct;
1654 typetup = SearchSysCacheTuple(TYPEOID,
1655 ObjectIdGetDatum(constval->consttype),
1657 if (!HeapTupleIsValid(typetup))
1658 elog(ERROR, "cache lookup of type %u failed", constval->consttype);
1660 typeStruct = (Form_pg_type) GETSTRUCT(typetup);
1662 if (constval->constisnull)
1666 * Always label the type of a NULL constant. This not only
1667 * prevents misdecisions about the type, but it ensures that our
1668 * output is a valid b_expr.
1670 extval = pstrdup(NameStr(typeStruct->typname));
1671 appendStringInfo(buf, "NULL::%s", quote_identifier(extval));
1676 extval = DatumGetCString(OidFunctionCall3(typeStruct->typoutput,
1677 constval->constvalue,
1678 ObjectIdGetDatum(typeStruct->typelem),
1679 Int32GetDatum(-1)));
1681 switch (constval->consttype)
1685 case OIDOID: /* int types */
1687 case FLOAT8OID: /* float types */
1688 /* These types are printed without quotes */
1689 appendStringInfo(buf, extval);
1694 * We must quote any funny characters in the constant's
1695 * representation. XXX Any MULTIBYTE considerations here?
1697 appendStringInfoChar(buf, '\'');
1698 for (valptr = extval; *valptr; valptr++)
1702 if (ch == '\'' || ch == '\\')
1704 appendStringInfoChar(buf, '\\');
1705 appendStringInfoChar(buf, ch);
1707 else if (ch >= 0 && ch < ' ')
1708 appendStringInfo(buf, "\\%03o", (int) ch);
1710 appendStringInfoChar(buf, ch);
1712 appendStringInfoChar(buf, '\'');
1718 switch (constval->consttype)
1723 /* These types can be left unlabeled */
1726 extval = pstrdup(NameStr(typeStruct->typname));
1727 appendStringInfo(buf, "::%s", quote_identifier(extval));
1735 * get_sublink_expr - Parse back a sublink
1739 get_sublink_expr(Node *node, deparse_context *context)
1741 StringInfo buf = context->buf;
1742 SubLink *sublink = (SubLink *) node;
1743 Query *query = (Query *) (sublink->subselect);
1749 appendStringInfoChar(buf, '(');
1751 if (sublink->lefthand != NIL)
1753 need_paren = (length(sublink->lefthand) > 1);
1755 appendStringInfoChar(buf, '(');
1758 foreach(l, sublink->lefthand)
1760 appendStringInfo(buf, sep);
1762 get_rule_expr((Node *) lfirst(l), context);
1766 appendStringInfo(buf, ") ");
1768 appendStringInfoChar(buf, ' ');
1773 switch (sublink->subLinkType)
1775 case EXISTS_SUBLINK:
1776 appendStringInfo(buf, "EXISTS ");
1780 oper = (Oper *) lfirst(sublink->oper);
1781 appendStringInfo(buf, "%s ANY ", get_opname(oper->opno));
1785 oper = (Oper *) lfirst(sublink->oper);
1786 appendStringInfo(buf, "%s ALL ", get_opname(oper->opno));
1789 case MULTIEXPR_SUBLINK:
1790 oper = (Oper *) lfirst(sublink->oper);
1791 appendStringInfo(buf, "%s ", get_opname(oper->opno));
1799 elog(ERROR, "get_sublink_expr: unsupported sublink type %d",
1800 sublink->subLinkType);
1805 appendStringInfoChar(buf, '(');
1807 get_query_def(query, buf, context->rangetables);
1810 appendStringInfo(buf, "))");
1812 appendStringInfoChar(buf, ')');
1816 * quote_identifier - Quote an identifier only if needed
1818 * When quotes are needed, we palloc the required space; slightly
1819 * space-wasteful but well worth it for notational simplicity.
1823 quote_identifier(char *ident)
1827 * Can avoid quoting if ident starts with a lowercase letter and
1828 * contains only lowercase letters, digits, and underscores, *and* is
1829 * not any SQL keyword. Otherwise, supply quotes.
1835 * would like to use <ctype.h> macros here, but they might yield
1836 * unwanted locale-specific results...
1838 safe = (ident[0] >= 'a' && ident[0] <= 'z');
1843 for (ptr = ident + 1; *ptr; ptr++)
1847 safe = ((ch >= 'a' && ch <= 'z') ||
1848 (ch >= '0' && ch <= '9') ||
1859 * Check for keyword. This test is overly strong, since many of
1860 * the "keywords" known to the parser are usable as column names,
1861 * but the parser doesn't provide any easy way to test for whether
1862 * an identifier is safe or not... so be safe not sorry.
1864 * Note: ScanKeywordLookup() expects an all-lower-case input, but
1865 * we've already checked we have that.
1867 if (ScanKeywordLookup(ident) != NULL)
1872 return ident; /* no change needed */
1874 result = (char *) palloc(strlen(ident) + 2 + 1);
1875 sprintf(result, "\"%s\"", ident);
1880 * get_relation_name - Get a relation name by Oid
1884 get_relation_name(Oid relid)
1887 Form_pg_class classStruct;
1889 classtup = SearchSysCacheTuple(RELOID,
1890 ObjectIdGetDatum(relid), 0, 0, 0);
1891 if (!HeapTupleIsValid(classtup))
1892 elog(ERROR, "cache lookup of relation %u failed", relid);
1894 classStruct = (Form_pg_class) GETSTRUCT(classtup);
1895 return pstrdup(NameStr(classStruct->relname));
1900 * get_attribute_name - Get an attribute name by its
1901 * relations Oid and its attnum
1905 get_attribute_name(Oid relid, int2 attnum)
1908 Form_pg_attribute attStruct;
1910 atttup = SearchSysCacheTuple(ATTNUM,
1911 ObjectIdGetDatum(relid), (Datum) attnum,
1913 if (!HeapTupleIsValid(atttup))
1914 elog(ERROR, "cache lookup of attribute %d in relation %u failed",
1917 attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
1918 return pstrdup(NameStr(attStruct->attname));
1924 * Check a targetlist or qual to see if a given rangetable entry
1929 check_if_rte_used(Node *node, Index rt_index, int levelsup)
1931 check_if_rte_used_context context;
1933 context.rt_index = rt_index;
1934 context.levelsup = levelsup;
1935 return check_if_rte_used_walker(node, &context);
1939 check_if_rte_used_walker(Node *node,
1940 check_if_rte_used_context *context)
1946 Var *var = (Var *) node;
1948 return var->varno == context->rt_index &&
1949 var->varlevelsup == context->levelsup;
1951 if (IsA(node, SubLink))
1953 SubLink *sublink = (SubLink *) node;
1954 Query *query = (Query *) sublink->subselect;
1956 /* Recurse into subquery; expression_tree_walker will not */
1957 if (check_if_rte_used((Node *) (query->targetList),
1958 context->rt_index, context->levelsup + 1) ||
1959 check_if_rte_used(query->qual,
1960 context->rt_index, context->levelsup + 1) ||
1961 check_if_rte_used(query->havingQual,
1962 context->rt_index, context->levelsup + 1))
1966 * fall through to let expression_tree_walker examine lefthand
1970 return expression_tree_walker(node, check_if_rte_used_walker,