⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ruleutils.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
/********************************************************************** * get_ruledef.c	- Function to get a rules definition text *			  out of it's tuple * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.18.2.3 1999/09/05 22:55:28 tgl Exp $ * *	  This software is copyrighted by Jan Wieck - Hamburg. * *	  The author hereby grants permission  to  use,  copy,	modify, *	  distribute,  and	license this software and its documentation *	  for any purpose, provided that existing copyright notices are *	  retained	in	all  copies  and  that	this notice is included *	  verbatim in any distributions. No written agreement, license, *	  or  royalty  fee	is required for any of the authorized uses. *	  Modifications to this software may be  copyrighted  by  their *	  author  and  need  not  follow  the licensing terms described *	  here, provided that the new terms are  clearly  indicated  on *	  the first page of each file where they apply. * *	  IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY *	  PARTY  FOR  DIRECT,	INDIRECT,	SPECIAL,   INCIDENTAL,	 OR *	  CONSEQUENTIAL   DAMAGES  ARISING	OUT  OF  THE  USE  OF  THIS *	  SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN *	  IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH *	  DAMAGE. * *	  THE  AUTHOR  AND	DISTRIBUTORS  SPECIFICALLY	 DISCLAIM	ANY *	  WARRANTIES,  INCLUDING,  BUT	NOT  LIMITED  TO,  THE	IMPLIED *	  WARRANTIES  OF  MERCHANTABILITY,	FITNESS  FOR  A  PARTICULAR *	  PURPOSE,	AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON *	  AN "AS IS" BASIS, AND THE AUTHOR	AND  DISTRIBUTORS  HAVE  NO *	  OBLIGATION   TO	PROVIDE   MAINTENANCE,	 SUPPORT,  UPDATES, *	  ENHANCEMENTS, OR MODIFICATIONS. * **********************************************************************/#include <unistd.h>#include <fcntl.h>#include "postgres.h"#include "executor/spi.h"#include "optimizer/clauses.h"#include "utils/lsyscache.h"#include "catalog/pg_index.h"#include "catalog/pg_operator.h"#include "catalog/pg_shadow.h"#define BUFSIZE 8192/* ---------- * Local data types * ---------- */typedef struct QryHier{	struct QryHier *parent;	Query	   *query;} QryHier;typedef struct {	Index		rt_index;	int			levelsup;} check_if_rte_used_context;/* ---------- * Global data * ---------- */static char *rulename;static void *plan_getrule = NULL;static char *query_getrule = "SELECT * FROM pg_rewrite WHERE rulename = $1";static void *plan_getview = NULL;static char *query_getview = "SELECT * FROM pg_rewrite WHERE rulename = $1 or rulename = $2";static void *plan_getam = NULL;static char *query_getam = "SELECT * FROM pg_am WHERE oid = $1";static void *plan_getopclass = NULL;static char *query_getopclass = "SELECT * FROM pg_opclass WHERE oid = $1";/* ---------- * Global functions * ---------- */text	   *pg_get_ruledef(NameData *rname);text	   *pg_get_viewdef(NameData *rname);text	   *pg_get_indexdef(Oid indexrelid);NameData   *pg_get_userbyid(int4 uid);/* ---------- * Local functions * ---------- */static char *make_ruledef(HeapTuple ruletup, TupleDesc rulettc);static char *make_viewdef(HeapTuple ruletup, TupleDesc rulettc);static char *get_query_def(Query *query, QryHier *parentqh);static char *get_select_query_def(Query *query, QryHier *qh);static char *get_insert_query_def(Query *query, QryHier *qh);static char *get_update_query_def(Query *query, QryHier *qh);static char *get_delete_query_def(Query *query, QryHier *qh);static RangeTblEntry *get_rte_for_var(Var *var, QryHier *qh);static char *get_rule_expr(QryHier *qh, int rt_index, Node *node, bool varprefix);static char *get_func_expr(QryHier *qh, int rt_index, Expr *expr, bool varprefix);static char *get_tle_expr(QryHier *qh, int rt_index, TargetEntry *tle, bool varprefix);static char *get_const_expr(Const *constval);static char *get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix);static char *get_relation_name(Oid relid);static char *get_attribute_name(Oid relid, int2 attnum);static bool check_if_rte_used(Node *node, Index rt_index, int levelsup);static bool check_if_rte_used_walker(Node *node,									 check_if_rte_used_context *context);/* ---------- * get_ruledef			- Do it all and return a text *				  that could be used as a statement *				  to recreate the rule * ---------- */text *pg_get_ruledef(NameData *rname){	text	   *ruledef;	Datum		args[1];	char		nulls[2];	int			spirc;	HeapTuple	ruletup;	TupleDesc	rulettc;	char	   *tmp;	int			len;	/* ----------	 * We need the rules name somewhere deep down	 * ----------	 */	rulename = nameout(rname);	/* ----------	 * Connect to SPI manager	 * ----------	 */	if (SPI_connect() != SPI_OK_CONNECT)		elog(ERROR, "get_ruledef: cannot connect to SPI manager");	/* ----------	 * On the first call prepare the plan to lookup pg_proc.	 * We read pg_proc over the SPI manager instead of using	 * the syscache to be checked for read access on pg_proc.	 * ----------	 */	if (plan_getrule == NULL)	{		Oid			argtypes[1];		void	   *plan;		argtypes[0] = NAMEOID;		plan = SPI_prepare(query_getrule, 1, argtypes);		if (plan == NULL)			elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getrule);		plan_getrule = SPI_saveplan(plan);	}	/* ----------	 * Get the pg_rewrite tuple for this rule	 * ----------	 */	args[0] = PointerGetDatum(rulename);	nulls[0] = (rulename == NULL) ? 'n' : ' ';	nulls[1] = '\0';	spirc = SPI_execp(plan_getrule, args, nulls, 1);	if (spirc != SPI_OK_SELECT)		elog(ERROR, "failed to get pg_rewrite tuple for %s", rulename);	if (SPI_processed != 1)	{		if (SPI_finish() != SPI_OK_FINISH)			elog(ERROR, "get_ruledef: SPI_finish() failed");		ruledef = SPI_palloc(VARHDRSZ + 1);		VARSIZE(ruledef) = VARHDRSZ + 1;		VARDATA(ruledef)[0] = '-';		return ruledef;	}	ruletup = SPI_tuptable->vals[0];	rulettc = SPI_tuptable->tupdesc;	/* ----------	 * Get the rules definition and put it into executors memory	 * ----------	 */	tmp = make_ruledef(ruletup, rulettc);	len = strlen(tmp) + VARHDRSZ;	ruledef = SPI_palloc(len);	VARSIZE(ruledef) = len;	memcpy(VARDATA(ruledef), tmp, len - VARHDRSZ);	/* ----------	 * Disconnect from SPI manager	 * ----------	 */	if (SPI_finish() != SPI_OK_FINISH)		elog(ERROR, "get_ruledef: SPI_finish() failed");	/* ----------	 * Easy - isn't it?	 * ----------	 */	return ruledef;}/* ---------- * get_viewdef			- Mainly the same thing, but we *				  only return the SELECT part of a view * ---------- */text *pg_get_viewdef(NameData *rname){	text	   *ruledef;	Datum		args[2];	char		nulls[3];	int			spirc;	HeapTuple	ruletup;	TupleDesc	rulettc;	char	   *tmp;	int			len;	char		name1[NAMEDATALEN + 5];	char		name2[NAMEDATALEN + 5];	/* ----------	 * We need the rules name somewhere deep down	 * ----------	 */	rulename = nameout(rname);	/* ----------	 * Connect to SPI manager	 * ----------	 */	if (SPI_connect() != SPI_OK_CONNECT)		elog(ERROR, "get_viewdef: cannot connect to SPI manager");	/* ----------	 * On the first call prepare the plan to lookup pg_proc.	 * We read pg_proc over the SPI manager instead of using	 * the syscache to be checked for read access on pg_proc.	 * ----------	 */	if (plan_getview == NULL)	{		Oid			argtypes[2];		void	   *plan;		argtypes[0] = NAMEOID;		argtypes[1] = NAMEOID;		plan = SPI_prepare(query_getview, 2, argtypes);		if (plan == NULL)			elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getview);		plan_getview = SPI_saveplan(plan);	}	/* ----------	 * Get the pg_rewrite tuple for this rule	 * ----------	 */	sprintf(name1, "_RET%s", rulename);	sprintf(name2, "_ret%s", rulename);	args[0] = PointerGetDatum(name1);	args[1] = PointerGetDatum(name2);	nulls[0] = ' ';	nulls[1] = ' ';	nulls[2] = '\0';	spirc = SPI_execp(plan_getview, args, nulls, 1);	if (spirc != SPI_OK_SELECT)		elog(ERROR, "failed to get pg_rewrite tuple for view %s", rulename);	if (SPI_processed != 1)		tmp = "Not a view";	else	{		/* ----------		 * Get the rules definition and put it into executors memory		 * ----------		 */		ruletup = SPI_tuptable->vals[0];		rulettc = SPI_tuptable->tupdesc;		tmp = make_viewdef(ruletup, rulettc);	}	len = strlen(tmp) + VARHDRSZ;	ruledef = SPI_palloc(len);	VARSIZE(ruledef) = len;	memcpy(VARDATA(ruledef), tmp, len - VARHDRSZ);	/* ----------	 * Disconnect from SPI manager	 * ----------	 */	if (SPI_finish() != SPI_OK_FINISH)		elog(ERROR, "get_viewdef: SPI_finish() failed");	/* ----------	 * Easy - isn't it?	 * ----------	 */	return ruledef;}/* ---------- * get_viewdef			- Mainly the same thing, but we *				  only return the SELECT part of a view * ---------- */text *pg_get_indexdef(Oid indexrelid){	text	   *indexdef;	HeapTuple	ht_idx;	HeapTuple	ht_idxrel;	HeapTuple	ht_indrel;	HeapTuple	spi_tup;	TupleDesc	spi_ttc;	int			spi_fno;	Form_pg_index idxrec;	Form_pg_class idxrelrec;	Form_pg_class indrelrec;	Datum		spi_args[1];	char		spi_nulls[2];	int			spirc;	int			len;	int			keyno;	char		buf[BUFSIZE];	char		keybuf[BUFSIZE];	char	   *sep;	/* ----------	 * Connect to SPI manager	 * ----------	 */	if (SPI_connect() != SPI_OK_CONNECT)		elog(ERROR, "get_indexdef: cannot connect to SPI manager");	/* ----------	 * On the first call prepare the plans to lookup pg_am	 * and pg_opclass.	 * ----------	 */	if (plan_getam == NULL)	{		Oid			argtypes[1];		void	   *plan;		argtypes[0] = OIDOID;		plan = SPI_prepare(query_getam, 1, argtypes);		if (plan == NULL)			elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getam);		plan_getam = SPI_saveplan(plan);		argtypes[0] = OIDOID;		plan = SPI_prepare(query_getopclass, 1, argtypes);		if (plan == NULL)			elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getopclass);		plan_getopclass = SPI_saveplan(plan);	}	/* ----------	 * Fetch the pg_index tuple by the Oid of the index	 * ----------	 */	ht_idx = SearchSysCacheTuple(INDEXRELID,								 ObjectIdGetDatum(indexrelid), 0, 0, 0);	if (!HeapTupleIsValid(ht_idx))		elog(ERROR, "syscache lookup for index %u failed", indexrelid);	idxrec = (Form_pg_index) GETSTRUCT(ht_idx);	/* ----------	 * Fetch the pg_class tuple of the index relation	 * ----------	 */	ht_idxrel = SearchSysCacheTuple(RELOID,						  ObjectIdGetDatum(idxrec->indexrelid), 0, 0, 0);	if (!HeapTupleIsValid(ht_idxrel))		elog(ERROR, "syscache lookup for relid %u failed", idxrec->indexrelid);	idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);	/* ----------	 * Fetch the pg_class tuple of the indexed relation	 * ----------	 */	ht_indrel = SearchSysCacheTuple(RELOID,							ObjectIdGetDatum(idxrec->indrelid), 0, 0, 0);	if (!HeapTupleIsValid(ht_indrel))		elog(ERROR, "syscache lookup for relid %u failed", idxrec->indrelid);	indrelrec = (Form_pg_class) GETSTRUCT(ht_indrel);	/* ----------	 * Get the am name for the index relation	 * ----------	 */	spi_args[0] = ObjectIdGetDatum(idxrelrec->relam);	spi_nulls[0] = ' ';	spi_nulls[1] = '\0';	spirc = SPI_execp(plan_getam, spi_args, spi_nulls, 1);	if (spirc != SPI_OK_SELECT)		elog(ERROR, "failed to get pg_am tuple for index %s", nameout(&(idxrelrec->relname)));	if (SPI_processed != 1)		elog(ERROR, "failed to get pg_am tuple for index %s", nameout(&(idxrelrec->relname)));	spi_tup = SPI_tuptable->vals[0];	spi_ttc = SPI_tuptable->tupdesc;	spi_fno = SPI_fnumber(spi_ttc, "amname");	/* ----------	 * Start the index definition	 * ----------	 */	sprintf(buf, "CREATE %sINDEX \"%s\" ON \"%s\" USING %s (",			idxrec->indisunique ? "UNIQUE " : "",			nameout(&(idxrelrec->relname)),			nameout(&(indrelrec->relname)),			SPI_getvalue(spi_tup, spi_ttc, spi_fno));	/* ----------	 * Collect the indexed attributes	 * ----------	 */	sep = "";	keybuf[0] = '\0';	for (keyno = 0; keyno < INDEX_MAX_KEYS; keyno++)	{		if (idxrec->indkey[keyno] == InvalidAttrNumber)			break;		strcat(keybuf, sep);		sep = ", ";		/* ----------		 * Add the indexed field name		 * ----------		 */		strcat(keybuf, "\"");		if (idxrec->indkey[keyno] == ObjectIdAttributeNumber - 1)			strcat(keybuf, "oid");		else			strcat(keybuf, get_attribute_name(idxrec->indrelid,											  idxrec->indkey[keyno]));		strcat(keybuf, "\"");		/* ----------		 * If not a functional index, add the operator class name		 * ----------		 */		if (idxrec->indproc == InvalidOid)		{			spi_args[0] = ObjectIdGetDatum(idxrec->indclass[keyno]);			spi_nulls[0] = ' ';			spi_nulls[1] = '\0';			spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);			if (spirc != SPI_OK_SELECT)				elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[keyno]);			if (SPI_processed != 1)				elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[keyno]);			spi_tup = SPI_tuptable->vals[0];			spi_ttc = SPI_tuptable->tupdesc;			spi_fno = SPI_fnumber(spi_ttc, "opcname");			strcat(keybuf, " \"");			strcat(keybuf, SPI_getvalue(spi_tup, spi_ttc, spi_fno));			strcat(keybuf, "\"");		}	}	/* ----------	 * For functional index say 'func (attrs) opclass'	 * ----------	 */	if (idxrec->indproc != InvalidOid)	{		HeapTuple	proctup;		Form_pg_proc procStruct;		proctup = SearchSysCacheTuple(PROOID,							 ObjectIdGetDatum(idxrec->indproc), 0, 0, 0);		if (!HeapTupleIsValid(proctup))			elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc);		procStruct = (Form_pg_proc) GETSTRUCT(proctup);		strcat(buf, "\"");		strcat(buf, nameout(&(procStruct->proname)));		strcat(buf, "\" (");		strcat(buf, keybuf);		strcat(buf, ") ");		spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]);		spi_nulls[0] = ' ';		spi_nulls[1] = '\0';		spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);		if (spirc != SPI_OK_SELECT)			elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[0]);		if (SPI_processed != 1)			elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[0]);		spi_tup = SPI_tuptable->vals[0];		spi_ttc = SPI_tuptable->tupdesc;		spi_fno = SPI_fnumber(spi_ttc, "opcname");		strcat(buf, "\"");		strcat(buf, SPI_getvalue(spi_tup, spi_ttc, spi_fno));		strcat(buf, "\"");	}	else		/* ----------		 * For the others say 'attr opclass [, ...]'		 * ----------		 */		strcat(buf, keybuf);	/* ----------	 * Finish	 * ----------	 */	strcat(buf, ")");	/* ----------	 * Create the result in upper executor memory	 * ----------	 */	len = strlen(buf) + VARHDRSZ;	indexdef = SPI_palloc(len);	VARSIZE(indexdef) = len;	memcpy(VARDATA(indexdef), buf, len - VARHDRSZ);	/* ----------	 * Disconnect from SPI manager	 * ----------	 */	if (SPI_finish() != SPI_OK_FINISH)		elog(ERROR, "get_viewdef: SPI_finish() failed");	return indexdef;}/* ---------- * get_userbyid			- Get a user name by usesysid and *				  fallback to 'unknown (UID=n)' * ---------- */NameData   *pg_get_userbyid(int4 uid){	HeapTuple	usertup;	Form_pg_shadow user_rec;	NameData   *result;	/* ----------	 * Allocate space for the result	 * ----------	 */	result = (NameData *) palloc(NAMEDATALEN);	memset(result->data, 0, NAMEDATALEN);	/* ----------	 * Get the pg_shadow entry and print the result	 * ----------	 */	usertup = SearchSysCacheTuple(USESYSID,								  ObjectIdGetDatum(uid), 0, 0, 0);	if (HeapTupleIsValid(usertup))	{		user_rec = (Form_pg_shadow) GETSTRUCT(usertup);		StrNCpy(result->data, (&(user_rec->usename))->data, NAMEDATALEN);	}	else		sprintf((char *) result, "unknown (UID=%d)", uid);	return result;}/* ---------- * make_ruledef			- reconstruct the CREATE RULE command *				  for a given pg_rewrite tuple * ---------- */static char *make_ruledef(HeapTuple ruletup, TupleDesc rulettc){	char	   *buf;	char		ev_type;	Oid			ev_class;	int2		ev_attr;	bool		is_instead;	char	   *ev_qual;	char	   *ev_action;	List	   *actions = NIL;	int			fno;	bool		isnull;	/* ----------	 * Allocate space for the returned rule definition text	 * ----------	 */	buf = palloc(BUFSIZE);	/* ----------	 * Get the attribute values from the rules tuple	 * ----------	 */	fno = SPI_fnumber(rulettc, "ev_type");	ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);	fno = SPI_fnumber(rulettc, "ev_class");	ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull);	fno = SPI_fnumber(rulettc, "ev_attr");	ev_attr = (int2) SPI_getbinval(ruletup, rulettc, fno, &isnull);

⌨️ 快捷键说明

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