aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/view.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/view.c')
-rw-r--r--src/backend/commands/view.c325
1 files changed, 325 insertions, 0 deletions
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
new file mode 100644
index 00000000000..f6023ca08de
--- /dev/null
+++ b/src/backend/commands/view.c
@@ -0,0 +1,325 @@
+/*-------------------------------------------------------------------------
+ *
+ * view.c--
+ * use rewrite rules to construct views
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.1.1.1 1996/07/09 06:21:22 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdio.h> /* for sprintf() */
+#include "postgres.h"
+#include "access/heapam.h"
+#include "access/xact.h"
+#include "utils/builtins.h"
+#include "utils/syscache.h"
+#include "utils/elog.h"
+#include "utils/palloc.h"
+#include "nodes/relation.h"
+#include "nodes/primnodes.h"
+#include "nodes/parsenodes.h"
+#include "parser/catalog_utils.h"
+#include "parser/parse_query.h"
+#include "rewrite/rewriteDefine.h"
+#include "rewrite/rewriteHandler.h"
+#include "rewrite/rewriteManip.h"
+#include "rewrite/rewriteRemove.h"
+#include "commands/creatinh.h"
+
+/*---------------------------------------------------------------------
+ * DefineVirtualRelation
+ *
+ * Create the "view" relation.
+ * `DefineRelation' does all the work, we just provide the correct
+ * arguments!
+ *
+ * If the relation already exists, then 'DefineRelation' will abort
+ * the xact...
+ *---------------------------------------------------------------------
+ */
+static void
+DefineVirtualRelation(char *relname, List *tlist)
+{
+ CreateStmt createStmt;
+ List *attrList, *t;
+ TargetEntry *entry;
+ Resdom *res;
+ char *resname;
+ char *restypename;
+
+ /*
+ * create a list with one entry per attribute of this relation.
+ * Each entry is a two element list. The first element is the
+ * name of the attribute (a string) and the second the name of the type
+ * (NOTE: a string, not a type id!).
+ */
+ attrList = NIL;
+ if (tlist!=NIL) {
+ foreach (t, tlist ) {
+ ColumnDef *def = makeNode(ColumnDef);
+ TypeName *typename;
+
+ /*
+ * find the names of the attribute & its type
+ */
+ entry = lfirst(t);
+ res = entry->resdom;
+ resname = res->resname;
+ restypename = tname(get_id_type((long)res->restype));
+
+ typename = makeNode(TypeName);
+
+ typename->name = pstrdup(restypename);
+ def->colname = pstrdup(resname);
+
+ def->typename = typename;
+
+ attrList = lappend(attrList, def);
+ }
+ } else {
+ elog ( WARN, "attempted to define virtual relation with no attrs");
+ }
+
+ /*
+ * now create the parametesr for keys/inheritance etc.
+ * All of them are nil...
+ */
+ createStmt.relname = relname;
+ createStmt.tableElts = attrList;
+/* createStmt.tableType = NULL;*/
+ createStmt.inhRelnames = NIL;
+ createStmt.archiveType = ARCH_NONE;
+ createStmt.location = -1;
+ createStmt.archiveLoc = -1;
+
+ /*
+ * finally create the relation...
+ */
+ DefineRelation(&createStmt);
+}
+
+/*------------------------------------------------------------------
+ * makeViewRetrieveRuleName
+ *
+ * Given a view name, returns the name for the 'on retrieve to "view"'
+ * rule.
+ * This routine is called when defining/removing a view.
+ *
+ * NOTE: it quarantees that the name is at most 15 chars long
+ *
+ * XXX it also means viewName cannot be 16 chars long! - ay 11/94
+ *------------------------------------------------------------------
+ */
+char *
+MakeRetrieveViewRuleName(char *viewName)
+{
+/*
+ char buf[100];
+
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "_RET%.*s", NAMEDATALEN, viewName->data);
+ buf[15] = '\0';
+ namestrcpy(rule_name, buf);
+*/
+
+ char *buf;
+ buf = palloc(strlen(viewName) + 5);
+ sprintf(buf, "_RET%s",viewName);
+ return buf;
+}
+
+static RuleStmt *
+FormViewRetrieveRule(char *viewName, Query *viewParse)
+{
+ RuleStmt *rule;
+ char *rname;
+ Attr *attr;
+
+ /*
+ * Create a RuleStmt that corresponds to the suitable
+ * rewrite rule args for DefineQueryRewrite();
+ */
+ rule = makeNode(RuleStmt);
+ rname = MakeRetrieveViewRuleName(viewName);
+
+ attr = makeNode(Attr);
+ attr->relname = pstrdup(viewName);
+/* attr->refname = pstrdup(viewName);*/
+ rule->rulename = pstrdup(rname);
+ rule->whereClause = NULL;
+ rule->event = CMD_SELECT;
+ rule->object = attr;
+ rule->instead = true;
+ rule->actions = lcons(viewParse, NIL);
+
+ return rule;
+}
+
+static void
+DefineViewRules(char *viewName, Query *viewParse)
+{
+ RuleStmt *retrieve_rule = NULL;
+#ifdef NOTYET
+ RuleStmt *replace_rule = NULL;
+ RuleStmt *append_rule = NULL;
+ RuleStmt *delete_rule = NULL;
+#endif
+
+ retrieve_rule =
+ FormViewRetrieveRule(viewName, viewParse);
+
+#ifdef NOTYET
+
+ replace_rule =
+ FormViewReplaceRule(viewName, viewParse);
+ append_rule =
+ FormViewAppendRule(viewName, viewParse);
+ delete_rule =
+ FormViewDeleteRule(viewName, viewParse);
+
+#endif
+
+ DefineQueryRewrite(retrieve_rule);
+
+#ifdef NOTYET
+ DefineQueryRewrite(replace_rule);
+ DefineQueryRewrite(append_rule);
+ DefineQueryRewrite(delete_rule);
+#endif
+
+}
+
+/*---------------------------------------------------------------
+ * UpdateRangeTableOfViewParse
+ *
+ * Update the range table of the given parsetree.
+ * This update consists of adding two new entries IN THE BEGINNING
+ * of the range table (otherwise the rule system will die a slow,
+ * horrible and painful death, and we do not want that now, do we?)
+ * one for the CURRENT relation and one for the NEW one (both of
+ * them refer in fact to the "view" relation).
+ *
+ * Of course we must also increase the 'varnos' of all the Var nodes
+ * by 2...
+ *
+ * NOTE: these are destructive changes. It would be difficult to
+ * make a complete copy of the parse tree and make the changes
+ * in the copy.
+ *---------------------------------------------------------------
+ */
+static void
+UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
+{
+ List *old_rt;
+ List *new_rt;
+ RangeTblEntry *rt_entry1, *rt_entry2;
+
+ /*
+ * first offset all var nodes by 2
+ */
+ OffsetVarNodes((Node*)viewParse->targetList, 2);
+ OffsetVarNodes(viewParse->qual, 2);
+
+ /*
+ * find the old range table...
+ */
+ old_rt = viewParse->rtable;
+
+ /*
+ * create the 2 new range table entries and form the new
+ * range table...
+ * CURRENT first, then NEW....
+ */
+ rt_entry1 =
+ makeRangeTableEntry((char*)viewName, FALSE, NULL, "*CURRENT*");
+ rt_entry2 =
+ makeRangeTableEntry((char*)viewName, FALSE, NULL, "*NEW*");
+ new_rt = lcons(rt_entry2, old_rt);
+ new_rt = lcons(rt_entry1, new_rt);
+
+ /*
+ * Now the tricky part....
+ * Update the range table in place... Be careful here, or
+ * hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
+ */
+ viewParse->rtable = new_rt;
+}
+
+/*-------------------------------------------------------------------
+ * DefineView
+ *
+ * - takes a "viewname", "parsetree" pair and then
+ * 1) construct the "virtual" relation
+ * 2) commit the command but NOT the transaction,
+ * so that the relation exists
+ * before the rules are defined.
+ * 2) define the "n" rules specified in the PRS2 paper
+ * over the "virtual" relation
+ *-------------------------------------------------------------------
+ */
+void
+DefineView(char *viewName, Query *viewParse)
+{
+ List *viewTlist;
+
+ viewTlist = viewParse->targetList;
+
+ /*
+ * Create the "view" relation
+ * NOTE: if it already exists, the xaxt will be aborted.
+ */
+ DefineVirtualRelation(viewName, viewTlist);
+
+ /*
+ * The relation we have just created is not visible
+ * to any other commands running with the same transaction &
+ * command id.
+ * So, increment the command id counter (but do NOT pfree any
+ * memory!!!!)
+ */
+ CommandCounterIncrement();
+
+ /*
+ * The range table of 'viewParse' does not contain entries
+ * for the "CURRENT" and "NEW" relations.
+ * So... add them!
+ * NOTE: we make the update in place! After this call 'viewParse'
+ * will never be what it used to be...
+ */
+ UpdateRangeTableOfViewParse(viewName, viewParse);
+ DefineViewRules(viewName, viewParse);
+}
+
+/*------------------------------------------------------------------
+ * RemoveView
+ *
+ * Remove a view given its name
+ *------------------------------------------------------------------
+ */
+void
+RemoveView(char *viewName)
+{
+ char* rname;
+
+ /*
+ * first remove all the "view" rules...
+ * Currently we only have one!
+ */
+ rname = MakeRetrieveViewRuleName(viewName);
+ RemoveRewriteRule(rname);
+
+ /*
+ * we don't really need that, but just in case...
+ */
+ CommandCounterIncrement();
+
+ /*
+ * now remove the relation.
+ */
+ heap_destroy(viewName);
+ pfree(rname);
+}