ruleutils.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,446 行 · 第 1/5 页

C
2,446
字号
}/* * deparse_context_for_plan		- Build deparse context for a plan node * * When deparsing an expression in a Plan tree, we might have to resolve * OUTER or INNER references.  Pass the plan nodes whose targetlists define * such references, or NULL when none are expected.  (outer_plan and * inner_plan really ought to be declared as "Plan *", but we use "Node *" * to avoid having to include plannodes.h in builtins.h.) * * As a special case, when deparsing a SubqueryScan plan, pass the subplan * as inner_plan (there won't be any regular innerPlan() in this case). * * The plan's rangetable list must also be passed.  We actually prefer to use * the rangetable to resolve simple Vars, but the subplan inputs are needed * for Vars that reference expressions computed in subplan target lists. */List *deparse_context_for_plan(Node *outer_plan, Node *inner_plan,						 List *rtable){	deparse_namespace *dpns;	dpns = (deparse_namespace *) palloc(sizeof(deparse_namespace));	dpns->rtable = rtable;	dpns->outer_plan = (Plan *) outer_plan;	dpns->inner_plan = (Plan *) inner_plan;	/* Return a one-deep namespace stack */	return list_make1(dpns);}/* ---------- * make_ruledef			- reconstruct the CREATE RULE command *				  for a given pg_rewrite tuple * ---------- */static voidmake_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,			 int prettyFlags){	char	   *rulename;	char		ev_type;	Oid			ev_class;	int2		ev_attr;	bool		is_instead;	char	   *ev_qual;	char	   *ev_action;	List	   *actions = NIL;	int			fno;	Datum		dat;	bool		isnull;	/*	 * Get the attribute values from the rules tuple	 */	fno = SPI_fnumber(rulettc, "rulename");	dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);	Assert(!isnull);	rulename = NameStr(*(DatumGetName(dat)));	fno = SPI_fnumber(rulettc, "ev_type");	dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);	Assert(!isnull);	ev_type = DatumGetChar(dat);	fno = SPI_fnumber(rulettc, "ev_class");	dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);	Assert(!isnull);	ev_class = DatumGetObjectId(dat);	fno = SPI_fnumber(rulettc, "ev_attr");	dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);	Assert(!isnull);	ev_attr = DatumGetInt16(dat);	fno = SPI_fnumber(rulettc, "is_instead");	dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);	Assert(!isnull);	is_instead = DatumGetBool(dat);	/* these could be nulls */	fno = SPI_fnumber(rulettc, "ev_qual");	ev_qual = SPI_getvalue(ruletup, rulettc, fno);	fno = SPI_fnumber(rulettc, "ev_action");	ev_action = SPI_getvalue(ruletup, rulettc, fno);	if (ev_action != NULL)		actions = (List *) stringToNode(ev_action);	/*	 * Build the rules definition text	 */	appendStringInfo(buf, "CREATE RULE %s AS",					 quote_identifier(rulename));	if (prettyFlags & PRETTYFLAG_INDENT)		appendStringInfoString(buf, "\n    ON ");	else		appendStringInfoString(buf, " ON ");	/* The event the rule is fired for */	switch (ev_type)	{		case '1':			appendStringInfo(buf, "SELECT");			break;		case '2':			appendStringInfo(buf, "UPDATE");			break;		case '3':			appendStringInfo(buf, "INSERT");			break;		case '4':			appendStringInfo(buf, "DELETE");			break;		default:			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("rule \"%s\" has unsupported event type %d",							rulename, ev_type)));			break;	}	/* The relation the rule is fired on */	appendStringInfo(buf, " TO %s", generate_relation_name(ev_class));	if (ev_attr > 0)		appendStringInfo(buf, ".%s",						 quote_identifier(get_relid_attribute_name(ev_class,																   ev_attr)));	/* If the rule has an event qualification, add it */	if (ev_qual == NULL)		ev_qual = "";	if (strlen(ev_qual) > 0 && strcmp(ev_qual, "<>") != 0)	{		Node	   *qual;		Query	   *query;		deparse_context context;		deparse_namespace dpns;		if (prettyFlags & PRETTYFLAG_INDENT)			appendStringInfoString(buf, "\n  ");		appendStringInfo(buf, " WHERE ");		qual = stringToNode(ev_qual);		/*		 * We need to make a context for recognizing any Vars in the qual		 * (which can only be references to OLD and NEW).  Use the rtable of		 * the first query in the action list for this purpose.		 */		query = (Query *) linitial(actions);		/*		 * If the action is INSERT...SELECT, OLD/NEW have been pushed down		 * into the SELECT, and that's what we need to look at. (Ugly kluge		 * ... try to fix this when we redesign querytrees.)		 */		query = getInsertSelectQuery(query, NULL);		/* Must acquire locks right away; see notes in get_query_def() */		AcquireRewriteLocks(query);		context.buf = buf;		context.namespaces = list_make1(&dpns);		context.varprefix = (list_length(query->rtable) != 1);		context.prettyFlags = prettyFlags;		context.indentLevel = PRETTYINDENT_STD;		dpns.rtable = query->rtable;		dpns.outer_plan = dpns.inner_plan = NULL;		get_rule_expr(qual, &context, false);	}	appendStringInfo(buf, " DO ");	/* The INSTEAD keyword (if so) */	if (is_instead)		appendStringInfo(buf, "INSTEAD ");	/* Finally the rules actions */	if (list_length(actions) > 1)	{		ListCell   *action;		Query	   *query;		appendStringInfo(buf, "(");		foreach(action, actions)		{			query = (Query *) lfirst(action);			get_query_def(query, buf, NIL, NULL, prettyFlags, 0);			if (prettyFlags)				appendStringInfo(buf, ";\n");			else				appendStringInfo(buf, "; ");		}		appendStringInfo(buf, ");");	}	else if (list_length(actions) == 0)	{		appendStringInfo(buf, "NOTHING;");	}	else	{		Query	   *query;		query = (Query *) linitial(actions);		get_query_def(query, buf, NIL, NULL, prettyFlags, 0);		appendStringInfo(buf, ";");	}}/* ---------- * make_viewdef			- reconstruct the SELECT part of a *				  view rewrite rule * ---------- */static voidmake_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,			 int prettyFlags){	Query	   *query;	char		ev_type;	Oid			ev_class;	int2		ev_attr;	bool		is_instead;	char	   *ev_qual;	char	   *ev_action;	List	   *actions = NIL;	Relation	ev_relation;	int			fno;	bool		isnull;	/*	 * 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);	fno = SPI_fnumber(rulettc, "is_instead");	is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);	fno = SPI_fnumber(rulettc, "ev_qual");	ev_qual = SPI_getvalue(ruletup, rulettc, fno);	fno = SPI_fnumber(rulettc, "ev_action");	ev_action = SPI_getvalue(ruletup, rulettc, fno);	if (ev_action != NULL)		actions = (List *) stringToNode(ev_action);	if (list_length(actions) != 1)	{		appendStringInfo(buf, "Not a view");		return;	}	query = (Query *) linitial(actions);	if (ev_type != '1' || ev_attr >= 0 || !is_instead ||		strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT)	{		appendStringInfo(buf, "Not a view");		return;	}	ev_relation = heap_open(ev_class, AccessShareLock);	get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),				  prettyFlags, 0);	appendStringInfo(buf, ";");	heap_close(ev_relation, AccessShareLock);}/* ---------- * get_query_def			- Parse back one query parsetree * * If resultDesc is not NULL, then it is the output tuple descriptor for * the view represented by a SELECT query. * ---------- */static voidget_query_def(Query *query, StringInfo buf, List *parentnamespace,			  TupleDesc resultDesc, int prettyFlags, int startIndent){	deparse_context context;	deparse_namespace dpns;	/*	 * Before we begin to examine the query, acquire locks on referenced	 * relations, and fix up deleted columns in JOIN RTEs.	This ensures	 * consistent results.	Note we assume it's OK to scribble on the passed	 * querytree!	 */	AcquireRewriteLocks(query);	context.buf = buf;	context.namespaces = lcons(&dpns, list_copy(parentnamespace));	context.varprefix = (parentnamespace != NIL ||						 list_length(query->rtable) != 1);	context.prettyFlags = prettyFlags;	context.indentLevel = startIndent;	dpns.rtable = query->rtable;	dpns.outer_plan = dpns.inner_plan = NULL;	switch (query->commandType)	{		case CMD_SELECT:			get_select_query_def(query, &context, resultDesc);			break;		case CMD_UPDATE:			get_update_query_def(query, &context);			break;		case CMD_INSERT:			get_insert_query_def(query, &context);			break;		case CMD_DELETE:			get_delete_query_def(query, &context);			break;		case CMD_NOTHING:			appendStringInfo(buf, "NOTHING");			break;		case CMD_UTILITY:			get_utility_query_def(query, &context);			break;		default:			elog(ERROR, "unrecognized query command type: %d",				 query->commandType);			break;	}}/* ---------- * get_values_def			- Parse back a VALUES list * ---------- */static voidget_values_def(List *values_lists, deparse_context *context){	StringInfo	buf = context->buf;	bool		first_list = true;	ListCell   *vtl;	appendStringInfoString(buf, "VALUES ");	foreach(vtl, values_lists)	{		List	   *sublist = (List *) lfirst(vtl);		bool		first_col = true;		ListCell   *lc;		if (first_list)			first_list = false;		else			appendStringInfoString(buf, ", ");		appendStringInfoChar(buf, '(');		foreach(lc, sublist)		{			Node	   *col = (Node *) lfirst(lc);			if (first_col)				first_col = false;			else				appendStringInfoChar(buf, ',');			/*			 * Strip any top-level nodes representing indirection assignments,			 * then print the result.			 */			get_rule_expr(processIndirection(col, context, false),						  context, false);		}		appendStringInfoChar(buf, ')');	}}/* ---------- * get_select_query_def			- Parse back a SELECT parsetree * ---------- */static voidget_select_query_def(Query *query, deparse_context *context,					 TupleDesc resultDesc){	StringInfo	buf = context->buf;	bool		force_colno;	char	   *sep;	ListCell   *l;	/*	 * If the Query node has a setOperations tree, then it's the top level of	 * a UNION/INTERSECT/EXCEPT query; only the ORDER BY and LIMIT fields are	 * interesting in the top query itself.	 */	if (query->setOperations)	{		get_setop_query(query->setOperations, query, context, resultDesc);		/* ORDER BY clauses must be simple in this case */		force_colno = true;	}	else	{		get_basic_select_query(query, context, resultDesc);		force_colno = false;	}	/* Add the ORDER BY clause if given */	if (query->sortClause != NIL)	{		appendContextKeyword(context, " ORDER BY ",							 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);		sep = "";		foreach(l, query->sortClause)		{			SortClause *srt = (SortClause *) lfirst(l);			Node	   *sortexpr;			Oid			sortcoltype;			TypeCacheEntry *typentry;			appendStringInfoString(buf, sep);			sortexpr = get_rule_sortgroupclause(srt, query->targetList,												force_colno, context);			sortcoltype = exprType(sortexpr);			/* See whether operator is default < or > for datatype */			typentry = lookup_type_cache(sortcoltype,										 TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);			if (srt->sortop == typentry->lt_opr)			{				/* ASC is default, so emit nothing for it */				if (srt->nulls_first)					appendStringInfo(buf, " NULLS FIRST");			}			else if (srt->sortop == typentry->gt_opr)			{				appendStringInfo(buf, " DESC");				/* DESC defaults to NULLS FIRST */				if (!srt->nulls_first)					appendStringInfo(buf, " NULLS LAST");			}			else			{				appendStringInfo(buf, " USING %s",								 generate_operator_name(srt->sortop,														sortcoltype,														sortcoltype));				/* be specific to eliminate ambiguity */				if (srt->nulls_first)					appendStringInfo(buf, " NULLS FIRST");				else					appendStringInfo(buf, " NULLS LAST");			}			sep = ", ";		}	}	/* Add the LIMIT clause if given */	if (query->limitOffset != NULL)	{		appendContextKeyword(context, " OFFSET ",							 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);		get_rule_expr(query->limitOffset, context, false);	}	if (query->limitCount != NULL)	{		appendContextKeyword(context, " LIMIT ",							 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);		if (IsA(query->limitCount, Const) &&

⌨️ 快捷键说明

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