ruleutils.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,434 行 · 第 1/5 页

C
2,434
字号
 * * The returned node is actually the given RangeTblEntry, but we declare it * as just Node to discourage callers from assuming anything. */Node *deparse_context_for_rte(RangeTblEntry *rte){	return (Node *) rte;}/* * deparse_context_for_subplan	- Build deparse context for a plan node * * Helper routine to build one of the inputs for deparse_context_for_plan. * Pass the tlist of the subplan node, plus the query rangetable. * * The returned node is actually a RangeTblEntry, but we declare it as just * Node to discourage callers from assuming anything. */Node *deparse_context_for_subplan(const char *name, List *tlist,							List *rtable){	RangeTblEntry *rte = makeNode(RangeTblEntry);	List	   *attrs = NIL;	int			nattrs = 0;	int			rtablelength = list_length(rtable);	ListCell   *tl;	char		buf[32];	foreach(tl, tlist)	{		TargetEntry *tle = lfirst(tl);		nattrs++;		Assert(tle->resno == nattrs);		if (tle->resname)		{			attrs = lappend(attrs, makeString(tle->resname));			continue;		}		if (tle->expr && IsA(tle->expr, Var))		{			Var		   *var = (Var *) tle->expr;			/* varno/varattno won't be any good, but varnoold might be */			if (var->varnoold > 0 && var->varnoold <= rtablelength)			{				RangeTblEntry *varrte = rt_fetch(var->varnoold, rtable);				AttrNumber	varattnum = var->varoattno;				/* need this test in case it's referencing a resjunk col */				if (varattnum <= list_length(varrte->eref->colnames))				{					char	   *varname;					varname = get_rte_attribute_name(varrte, varattnum);					attrs = lappend(attrs, makeString(varname));					continue;				}			}		}		/* Fallback if can't get name */		snprintf(buf, sizeof(buf), "?column%d?", tle->resno);		attrs = lappend(attrs, makeString(pstrdup(buf)));	}	/*	 * We create an RTE_SPECIAL RangeTblEntry, and store the given tlist	 * in its coldeflist field.  This is a hack to make the tlist available	 * to get_name_for_var_field().  RTE_SPECIAL nodes shouldn't appear in	 * deparse contexts otherwise.	 */	rte->rtekind = RTE_SPECIAL;	rte->relid = InvalidOid;	rte->coldeflist = tlist;	rte->eref = makeAlias(name, attrs);	rte->inh = false;	rte->inFromCl = true;	return (Node *) rte;}/* ---------- * 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_varno = dpns.inner_varno = 0;		dpns.outer_rte = dpns.inner_rte = 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_varno = dpns.inner_varno = 0;	dpns.outer_rte = dpns.inner_rte = 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_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 */ ;			else if (srt->sortop == typentry->gt_opr)				appendStringInfo(buf, " DESC");			else				appendStringInfo(buf, " USING %s",								 generate_operator_name(srt->sortop,														sortcoltype,														sortcoltype));			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) &&			((Const *) query->limitCount)->constisnull)			appendStringInfo(buf, "ALL");		else			get_rule_expr(query->limitCount, context, false);	}

⌨️ 快捷键说明

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