1 /**********************************************************************
2 * get_ruledef.c - Function to get a rules definition text
6 * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.42 2000/02/20 21:32:12 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 "catalog/pg_type.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/parsetree.h"
53 #include "utils/builtins.h"
54 #include "utils/lsyscache.h"
63 StringInfo buf; /* output buffer to append to */
64 List *rangetables; /* List of List of RangeTblEntry */
65 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(Oid indexrelid)
332 Form_pg_index idxrec;
333 Form_pg_class idxrelrec;
334 Form_pg_class indrelrec;
341 StringInfoData keybuf;
345 * Connect to SPI manager
348 if (SPI_connect() != SPI_OK_CONNECT)
349 elog(ERROR, "get_indexdef: cannot connect to SPI manager");
352 * On the first call prepare the plans to lookup pg_am
356 if (plan_getam == NULL)
361 argtypes[0] = OIDOID;
362 plan = SPI_prepare(query_getam, 1, argtypes);
364 elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getam);
365 plan_getam = SPI_saveplan(plan);
367 argtypes[0] = OIDOID;
368 plan = SPI_prepare(query_getopclass, 1, argtypes);
370 elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getopclass);
371 plan_getopclass = SPI_saveplan(plan);
375 * Fetch the pg_index tuple by the Oid of the index
378 ht_idx = SearchSysCacheTuple(INDEXRELID,
379 ObjectIdGetDatum(indexrelid), 0, 0, 0);
380 if (!HeapTupleIsValid(ht_idx))
381 elog(ERROR, "syscache lookup for index %u failed", indexrelid);
382 idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
385 * Fetch the pg_class tuple of the index relation
388 ht_idxrel = SearchSysCacheTuple(RELOID,
389 ObjectIdGetDatum(idxrec->indexrelid), 0, 0, 0);
390 if (!HeapTupleIsValid(ht_idxrel))
391 elog(ERROR, "syscache lookup for relid %u failed", idxrec->indexrelid);
392 idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
395 * Fetch the pg_class tuple of the indexed relation
398 ht_indrel = SearchSysCacheTuple(RELOID,
399 ObjectIdGetDatum(idxrec->indrelid), 0, 0, 0);
400 if (!HeapTupleIsValid(ht_indrel))
401 elog(ERROR, "syscache lookup for relid %u failed", idxrec->indrelid);
402 indrelrec = (Form_pg_class) GETSTRUCT(ht_indrel);
405 * Get the am name for the index relation
408 spi_args[0] = ObjectIdGetDatum(idxrelrec->relam);
411 spirc = SPI_execp(plan_getam, spi_args, spi_nulls, 1);
412 if (spirc != SPI_OK_SELECT)
413 elog(ERROR, "failed to get pg_am tuple for index %s",
414 NameStr(idxrelrec->relname));
415 if (SPI_processed != 1)
416 elog(ERROR, "failed to get pg_am tuple for index %s",
417 NameStr(idxrelrec->relname));
418 spi_tup = SPI_tuptable->vals[0];
419 spi_ttc = SPI_tuptable->tupdesc;
420 spi_fno = SPI_fnumber(spi_ttc, "amname");
423 * Start the index definition
426 initStringInfo(&buf);
427 appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
428 idxrec->indisunique ? "UNIQUE " : "",
429 quote_identifier(pstrdup(NameStr(idxrelrec->relname))),
430 quote_identifier(pstrdup(NameStr(indrelrec->relname))),
431 quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
435 * Collect the indexed attributes
438 initStringInfo(&keybuf);
440 for (keyno = 0; keyno < INDEX_MAX_KEYS; keyno++)
442 if (idxrec->indkey[keyno] == InvalidAttrNumber)
445 appendStringInfo(&keybuf, sep);
449 * Add the indexed field name
452 appendStringInfo(&keybuf, "%s",
453 quote_identifier(get_attribute_name(idxrec->indrelid,
454 idxrec->indkey[keyno])));
457 * If not a functional index, add the operator class name
460 if (idxrec->indproc == InvalidOid)
462 spi_args[0] = ObjectIdGetDatum(idxrec->indclass[keyno]);
465 spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
466 if (spirc != SPI_OK_SELECT)
467 elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[keyno]);
468 if (SPI_processed != 1)
469 elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[keyno]);
470 spi_tup = SPI_tuptable->vals[0];
471 spi_ttc = SPI_tuptable->tupdesc;
472 spi_fno = SPI_fnumber(spi_ttc, "opcname");
473 appendStringInfo(&keybuf, " %s",
474 quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
480 * For functional index say 'func (attrs) opclass'
483 if (idxrec->indproc != InvalidOid)
486 Form_pg_proc procStruct;
488 proctup = SearchSysCacheTuple(PROCOID,
489 ObjectIdGetDatum(idxrec->indproc), 0, 0, 0);
490 if (!HeapTupleIsValid(proctup))
491 elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc);
493 procStruct = (Form_pg_proc) GETSTRUCT(proctup);
494 appendStringInfo(&buf, "%s(%s) ",
495 quote_identifier(pstrdup(NameStr(procStruct->proname))),
498 spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]);
501 spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
502 if (spirc != SPI_OK_SELECT)
503 elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[0]);
504 if (SPI_processed != 1)
505 elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[0]);
506 spi_tup = SPI_tuptable->vals[0];
507 spi_ttc = SPI_tuptable->tupdesc;
508 spi_fno = SPI_fnumber(spi_ttc, "opcname");
509 appendStringInfo(&buf, "%s",
510 quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
515 * For the others say 'attr opclass [, ...]'
518 appendStringInfo(&buf, "%s", keybuf.data);
524 appendStringInfo(&buf, ")");
527 * Create the result in upper executor memory
530 len = buf.len + VARHDRSZ;
531 indexdef = SPI_palloc(len);
532 VARSIZE(indexdef) = len;
533 memcpy(VARDATA(indexdef), buf.data, buf.len);
538 * Disconnect from SPI manager
541 if (SPI_finish() != SPI_OK_FINISH)
542 elog(ERROR, "get_viewdef: SPI_finish() failed");
549 * get_userbyid - Get a user name by usesysid and
550 * fallback to 'unknown (UID=n)'
554 pg_get_userbyid(int32 uid)
557 Form_pg_shadow user_rec;
561 * Allocate space for the result
564 result = (NameData *) 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), 0, 0, 0);
573 if (HeapTupleIsValid(usertup))
575 user_rec = (Form_pg_shadow) GETSTRUCT(usertup);
576 StrNCpy(NameStr(*result), NameStr(user_rec->usename), NAMEDATALEN);
579 sprintf((char *) result, "unknown (UID=%d)", uid);
585 * deparse_expression - General utility for deparsing expressions
587 * expr is the node tree to be deparsed. It must be a transformed expression
588 * tree (ie, not the raw output of gram.y).
590 * rangetables is a List of Lists of RangeTblEntry nodes: first sublist is for
591 * varlevelsup = 0, next for varlevelsup = 1, etc. In each sublist the first
592 * item is for varno = 1, next varno = 2, etc. (Each sublist has the same
593 * format as the rtable list of a parsetree or query.)
595 * forceprefix is TRUE to force all Vars to be prefixed with their table names.
596 * Otherwise, a prefix is printed only if there's more than one table involved
597 * (and someday the code might try to print one only if there's ambiguity).
599 * The result is a palloc'd string.
603 deparse_expression(Node *expr, List *rangetables, bool forceprefix)
606 deparse_context context;
608 initStringInfo(&buf);
610 context.rangetables = rangetables;
611 context.varprefix = (forceprefix ||
612 length(rangetables) != 1 ||
613 length((List *) lfirst(rangetables)) != 1);
615 rulename = ""; /* in case of errors */
617 get_rule_expr(expr, &context);
623 * make_ruledef - reconstruct the CREATE RULE command
624 * for a given pg_rewrite tuple
628 make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
641 * Get the attribute values from the rules tuple
644 fno = SPI_fnumber(rulettc, "ev_type");
645 ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
647 fno = SPI_fnumber(rulettc, "ev_class");
648 ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull);
650 fno = SPI_fnumber(rulettc, "ev_attr");
651 ev_attr = (int2) SPI_getbinval(ruletup, rulettc, fno, &isnull);
653 fno = SPI_fnumber(rulettc, "is_instead");
654 is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);
656 fno = SPI_fnumber(rulettc, "ev_qual");
657 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
659 fno = SPI_fnumber(rulettc, "ev_action");
660 ev_action = SPI_getvalue(ruletup, rulettc, fno);
661 if (ev_action != NULL)
662 actions = (List *) stringToNode(ev_action);
666 * Build the rules definition text
669 appendStringInfo(buf, "CREATE RULE %s AS ON ",
670 quote_identifier(rulename));
672 /* The event the rule is fired for */
676 appendStringInfo(buf, "SELECT");
680 appendStringInfo(buf, "UPDATE");
684 appendStringInfo(buf, "INSERT");
688 appendStringInfo(buf, "DELETE");
692 elog(ERROR, "get_ruledef: rule %s has unsupported event type %d",
697 /* The relation the rule is fired on */
698 appendStringInfo(buf, " TO %s",
699 quote_identifier(get_relation_name(ev_class)));
701 appendStringInfo(buf, ".%s",
702 quote_identifier(get_attribute_name(ev_class,
705 /* If the rule has an event qualification, add it */
708 if (strlen(ev_qual) > 0 && strcmp(ev_qual, "<>") != 0)
712 deparse_context context;
714 appendStringInfo(buf, " WHERE ");
716 qual = stringToNode(ev_qual);
717 query = (Query *) lfirst(actions);
720 context.rangetables = lcons(query->rtable, NIL);
721 context.varprefix = (length(query->rtable) != 1);
723 get_rule_expr(qual, &context);
726 appendStringInfo(buf, " DO ");
728 /* The INSTEAD keyword (if so) */
730 appendStringInfo(buf, "INSTEAD ");
732 /* Finally the rules actions */
733 if (length(actions) > 1)
738 appendStringInfo(buf, "(");
739 foreach(action, actions)
741 query = (Query *) lfirst(action);
742 get_query_def(query, buf, NIL);
743 appendStringInfo(buf, "; ");
745 appendStringInfo(buf, ");");
749 if (length(actions) == 0)
751 appendStringInfo(buf, "NOTHING;");
757 query = (Query *) lfirst(actions);
758 get_query_def(query, buf, NIL);
759 appendStringInfo(buf, ";");
766 * make_viewdef - reconstruct the SELECT part of a
771 make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc)
785 * Get the attribute values from the rules tuple
788 fno = SPI_fnumber(rulettc, "ev_type");
789 ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
791 fno = SPI_fnumber(rulettc, "ev_class");
792 ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull);
794 fno = SPI_fnumber(rulettc, "ev_attr");
795 ev_attr = (int2) SPI_getbinval(ruletup, rulettc, fno, &isnull);
797 fno = SPI_fnumber(rulettc, "is_instead");
798 is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);
800 fno = SPI_fnumber(rulettc, "ev_qual");
801 ev_qual = SPI_getvalue(ruletup, rulettc, fno);
803 fno = SPI_fnumber(rulettc, "ev_action");
804 ev_action = SPI_getvalue(ruletup, rulettc, fno);
805 if (ev_action != NULL)
806 actions = (List *) stringToNode(ev_action);
808 if (length(actions) != 1)
810 appendStringInfo(buf, "Not a view");
814 query = (Query *) lfirst(actions);
816 if (ev_type != '1' || ev_attr >= 0 || !is_instead || strcmp(ev_qual, "<>"))
818 appendStringInfo(buf, "Not a view");
822 get_query_def(query, buf, NIL);
823 appendStringInfo(buf, ";");
828 * get_query_def - Parse back one action from
829 * the parsetree in the actions
834 get_query_def(Query *query, StringInfo buf, List *parentrtables)
836 deparse_context context;
839 context.rangetables = lcons(query->rtable, parentrtables);
840 context.varprefix = (parentrtables != NIL ||
841 length(query->rtable) != 1);
843 switch (query->commandType)
846 get_select_query_def(query, &context);
850 get_update_query_def(query, &context);
854 get_insert_query_def(query, &context);
858 get_delete_query_def(query, &context);
862 appendStringInfo(buf, "NOTHING");
866 elog(ERROR, "get_ruledef of %s: query command type %d not implemented yet",
867 rulename, query->commandType);
874 * get_select_query_def - Parse back a SELECT parsetree
878 get_select_query_def(Query *query, deparse_context *context)
880 StringInfo buf = context->buf;
887 bool rt_constonly = TRUE;
892 * First we need to know which and how many of the
893 * range table entries in the query are used in the target list
894 * or queries qualification
897 rt_length = length(query->rtable);
898 rt_used = palloc(sizeof(bool) * rt_length);
899 for (i = 0; i < rt_length; i++)
901 if (check_if_rte_used((Node *) (query->targetList), i + 1, 0) ||
902 check_if_rte_used(query->qual, i + 1, 0) ||
903 check_if_rte_used(query->havingQual, i + 1, 0))
913 * Now check if any of the used rangetable entries is different
914 * from *NEW* and *CURRENT*. If so we must provide the FROM clause
919 foreach(l, query->rtable)
924 rte = (RangeTblEntry *) lfirst(l);
925 if (!strcmp(rte->ref->relname, "*NEW*"))
927 if (!strcmp(rte->ref->relname, "*CURRENT*"))
930 rt_constonly = FALSE;
935 * Build up the query string - first we say SELECT
938 appendStringInfo(buf, "SELECT");
940 /* Then we tell what to select (the targetlist) */
942 foreach(l, query->targetList)
944 bool tell_as = FALSE;
946 tle = (TargetEntry *) lfirst(l);
947 appendStringInfo(buf, sep);
950 get_tle_expr(tle, context);
952 /* Check if we must say AS ... */
953 if (! IsA(tle->expr, Var))
954 tell_as = strcmp(tle->resdom->resname, "?column?");
957 Var *var = (Var *) (tle->expr);
960 rte = get_rte_for_var(var, context);
961 attname = get_attribute_name(rte->relid, var->varattno);
962 if (strcmp(attname, tle->resdom->resname))
968 appendStringInfo(buf, " AS %s",
969 quote_identifier(tle->resdom->resname));
972 /* If we need other tables than *NEW* or *CURRENT* add the FROM clause */
973 if (!rt_constonly && rt_numused > 0)
977 foreach(l, query->rtable)
981 rte = (RangeTblEntry *) lfirst(l);
983 if (!strcmp(rte->ref->relname, "*NEW*"))
986 if (!strcmp(rte->ref->relname, "*CURRENT*"))
989 appendStringInfo(buf, sep);
991 appendStringInfo(buf, "%s%s",
992 quote_identifier(rte->relname),
993 inherit_marker(rte));
994 if (strcmp(rte->relname, rte->ref->relname) != 0)
995 appendStringInfo(buf, " %s",
996 quote_identifier(rte->ref->relname));
997 if (rte->ref->attrs != NIL)
1001 appendStringInfo(buf, " (");
1002 foreach(col, rte->ref->attrs)
1004 if (col != rte->ref->attrs)
1005 appendStringInfo(buf, ", ");
1006 appendStringInfo(buf, "%s",
1007 quote_identifier(strVal(lfirst(col))));
1009 appendStringInfoChar(buf, ')');
1015 /* Add the WHERE clause if given */
1016 if (query->qual != NULL)
1018 appendStringInfo(buf, " WHERE ");
1019 get_rule_expr(query->qual, context);
1022 /* Add the GROUP BY CLAUSE */
1023 if (query->groupClause != NULL)
1025 appendStringInfo(buf, " GROUP BY ");
1027 foreach(l, query->groupClause)
1029 GroupClause *grp = (GroupClause *) lfirst(l);
1032 groupexpr = get_sortgroupclause_expr(grp,
1034 appendStringInfo(buf, sep);
1035 get_rule_expr(groupexpr, context);
1043 * get_insert_query_def - Parse back an INSERT parsetree
1047 get_insert_query_def(Query *query, deparse_context *context)
1049 StringInfo buf = context->buf;
1056 bool rt_constonly = TRUE;
1061 * We need to know if other tables than *NEW* or *CURRENT*
1062 * are used in the query. If not, it's an INSERT ... VALUES,
1063 * otherwise an INSERT ... SELECT.
1066 rt_length = length(query->rtable);
1067 rt_used = palloc(sizeof(bool) * rt_length);
1068 for (i = 0; i < rt_length; i++)
1070 if (check_if_rte_used((Node *) (query->targetList), i + 1, 0) ||
1071 check_if_rte_used(query->qual, i + 1, 0) ||
1072 check_if_rte_used(query->havingQual, i + 1, 0))
1082 foreach(l, query->rtable)
1087 rte = (RangeTblEntry *) lfirst(l);
1088 if (!strcmp(rte->ref->relname, "*NEW*"))
1090 if (!strcmp(rte->ref->relname, "*CURRENT*"))
1093 rt_constonly = FALSE;
1098 * Start the query with INSERT INTO relname
1101 rte = rt_fetch(query->resultRelation, query->rtable);
1102 appendStringInfo(buf, "INSERT INTO %s",
1103 quote_identifier(rte->relname));
1105 /* Add the target list */
1107 foreach(l, query->targetList)
1109 tle = (TargetEntry *) lfirst(l);
1111 appendStringInfo(buf, sep);
1113 appendStringInfo(buf, "%s", quote_identifier(tle->resdom->resname));
1115 appendStringInfo(buf, ") ");
1117 /* Add the VALUES or the SELECT */
1118 if (rt_constonly && query->qual == NULL)
1120 appendStringInfo(buf, "VALUES (");
1122 foreach(l, query->targetList)
1124 tle = (TargetEntry *) lfirst(l);
1126 appendStringInfo(buf, sep);
1128 get_tle_expr(tle, context);
1130 appendStringInfoChar(buf, ')');
1133 get_select_query_def(query, context);
1138 * get_update_query_def - Parse back an UPDATE parsetree
1142 get_update_query_def(Query *query, deparse_context *context)
1144 StringInfo buf = context->buf;
1151 * Start the query with UPDATE relname SET
1154 rte = rt_fetch(query->resultRelation, query->rtable);
1155 appendStringInfo(buf, "UPDATE %s%s SET ",
1156 quote_identifier(rte->relname),
1157 inherit_marker(rte));
1159 /* Add the comma separated list of 'attname = value' */
1161 foreach(l, query->targetList)
1163 tle = (TargetEntry *) lfirst(l);
1165 appendStringInfo(buf, sep);
1167 appendStringInfo(buf, "%s = ",
1168 quote_identifier(tle->resdom->resname));
1169 get_tle_expr(tle, context);
1172 /* Finally add a WHERE clause if given */
1173 if (query->qual != NULL)
1175 appendStringInfo(buf, " WHERE ");
1176 get_rule_expr(query->qual, context);
1182 * get_delete_query_def - Parse back a DELETE parsetree
1186 get_delete_query_def(Query *query, deparse_context *context)
1188 StringInfo buf = context->buf;
1192 * Start the query with DELETE FROM relname
1195 rte = rt_fetch(query->resultRelation, query->rtable);
1196 appendStringInfo(buf, "DELETE FROM %s%s",
1197 quote_identifier(rte->relname),
1198 inherit_marker(rte));
1200 /* Add a WHERE clause if given */
1201 if (query->qual != NULL)
1203 appendStringInfo(buf, " WHERE ");
1204 get_rule_expr(query->qual, context);
1209 * Find the RTE referenced by a (possibly nonlocal) Var.
1211 static RangeTblEntry *
1212 get_rte_for_var(Var *var, deparse_context *context)
1214 List *rtlist = context->rangetables;
1215 int sup = var->varlevelsup;
1218 rtlist = lnext(rtlist);
1220 return rt_fetch(var->varno, (List *) lfirst(rtlist));
1225 * get_rule_expr - Parse back an expression
1229 get_rule_expr(Node *node, deparse_context *context)
1231 StringInfo buf = context->buf;
1237 * Each level of get_rule_expr must emit an indivisible term
1238 * (parenthesized if necessary) to ensure result is reparsed into
1239 * the same expression tree.
1241 * There might be some work left here to support additional node types.
1242 * Can we ever see Param nodes here?
1245 switch (nodeTag(node))
1248 get_const_expr((Const *) node, context);
1253 Var *var = (Var *) node;
1254 RangeTblEntry *rte = get_rte_for_var(var, context);
1256 if (context->varprefix)
1258 if (!strcmp(rte->ref->relname, "*NEW*"))
1259 appendStringInfo(buf, "new.");
1260 else if (!strcmp(rte->ref->relname, "*CURRENT*"))
1261 appendStringInfo(buf, "old.");
1263 appendStringInfo(buf, "%s.",
1264 quote_identifier(rte->ref->relname));
1266 appendStringInfo(buf, "%s",
1267 quote_identifier(get_attribute_name(rte->relid,
1274 Expr *expr = (Expr *) node;
1275 List *args = expr->args;
1278 * Expr nodes have to be handled a bit detailed
1281 switch (expr->opType)
1284 appendStringInfoChar(buf, '(');
1285 if (length(args) == 2)
1287 /* binary operator */
1288 get_rule_expr((Node *) lfirst(args), context);
1289 appendStringInfo(buf, " %s ",
1290 get_opname(((Oper *) expr->oper)->opno));
1291 get_rule_expr((Node *) lsecond(args), context);
1295 /* unary operator --- but which side? */
1296 Oid opno = ((Oper *) expr->oper)->opno;
1298 Form_pg_operator optup;
1300 tp = SearchSysCacheTuple(OPEROID,
1301 ObjectIdGetDatum(opno),
1303 Assert(HeapTupleIsValid(tp));
1304 optup = (Form_pg_operator) GETSTRUCT(tp);
1305 switch (optup->oprkind)
1308 appendStringInfo(buf, "%s ",
1310 get_rule_expr((Node *) lfirst(args),
1314 get_rule_expr((Node *) lfirst(args),
1316 appendStringInfo(buf, " %s",
1320 elog(ERROR, "get_rule_expr: bogus oprkind");
1323 appendStringInfoChar(buf, ')');
1327 appendStringInfoChar(buf, '(');
1328 get_rule_expr((Node *) lfirst(args), context);
1329 while ((args = lnext(args)) != NIL)
1331 appendStringInfo(buf, " OR ");
1332 get_rule_expr((Node *) lfirst(args), context);
1334 appendStringInfoChar(buf, ')');
1338 appendStringInfoChar(buf, '(');
1339 get_rule_expr((Node *) lfirst(args), context);
1340 while ((args = lnext(args)) != NIL)
1342 appendStringInfo(buf, " AND ");
1343 get_rule_expr((Node *) lfirst(args), context);
1345 appendStringInfoChar(buf, ')');
1349 appendStringInfo(buf, "(NOT ");
1350 get_rule_expr((Node *) lfirst(args), context);
1351 appendStringInfoChar(buf, ')');
1355 get_func_expr((Expr *) node, context);
1359 elog(ERROR, "get_rule_expr: expr opType %d not supported",
1367 Aggref *aggref = (Aggref *) node;
1369 appendStringInfo(buf, "%s(%s",
1370 quote_identifier(aggref->aggname),
1371 aggref->aggdistinct ? "DISTINCT " : "");
1372 if (aggref->aggstar)
1373 appendStringInfo(buf, "*");
1375 get_rule_expr(aggref->target, context);
1376 appendStringInfoChar(buf, ')');
1381 get_rule_expr(((Iter *) node)->iterexpr, context);
1386 ArrayRef *aref = (ArrayRef *) node;
1390 get_rule_expr(aref->refexpr, context);
1391 lowlist = aref->reflowerindexpr;
1392 foreach(uplist, aref->refupperindexpr)
1394 appendStringInfo(buf, "[");
1397 get_rule_expr((Node *) lfirst(lowlist), context);
1398 appendStringInfo(buf, ":");
1399 lowlist = lnext(lowlist);
1401 get_rule_expr((Node *) lfirst(uplist), context);
1402 appendStringInfo(buf, "]");
1404 /* XXX need to do anything with refassgnexpr? */
1410 RelabelType *relabel = (RelabelType *) node;
1412 Form_pg_type typeStruct;
1415 appendStringInfoChar(buf, '(');
1416 get_rule_expr(relabel->arg, context);
1417 typetup = SearchSysCacheTuple(TYPEOID,
1418 ObjectIdGetDatum(relabel->resulttype),
1420 if (!HeapTupleIsValid(typetup))
1421 elog(ERROR, "cache lookup of type %u failed",
1422 relabel->resulttype);
1423 typeStruct = (Form_pg_type) GETSTRUCT(typetup);
1424 extval = pstrdup(NameStr(typeStruct->typname));
1425 appendStringInfo(buf, ")::%s", quote_identifier(extval));
1432 CaseExpr *caseexpr = (CaseExpr *) node;
1435 appendStringInfo(buf, "CASE");
1436 foreach(temp, caseexpr->args)
1438 CaseWhen *when = (CaseWhen *) lfirst(temp);
1440 appendStringInfo(buf, " WHEN ");
1441 get_rule_expr(when->expr, context);
1442 appendStringInfo(buf, " THEN ");
1443 get_rule_expr(when->result, context);
1445 appendStringInfo(buf, " ELSE ");
1446 get_rule_expr(caseexpr->defresult, context);
1447 appendStringInfo(buf, " END");
1452 get_sublink_expr(node, context);
1456 printf("\n%s\n", nodeToString(node));
1457 elog(ERROR, "get_ruledef of %s: unknown node type %d in get_rule_expr()",
1458 rulename, nodeTag(node));
1465 * get_func_expr - Parse back a Func node
1469 get_func_expr(Expr *expr, deparse_context *context)
1471 StringInfo buf = context->buf;
1473 Form_pg_proc procStruct;
1476 Func *func = (Func *) (expr->oper);
1480 * Get the functions pg_proc tuple
1483 proctup = SearchSysCacheTuple(PROCOID,
1484 ObjectIdGetDatum(func->funcid),
1486 if (!HeapTupleIsValid(proctup))
1487 elog(ERROR, "cache lookup for proc %u failed", func->funcid);
1489 procStruct = (Form_pg_proc) GETSTRUCT(proctup);
1490 proname = pstrdup(NameStr(procStruct->proname));
1493 * nullvalue() and nonnullvalue() should get turned into special syntax
1495 if (procStruct->pronargs == 1 && procStruct->proargtypes[0] == InvalidOid)
1497 if (!strcmp(proname, "nullvalue"))
1499 appendStringInfoChar(buf, '(');
1500 get_rule_expr((Node *) lfirst(expr->args), context);
1501 appendStringInfo(buf, " ISNULL)");
1504 if (!strcmp(proname, "nonnullvalue"))
1506 appendStringInfoChar(buf, '(');
1507 get_rule_expr((Node *) lfirst(expr->args), context);
1508 appendStringInfo(buf, " NOTNULL)");
1514 * Build a string of proname(args)
1517 appendStringInfo(buf, "%s(", quote_identifier(proname));
1519 foreach(l, expr->args)
1521 appendStringInfo(buf, sep);
1523 get_rule_expr((Node *) lfirst(l), context);
1525 appendStringInfoChar(buf, ')');
1532 * A target list expression is a bit different from a normal expression.
1533 * If the target column has an atttypmod, the parser usually puts a
1534 * padding-/cut-function call around the expression itself.
1535 * We must get rid of it, otherwise dump/reload/dump... would blow up
1540 get_tle_expr(TargetEntry *tle, deparse_context *context)
1542 Expr *expr = (Expr *) (tle->expr);
1545 Form_pg_proc procStruct;
1546 Form_pg_type typeStruct;
1550 * Check if the result has an atttypmod and if the
1551 * expression in the targetlist entry is a function call
1554 if (tle->resdom->restypmod < 0 ||
1555 ! IsA(expr, Expr) ||
1556 expr->opType != FUNC_EXPR)
1558 get_rule_expr(tle->expr, context);
1562 func = (Func *) (expr->oper);
1565 * Get the functions pg_proc tuple
1568 tup = SearchSysCacheTuple(PROCOID,
1569 ObjectIdGetDatum(func->funcid), 0, 0, 0);
1570 if (!HeapTupleIsValid(tup))
1571 elog(ERROR, "cache lookup for proc %u failed", func->funcid);
1572 procStruct = (Form_pg_proc) GETSTRUCT(tup);
1575 * It must be a function with two arguments where the first
1576 * is of the same type as the return value and the second is
1580 if (procStruct->pronargs != 2 ||
1581 procStruct->prorettype != procStruct->proargtypes[0] ||
1582 procStruct->proargtypes[1] != INT4OID)
1584 get_rule_expr(tle->expr, context);
1589 * Furthermore, the name of the function must be the same
1590 * as the argument/result type name.
1592 tup = SearchSysCacheTuple(TYPEOID,
1593 ObjectIdGetDatum(procStruct->prorettype),
1595 if (!HeapTupleIsValid(tup))
1596 elog(ERROR, "cache lookup for type %u failed",
1597 procStruct->prorettype);
1598 typeStruct = (Form_pg_type) GETSTRUCT(tup);
1599 if (strncmp(NameStr(procStruct->proname),
1600 NameStr(typeStruct->typname),
1603 get_rule_expr(tle->expr, context);
1608 * Finally (to be totally safe) the second argument must be a
1609 * const and match the value in the results atttypmod.
1612 second_arg = (Const *) lsecond(expr->args);
1613 if (! IsA(second_arg, Const) ||
1614 DatumGetInt32(second_arg->constvalue) != tle->resdom->restypmod)
1616 get_rule_expr(tle->expr, context);
1621 * Whow - got it. Now get rid of the padding function
1624 get_rule_expr((Node *) lfirst(expr->args), context);
1631 * Make a string representation of a Const
1635 get_const_expr(Const *constval, deparse_context *context)
1637 StringInfo buf = context->buf;
1639 Form_pg_type typeStruct;
1640 FmgrInfo finfo_output;
1644 typetup = SearchSysCacheTuple(TYPEOID,
1645 ObjectIdGetDatum(constval->consttype),
1647 if (!HeapTupleIsValid(typetup))
1648 elog(ERROR, "cache lookup of type %u failed", constval->consttype);
1650 typeStruct = (Form_pg_type) GETSTRUCT(typetup);
1652 if (constval->constisnull)
1655 * Always label the type of a NULL constant. This not only
1656 * prevents misdecisions about the type, but it ensures that
1657 * our output is a valid b_expr.
1659 extval = pstrdup(NameStr(typeStruct->typname));
1660 appendStringInfo(buf, "NULL::%s", quote_identifier(extval));
1665 fmgr_info(typeStruct->typoutput, &finfo_output);
1666 extval = (char *) (*fmgr_faddr(&finfo_output)) (constval->constvalue,
1667 typeStruct->typelem,
1670 switch (constval->consttype)
1674 case OIDOID: /* int types */
1676 case FLOAT8OID: /* float types */
1677 /* These types are printed without quotes */
1678 appendStringInfo(buf, extval);
1682 * We must quote any funny characters in the constant's
1684 * XXX Any MULTIBYTE considerations here?
1686 appendStringInfoChar(buf, '\'');
1687 for (valptr = extval; *valptr; valptr++)
1690 if (ch == '\'' || ch == '\\')
1692 appendStringInfoChar(buf, '\\');
1693 appendStringInfoChar(buf, ch);
1695 else if (ch >= 0 && ch < ' ')
1696 appendStringInfo(buf, "\\%03o", (int) ch);
1698 appendStringInfoChar(buf, ch);
1700 appendStringInfoChar(buf, '\'');
1706 switch (constval->consttype)
1711 /* These types can be left unlabeled */
1714 extval = pstrdup(NameStr(typeStruct->typname));
1715 appendStringInfo(buf, "::%s", quote_identifier(extval));
1723 * get_sublink_expr - Parse back a sublink
1727 get_sublink_expr(Node *node, deparse_context *context)
1729 StringInfo buf = context->buf;
1730 SubLink *sublink = (SubLink *) node;
1731 Query *query = (Query *) (sublink->subselect);
1737 appendStringInfoChar(buf, '(');
1739 if (sublink->lefthand != NIL)
1741 need_paren = (length(sublink->lefthand) > 1);
1743 appendStringInfoChar(buf, '(');
1746 foreach(l, sublink->lefthand)
1748 appendStringInfo(buf, sep);
1750 get_rule_expr((Node *) lfirst(l), context);
1754 appendStringInfo(buf, ") ");
1756 appendStringInfoChar(buf, ' ');
1761 switch (sublink->subLinkType)
1763 case EXISTS_SUBLINK:
1764 appendStringInfo(buf, "EXISTS ");
1768 oper = (Oper *) lfirst(sublink->oper);
1769 appendStringInfo(buf, "%s ANY ", get_opname(oper->opno));
1773 oper = (Oper *) lfirst(sublink->oper);
1774 appendStringInfo(buf, "%s ALL ", get_opname(oper->opno));
1777 case MULTIEXPR_SUBLINK:
1778 oper = (Oper *) lfirst(sublink->oper);
1779 appendStringInfo(buf, "%s ", get_opname(oper->opno));
1787 elog(ERROR, "get_sublink_expr: unsupported sublink type %d",
1788 sublink->subLinkType);
1793 appendStringInfoChar(buf, '(');
1795 get_query_def(query, buf, context->rangetables);
1798 appendStringInfo(buf, "))");
1800 appendStringInfoChar(buf, ')');
1804 * quote_identifier - Quote an identifier only if needed
1806 * When quotes are needed, we palloc the required space; slightly
1807 * space-wasteful but well worth it for notational simplicity.
1811 quote_identifier(char *ident)
1814 * Can avoid quoting if ident starts with a lowercase letter and
1815 * contains only lowercase letters, digits, and underscores,
1816 * *and* is not any SQL keyword. Otherwise, supply quotes.
1822 * would like to use <ctype.h> macros here, but they might yield
1823 * unwanted locale-specific results...
1825 safe = (ident[0] >= 'a' && ident[0] <= 'z');
1830 for (ptr = ident+1; *ptr; ptr++)
1834 safe = ((ch >= 'a' && ch <= 'z') ||
1835 (ch >= '0' && ch <= '9') ||
1845 * Check for keyword. This test is overly strong, since many of
1846 * the "keywords" known to the parser are usable as column names,
1847 * but the parser doesn't provide any easy way to test for whether
1848 * an identifier is safe or not... so be safe not sorry.
1850 * Note: ScanKeywordLookup() expects an all-lower-case input, but
1851 * we've already checked we have that.
1853 if (ScanKeywordLookup(ident) != NULL)
1858 return ident; /* no change needed */
1860 result = (char *) palloc(strlen(ident) + 2 + 1);
1861 sprintf(result, "\"%s\"", ident);
1866 * get_relation_name - Get a relation name by Oid
1870 get_relation_name(Oid relid)
1873 Form_pg_class classStruct;
1875 classtup = SearchSysCacheTuple(RELOID,
1876 ObjectIdGetDatum(relid), 0, 0, 0);
1877 if (!HeapTupleIsValid(classtup))
1878 elog(ERROR, "cache lookup of relation %u failed", relid);
1880 classStruct = (Form_pg_class) GETSTRUCT(classtup);
1881 return pstrdup(NameStr(classStruct->relname));
1886 * get_attribute_name - Get an attribute name by its
1887 * relations Oid and its attnum
1891 get_attribute_name(Oid relid, int2 attnum)
1894 Form_pg_attribute attStruct;
1896 atttup = SearchSysCacheTuple(ATTNUM,
1897 ObjectIdGetDatum(relid), (Datum) attnum,
1899 if (!HeapTupleIsValid(atttup))
1900 elog(ERROR, "cache lookup of attribute %d in relation %u failed",
1903 attStruct = (Form_pg_attribute) GETSTRUCT(atttup);
1904 return pstrdup(NameStr(attStruct->attname));
1910 * Check a targetlist or qual to see if a given rangetable entry
1915 check_if_rte_used(Node *node, Index rt_index, int levelsup)
1917 check_if_rte_used_context context;
1919 context.rt_index = rt_index;
1920 context.levelsup = levelsup;
1921 return check_if_rte_used_walker(node, &context);
1925 check_if_rte_used_walker(Node *node,
1926 check_if_rte_used_context *context)
1932 Var *var = (Var *) node;
1934 return var->varno == context->rt_index &&
1935 var->varlevelsup == context->levelsup;
1937 if (IsA(node, SubLink))
1939 SubLink *sublink = (SubLink *) node;
1940 Query *query = (Query *) sublink->subselect;
1942 /* Recurse into subquery; expression_tree_walker will not */
1943 if (check_if_rte_used((Node *) (query->targetList),
1944 context->rt_index, context->levelsup + 1) ||
1945 check_if_rte_used(query->qual,
1946 context->rt_index, context->levelsup + 1) ||
1947 check_if_rte_used(query->havingQual,
1948 context->rt_index, context->levelsup + 1))
1950 /* fall through to let expression_tree_walker examine lefthand args */
1952 return expression_tree_walker(node, check_if_rte_used_walker,