view.c 8.1 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * view.c--
4
 *	  use rewrite rules to construct views
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
B
Bruce Momjian 已提交
10
 *	  $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.12 1997/09/18 20:20:27 momjian Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
14
#include <stdio.h>				/* for sprintf() */
15
#include <string.h>
M
Marc G. Fournier 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

#include <postgres.h>

#include <catalog/heap.h>
#include <access/heapam.h>
#include <access/xact.h>
#include <utils/builtins.h>
#include <nodes/relation.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>
31
#include <commands/view.h>
32 33 34 35 36 37 38 39 40 41 42 43 44

/*---------------------------------------------------------------------
 * 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
45
DefineVirtualRelation(char *relname, List *tlist)
46
{
47 48 49 50 51 52 53
	CreateStmt	createStmt;
	List	   *attrList,
			   *t;
	TargetEntry *entry;
	Resdom	   *res;
	char	   *resname;
	char	   *restypename;
54 55 56 57 58 59 60 61 62 63 64 65

	/*
	 * 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)
		{
66 67
			ColumnDef  *def = makeNode(ColumnDef);
			TypeName   *typename;
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

			/*
			 * find the names of the attribute & its type
			 */
			entry = lfirst(t);
			res = entry->resdom;
			resname = res->resname;
			restypename = tname(get_id_type(res->restype));

			typename = makeNode(TypeName);

			typename->name = pstrdup(restypename);
			def->colname = pstrdup(resname);

			def->typename = typename;

			def->is_not_null = false;
			def->defval = (char *) NULL;

			attrList = lappend(attrList, def);
		}
89
	}
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
	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;
	createStmt.constraints = NIL;

	/*
	 * finally create the relation...
	 */
	DefineRelation(&createStmt);
}
113 114 115 116 117 118 119 120 121 122 123 124 125

/*------------------------------------------------------------------
 * 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
 *------------------------------------------------------------------
 */
126
char	   *
127 128 129
MakeRetrieveViewRuleName(char *viewName)
{
/*
130
	char buf[100];
131

B
Bruce Momjian 已提交
132
	MemSet(buf, 0, sizeof(buf));
133 134 135
	sprintf(buf, "_RET%.*s", NAMEDATALEN, viewName->data);
	buf[15] = '\0';
	namestrcpy(rule_name, buf);
136 137
*/

138
	char	   *buf;
139 140 141 142

	buf = palloc(strlen(viewName) + 5);
	sprintf(buf, "_RET%s", viewName);
	return buf;
143 144 145
}

static RuleStmt *
146
FormViewRetrieveRule(char *viewName, Query *viewParse)
147
{
148 149 150
	RuleStmt   *rule;
	char	   *rname;
	Attr	   *attr;
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169

	/*
	 * 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;
170 171 172
}

static void
173
DefineViewRules(char *viewName, Query *viewParse)
174
{
175
	RuleStmt   *retrieve_rule = NULL;
176

177
#ifdef NOTYET
178 179 180
	RuleStmt   *replace_rule = NULL;
	RuleStmt   *append_rule = NULL;
	RuleStmt   *delete_rule = NULL;
181

182
#endif
183 184 185 186

	retrieve_rule =
		FormViewRetrieveRule(viewName, viewParse);

187
#ifdef NOTYET
188 189 190 191 192 193 194 195

	replace_rule =
		FormViewReplaceRule(viewName, viewParse);
	append_rule =
		FormViewAppendRule(viewName, viewParse);
	delete_rule =
		FormViewDeleteRule(viewName, viewParse);

196
#endif
197 198

	DefineQueryRewrite(retrieve_rule);
199 200

#ifdef NOTYET
201 202 203
	DefineQueryRewrite(replace_rule);
	DefineQueryRewrite(append_rule);
	DefineQueryRewrite(delete_rule);
204
#endif
205 206

}
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226

/*---------------------------------------------------------------
 * 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
227
UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
228
{
229 230 231 232
	List	   *old_rt;
	List	   *new_rt;
	RangeTblEntry *rt_entry1,
			   *rt_entry2;
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262

	/*
	 * 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 =
		addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
						   FALSE, FALSE, NULL);
	rt_entry2 =
		addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
						   FALSE, FALSE, NULL);
	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;
263 264 265 266 267
}

/*-------------------------------------------------------------------
 * DefineView
 *
268 269 270 271 272 273 274
 *		- 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
275 276 277
 *-------------------------------------------------------------------
 */
void
278
DefineView(char *viewName, Query *viewParse)
279
{
280
	List	   *viewTlist;
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304

	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);
305 306 307 308 309 310 311 312 313 314 315
}

/*------------------------------------------------------------------
 * RemoveView
 *
 * Remove a view given its name
 *------------------------------------------------------------------
 */
void
RemoveView(char *viewName)
{
316
	char	   *rname;
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333

	/*
	 * 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);
334
}