ruleutils.c

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

C
2,475
字号
/********************************************************************** * ruleutils.c	- Functions to convert stored expressions/querytrees *				back to source text * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.157.2.2 2004/07/06 04:50:54 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 "postgres.h"#include <unistd.h>#include <fcntl.h>#include "access/genam.h"#include "catalog/catname.h"#include "catalog/heap.h"#include "catalog/index.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_cast.h"#include "catalog/pg_constraint.h"#include "catalog/pg_index.h"#include "catalog/pg_opclass.h"#include "catalog/pg_operator.h"#include "catalog/pg_shadow.h"#include "catalog/pg_trigger.h"#include "executor/spi.h"#include "lib/stringinfo.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/tlist.h"#include "parser/keywords.h"#include "parser/parse_expr.h"#include "parser/parse_func.h"#include "parser/parse_oper.h"#include "parser/parse_type.h"#include "parser/parsetree.h"#include "rewrite/rewriteManip.h"#include "rewrite/rewriteSupport.h"#include "utils/array.h"#include "utils/fmgroids.h"#include "utils/lsyscache.h"#include "utils/typcache.h"/* ---------- * Pretty formatting constants * ---------- *//* Indent counts */#define PRETTYINDENT_STD		8#define PRETTYINDENT_JOIN	   13#define PRETTYINDENT_JOIN_ON	(PRETTYINDENT_JOIN-PRETTYINDENT_STD)#define PRETTYINDENT_VAR		4/* Pretty flags */#define PRETTYFLAG_PAREN		1#define PRETTYFLAG_INDENT		2/* macro to test if pretty action needed */#define PRETTY_PAREN(context)	((context)->prettyFlags & PRETTYFLAG_PAREN)#define PRETTY_INDENT(context)	((context)->prettyFlags & PRETTYFLAG_INDENT)/* ---------- * Local data types * ---------- *//* Context info needed for invoking a recursive querytree display routine */typedef struct{	StringInfo	buf;			/* output buffer to append to */	List	   *namespaces;		/* List of deparse_namespace nodes */	int			prettyFlags;	/* enabling of pretty-print functions */	int			indentLevel;	/* current indent level for prettyprint */	bool		varprefix;		/* TRUE to print prefixes on Vars */} deparse_context;/* * Each level of query context around a subtree needs a level of Var namespace. * A Var having varlevelsup=N refers to the N'th item (counting from 0) in * the current context's namespaces list. * * The rangetable is the list of actual RTEs from the query tree. * * For deparsing plan trees, we allow two special RTE entries that are not * part of the rtable list (mainly because they don't have consecutively * allocated varnos). */typedef struct{	List	   *rtable;			/* List of RangeTblEntry nodes */	int			outer_varno;	/* varno for outer_rte */	RangeTblEntry *outer_rte;	/* special RangeTblEntry, or NULL */	int			inner_varno;	/* varno for inner_rte */	RangeTblEntry *inner_rte;	/* special RangeTblEntry, or NULL */} deparse_namespace;/* ---------- * Global data * ---------- */static void *plan_getrulebyoid = NULL;static char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";static void *plan_getviewrule = NULL;static char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";/* ---------- * Local functions * * Most of these functions used to use fixed-size buffers to build their * results.  Now, they take an (already initialized) StringInfo object * as a parameter, and append their text output to its contents. * ---------- */static char *deparse_expression_pretty(Node *expr, List *dpcontext,						  bool forceprefix, bool showimplicit,						  int prettyFlags, int startIndent);static text *pg_do_getviewdef(Oid viewoid, int prettyFlags);static void decompile_column_index_array(Datum column_index_array, Oid relId,							 StringInfo buf);static Datum pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);static Datum pg_get_indexdef_worker(Oid indexrelid, int colno,					   int prettyFlags);static Datum pg_get_constraintdef_worker(Oid constraintId, int prettyFlags);static Datum pg_get_expr_worker(text *expr, Oid relid, char *relname,				   int prettyFlags);static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,			 int prettyFlags);static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,			 int prettyFlags);static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,			  TupleDesc resultDesc, int prettyFlags, int startIndent);static void get_select_query_def(Query *query, deparse_context *context,					 TupleDesc resultDesc);static void get_insert_query_def(Query *query, deparse_context *context);static void get_update_query_def(Query *query, deparse_context *context);static void get_delete_query_def(Query *query, deparse_context *context);static void get_utility_query_def(Query *query, deparse_context *context);static void get_basic_select_query(Query *query, deparse_context *context,					   TupleDesc resultDesc);static void get_setop_query(Node *setOp, Query *query,				deparse_context *context,				TupleDesc resultDesc);static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist,						 bool force_colno,						 deparse_context *context);static void get_names_for_var(Var *var, deparse_context *context,				  char **schemaname, char **refname, char **attname);static RangeTblEntry *find_rte_by_refname(const char *refname,					deparse_context *context);static const char *get_simple_binary_op_name(OpExpr *expr);static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);static void appendStringInfoSpaces(StringInfo buf, int count);static void appendContextKeyword(deparse_context *context, const char *str,					 int indentBefore, int indentAfter, int indentPlus);static void get_rule_expr(Node *node, deparse_context *context,			  bool showimplicit);static void get_oper_expr(OpExpr *expr, deparse_context *context);static void get_func_expr(FuncExpr *expr, deparse_context *context,			  bool showimplicit);static void get_agg_expr(Aggref *aggref, deparse_context *context);static Node *strip_type_coercion(Node *expr, Oid resultType);static void get_const_expr(Const *constval, deparse_context *context);static void get_sublink_expr(SubLink *sublink, deparse_context *context);static void get_from_clause(Query *query, deparse_context *context);static void get_from_clause_item(Node *jtnode, Query *query,					 deparse_context *context);static void get_from_clause_coldeflist(List *coldeflist,						   deparse_context *context);static void get_opclass_name(Oid opclass, Oid actual_datatype,				 StringInfo buf);static bool tleIsArrayAssign(TargetEntry *tle);static char *generate_relation_name(Oid relid);static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes);static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);static void print_operator_name(StringInfo buf, List *opname);#define only_marker(rte)  ((rte)->inh ? "" : "ONLY ")/* ---------- * get_ruledef			- Do it all and return a text *				  that could be used as a statement *				  to recreate the rule * ---------- */Datumpg_get_ruledef(PG_FUNCTION_ARGS){	Oid			ruleoid = PG_GETARG_OID(0);	return pg_get_ruledef_worker(ruleoid, 0);}Datumpg_get_ruledef_ext(PG_FUNCTION_ARGS){	Oid			ruleoid = PG_GETARG_OID(0);	bool		pretty = PG_GETARG_BOOL(1);	int			prettyFlags;	prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;	return pg_get_ruledef_worker(ruleoid, prettyFlags);}static Datumpg_get_ruledef_worker(Oid ruleoid, int prettyFlags){	text	   *ruledef;	Datum		args[1];	char		nulls[1];	int			spirc;	HeapTuple	ruletup;	TupleDesc	rulettc;	StringInfoData buf;	int			len;	/*	 * Connect to SPI manager	 */	if (SPI_connect() != SPI_OK_CONNECT)		elog(ERROR, "SPI_connect failed");	/*	 * On the first call prepare the plan to lookup pg_rewrite. We read	 * pg_rewrite over the SPI manager instead of using the syscache to be	 * checked for read access on pg_rewrite.	 */	if (plan_getrulebyoid == NULL)	{		Oid			argtypes[1];		void	   *plan;		argtypes[0] = OIDOID;		plan = SPI_prepare(query_getrulebyoid, 1, argtypes);		if (plan == NULL)			elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid);		plan_getrulebyoid = SPI_saveplan(plan);	}	/*	 * Get the pg_rewrite tuple for this rule	 */	args[0] = ObjectIdGetDatum(ruleoid);	nulls[0] = ' ';	spirc = SPI_execp(plan_getrulebyoid, args, nulls, 1);	if (spirc != SPI_OK_SELECT)		elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid);	if (SPI_processed != 1)	{		if (SPI_finish() != SPI_OK_FINISH)			elog(ERROR, "SPI_finish failed");		ruledef = palloc(VARHDRSZ + 1);		VARATT_SIZEP(ruledef) = VARHDRSZ + 1;		VARDATA(ruledef)[0] = '-';		PG_RETURN_TEXT_P(ruledef);	}	ruletup = SPI_tuptable->vals[0];	rulettc = SPI_tuptable->tupdesc;	/*	 * Get the rules definition and put it into executors memory	 */	initStringInfo(&buf);	make_ruledef(&buf, ruletup, rulettc, prettyFlags);	len = buf.len + VARHDRSZ;	ruledef = SPI_palloc(len);	VARATT_SIZEP(ruledef) = len;	memcpy(VARDATA(ruledef), buf.data, buf.len);	pfree(buf.data);	/*	 * Disconnect from SPI manager	 */	if (SPI_finish() != SPI_OK_FINISH)		elog(ERROR, "SPI_finish failed");	/*	 * Easy - isn't it?	 */	PG_RETURN_TEXT_P(ruledef);}/* ---------- * get_viewdef			- Mainly the same thing, but we *				  only return the SELECT part of a view * ---------- */Datumpg_get_viewdef(PG_FUNCTION_ARGS){	/* By OID */	Oid			viewoid = PG_GETARG_OID(0);	text	   *ruledef;	ruledef = pg_do_getviewdef(viewoid, 0);	PG_RETURN_TEXT_P(ruledef);}Datumpg_get_viewdef_ext(PG_FUNCTION_ARGS){	/* By OID */	Oid			viewoid = PG_GETARG_OID(0);	bool		pretty = PG_GETARG_BOOL(1);	text	   *ruledef;	int			prettyFlags;	prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;	ruledef = pg_do_getviewdef(viewoid, prettyFlags);	PG_RETURN_TEXT_P(ruledef);}Datumpg_get_viewdef_name(PG_FUNCTION_ARGS){	/* By qualified name */	text	   *viewname = PG_GETARG_TEXT_P(0);	RangeVar   *viewrel;	Oid			viewoid;	text	   *ruledef;	viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname,														 "get_viewdef"));	viewoid = RangeVarGetRelid(viewrel, false);	ruledef = pg_do_getviewdef(viewoid, 0);	PG_RETURN_TEXT_P(ruledef);}Datumpg_get_viewdef_name_ext(PG_FUNCTION_ARGS){	/* By qualified name */	text	   *viewname = PG_GETARG_TEXT_P(0);	bool		pretty = PG_GETARG_BOOL(1);	int			prettyFlags;	RangeVar   *viewrel;	Oid			viewoid;	text	   *ruledef;	prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;	viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname,														 "get_viewdef"));	viewoid = RangeVarGetRelid(viewrel, false);	ruledef = pg_do_getviewdef(viewoid, prettyFlags);	PG_RETURN_TEXT_P(ruledef);}/* * Common code for by-OID and by-name variants of pg_get_viewdef */static text *pg_do_getviewdef(Oid viewoid, int prettyFlags){	text	   *ruledef;	Datum		args[2];	char		nulls[2];	int			spirc;	HeapTuple	ruletup;	TupleDesc	rulettc;	StringInfoData buf;	int			len;	/*	 * Connect to SPI manager	 */	if (SPI_connect() != SPI_OK_CONNECT)		elog(ERROR, "SPI_connect failed");	/*	 * On the first call prepare the plan to lookup pg_rewrite. We read	 * pg_rewrite over the SPI manager instead of using the syscache to be	 * checked for read access on pg_rewrite.	 */	if (plan_getviewrule == NULL)	{		Oid			argtypes[2];		void	   *plan;		argtypes[0] = OIDOID;		argtypes[1] = NAMEOID;		plan = SPI_prepare(query_getviewrule, 2, argtypes);		if (plan == NULL)			elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule);		plan_getviewrule = SPI_saveplan(plan);	}	/*	 * Get the pg_rewrite tuple for the view's SELECT rule	 */	args[0] = ObjectIdGetDatum(viewoid);	args[1] = PointerGetDatum(ViewSelectRuleName);	nulls[0] = ' ';	nulls[1] = ' ';	spirc = SPI_execp(plan_getviewrule, args, nulls, 2);	if (spirc != SPI_OK_SELECT)		elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid);	initStringInfo(&buf);	if (SPI_processed != 1)		appendStringInfo(&buf, "Not a view");	else	{		/*		 * Get the rules definition and put it into executors memory		 */		ruletup = SPI_tuptable->vals[0];		rulettc = SPI_tuptable->tupdesc;		make_viewdef(&buf, ruletup, rulettc, prettyFlags);	}	len = buf.len + VARHDRSZ;	ruledef = SPI_palloc(len);	VARATT_SIZEP(ruledef) = len;	memcpy(VARDATA(ruledef), buf.data, buf.len);	pfree(buf.data);	/*	 * Disconnect from SPI manager	 */	if (SPI_finish() != SPI_OK_FINISH)		elog(ERROR, "SPI_finish failed");	return ruledef;}/* ---------- * get_triggerdef			- Get the definition of a trigger * ---------- */Datumpg_get_triggerdef(PG_FUNCTION_ARGS){	Oid			trigid = PG_GETARG_OID(0);	text	   *trigdef;	HeapTuple	ht_trig;	Form_pg_trigger trigrec;	int			len;	StringInfoData buf;	Relation	tgrel;	ScanKeyData skey[1];	SysScanDesc tgscan;	int			findx = 0;	char	   *tgname;	/*	 * Fetch the pg_trigger tuple by the Oid of the trigger	 */	tgrel = heap_openr(TriggerRelationName, AccessShareLock);	ScanKeyEntryInitialize(&skey[0], 0x0,						   ObjectIdAttributeNumber, F_OIDEQ,						   ObjectIdGetDatum(trigid));	tgscan = systable_beginscan(tgrel, TriggerOidIndex, true,

⌨️ 快捷键说明

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