rewritedefine.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 588 行 · 第 1/2 页

C
588
字号
/*------------------------------------------------------------------------- * * rewriteDefine.c *	  routines for defining a rewrite rule * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.90 2003/09/29 00:05:25 petere Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/catname.h"#include "catalog/dependency.h"#include "catalog/indexing.h"#include "catalog/pg_rewrite.h"#include "commands/view.h"#include "miscadmin.h"#include "optimizer/clauses.h"#include "parser/parse_relation.h"#include "rewrite/rewriteDefine.h"#include "rewrite/rewriteManip.h"#include "rewrite/rewriteSupport.h"#include "storage/smgr.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/syscache.h"static void setRuleCheckAsUser(Query *qry, AclId userid);static bool setRuleCheckAsUser_walker(Node *node, Oid *context);/* * InsertRule - *	  takes the arguments and inserts them as a row into the system *	  relation "pg_rewrite" */static OidInsertRule(char *rulname,		   int evtype,		   Oid eventrel_oid,		   AttrNumber evslot_index,		   bool evinstead,		   Node *event_qual,		   List *action,		   bool replace){	char	   *evqual = nodeToString(event_qual);	char	   *actiontree = nodeToString((Node *) action);	int			i;	Datum		values[Natts_pg_rewrite];	char		nulls[Natts_pg_rewrite];	char		replaces[Natts_pg_rewrite];	NameData	rname;	Relation	pg_rewrite_desc;	HeapTuple	tup,				oldtup;	Oid			rewriteObjectId;	ObjectAddress myself,				referenced;	bool		is_update = false;	/*	 * Set up *nulls and *values arrays	 */	MemSet(nulls, ' ', sizeof(nulls));	i = 0;	namestrcpy(&rname, rulname);	values[i++] = NameGetDatum(&rname); /* rulename */	values[i++] = ObjectIdGetDatum(eventrel_oid);		/* ev_class */	values[i++] = Int16GetDatum(evslot_index);	/* ev_attr */	values[i++] = CharGetDatum(evtype + '0');	/* ev_type */	values[i++] = BoolGetDatum(evinstead);		/* is_instead */	values[i++] = DirectFunctionCall1(textin, CStringGetDatum(evqual)); /* ev_qual */	values[i++] = DirectFunctionCall1(textin, CStringGetDatum(actiontree));		/* ev_action */	/*	 * Ready to store new pg_rewrite tuple	 */	pg_rewrite_desc = heap_openr(RewriteRelationName, RowExclusiveLock);	/*	 * Check to see if we are replacing an existing tuple	 */	oldtup = SearchSysCache(RULERELNAME,							ObjectIdGetDatum(eventrel_oid),							PointerGetDatum(rulname),							0, 0);	if (HeapTupleIsValid(oldtup))	{		if (!replace)			ereport(ERROR,					(errcode(ERRCODE_DUPLICATE_OBJECT),				 errmsg("rule \"%s\" for relation \"%s\" already exists",						rulname, get_rel_name(eventrel_oid))));		/*		 * When replacing, we don't need to replace every attribute		 */		MemSet(replaces, ' ', sizeof(replaces));		replaces[Anum_pg_rewrite_ev_attr - 1] = 'r';		replaces[Anum_pg_rewrite_ev_type - 1] = 'r';		replaces[Anum_pg_rewrite_is_instead - 1] = 'r';		replaces[Anum_pg_rewrite_ev_qual - 1] = 'r';		replaces[Anum_pg_rewrite_ev_action - 1] = 'r';		tup = heap_modifytuple(oldtup, pg_rewrite_desc,							   values, nulls, replaces);		simple_heap_update(pg_rewrite_desc, &tup->t_self, tup);		ReleaseSysCache(oldtup);		rewriteObjectId = HeapTupleGetOid(tup);		is_update = true;	}	else	{		tup = heap_formtuple(pg_rewrite_desc->rd_att, values, nulls);		rewriteObjectId = simple_heap_insert(pg_rewrite_desc, tup);	}	/* Need to update indexes in either case */	CatalogUpdateIndexes(pg_rewrite_desc, tup);	heap_freetuple(tup);	/* If replacing, get rid of old dependencies and make new ones */	if (is_update)		deleteDependencyRecordsFor(RelationGetRelid(pg_rewrite_desc),								   rewriteObjectId);	/*	 * Install dependency on rule's relation to ensure it will go away on	 * relation deletion.  If the rule is ON SELECT, make the dependency	 * implicit --- this prevents deleting a view's SELECT rule.  Other	 * kinds of rules can be AUTO.	 */	myself.classId = RelationGetRelid(pg_rewrite_desc);	myself.objectId = rewriteObjectId;	myself.objectSubId = 0;	referenced.classId = RelOid_pg_class;	referenced.objectId = eventrel_oid;	referenced.objectSubId = 0;	recordDependencyOn(&myself, &referenced,		 (evtype == CMD_SELECT) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);	/*	 * Also install dependencies on objects referenced in action and qual.	 */	recordDependencyOnExpr(&myself, (Node *) action, NIL,						   DEPENDENCY_NORMAL);	if (event_qual != NULL)	{		/* Find query containing OLD/NEW rtable entries */		Query	   *qry = (Query *) lfirst(action);		qry = getInsertSelectQuery(qry, NULL);		recordDependencyOnExpr(&myself, event_qual, qry->rtable,							   DEPENDENCY_NORMAL);	}	heap_close(pg_rewrite_desc, RowExclusiveLock);	return rewriteObjectId;}voidDefineQueryRewrite(RuleStmt *stmt){	RangeVar   *event_obj = stmt->relation;	Node	   *event_qual = stmt->whereClause;	CmdType		event_type = stmt->event;	bool		is_instead = stmt->instead;	bool		replace = stmt->replace;	List	   *action = stmt->actions;	Relation	event_relation;	Oid			ev_relid;	Oid			ruleId;	int			event_attno;	Oid			event_attype;	List	   *l;	Query	   *query;	AclResult	aclresult;	bool		RelisBecomingView = false;	/*	 * If we are installing an ON SELECT rule, we had better grab	 * AccessExclusiveLock to ensure no SELECTs are currently running on	 * the event relation.	For other types of rules, it might be	 * sufficient to grab ShareLock to lock out insert/update/delete	 * actions.  But for now, let's just grab AccessExclusiveLock all the	 * time.	 */	event_relation = heap_openrv(event_obj, AccessExclusiveLock);	ev_relid = RelationGetRelid(event_relation);	/*	 * Check user has permission to apply rules to this relation.	 */	aclresult = pg_class_aclcheck(ev_relid, GetUserId(), ACL_RULE);	if (aclresult != ACLCHECK_OK)		aclcheck_error(aclresult, ACL_KIND_CLASS,					   RelationGetRelationName(event_relation));	/*	 * No rule actions that modify OLD or NEW	 */	foreach(l, action)	{		query = (Query *) lfirst(l);		if (query->resultRelation == 0)			continue;		/* Don't be fooled by INSERT/SELECT */		if (query != getInsertSelectQuery(query, NULL))			continue;		if (query->resultRelation == PRS2_OLD_VARNO)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("rule actions on OLD are not implemented"),					 errhint("Use views or triggers instead.")));		if (query->resultRelation == PRS2_NEW_VARNO)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("rule actions on NEW are not implemented"),					 errhint("Use triggers instead.")));	}	/*	 * Rules ON SELECT are restricted to view definitions	 */	if (event_type == CMD_SELECT)	{		List	   *tllist;		int			i;		/*		 * So there cannot be INSTEAD NOTHING, ...		 */		if (length(action) == 0)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),			errmsg("INSTEAD NOTHING rules on SELECT are not implemented"),					 errhint("Use views instead.")));		/*		 * ... there cannot be multiple actions, ...		 */		if (length(action) > 1)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("multiple actions for rules on SELECT are not implemented")));		/*		 * ... the one action must be a SELECT, ...		 */		query = (Query *) lfirst(action);		if (!is_instead || query->commandType != CMD_SELECT)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("rules on SELECT must have action INSTEAD SELECT")));		/*		 * ... there can be no rule qual, ...		 */		if (event_qual != NULL)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("event qualifications are not implemented for rules on SELECT")));		/*		 * ... the targetlist of the SELECT action must exactly match the		 * event relation, ...		 */		i = 0;		foreach(tllist, query->targetList)		{			TargetEntry *tle = (TargetEntry *) lfirst(tllist);			Resdom	   *resdom = tle->resdom;			Form_pg_attribute attr;			char	   *attname;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?