ruleutils.c

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

C
2,475
字号
	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 *) lfirst(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);		context.buf = buf;		context.namespaces = makeList1(&dpns);		context.varprefix = (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 (length(actions) > 1)	{		List	   *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 (length(actions) == 0)	{		appendStringInfo(buf, "NOTHING;");	}	else	{		Query	   *query;		query = (Query *) lfirst(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 (length(actions) != 1)	{		appendStringInfo(buf, "Not a view");		return;	}	query = (Query *) lfirst(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;	context.buf = buf;	context.namespaces = lcons(&dpns, parentnamespace);	context.varprefix = (parentnamespace != NIL ||						 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;	List	   *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;			appendStringInfo(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);	}}static voidget_basic_select_query(Query *query, deparse_context *context,					   TupleDesc resultDesc){	StringInfo	buf = context->buf;	char	   *sep;	List	   *l;	int			colno;	/*	 * Build up the query string - first we say SELECT	 */	if (PRETTY_INDENT(context))	{		context->indentLevel += PRETTYINDENT_STD;		appendStringInfoChar(buf, ' ');	}	appendStringInfo(buf, "SELECT");	/* Add the DISTINCT clause if given */	if (query->distinctClause != NIL)	{		if (has_distinct_on_clause(query))		{			appendStringInfo(buf, " DISTINCT ON (");			sep = "";			foreach(l, query->distinctClause)			{				SortClause *srt = (SortClause *) lfirst(l);				appendStringInfo(buf, sep);				get_rule_sortgroupclause(srt, query->targetList,										 false, context);				sep = ", ";			}			appendStringInfo(buf, ")");		}		else			appendStringInfo(buf, " DISTINCT");	}	/* Then we tell what to select (the targetlist) */	sep = " ";	colno = 0;	foreach(l, query->targetList)	{		TargetEntry *tle = (TargetEntry *) lfirst(l);		char	   *colname;		if (tle->resdom->resjunk)			continue;			/* ignore junk entries */		appendStringInfo(buf, sep);		sep = ", ";		colno++;		get_rule_expr((Node *) tle->expr, context, true);		/*		 * Figure out what the result column should be called.	In the		 * context of a view, use the view's tuple descriptor (so as to		 * pick up the effects of any column RENAME that's been done on		 * the view).  Otherwise, just use what we can find in the TLE.		 */		if (resultDesc && colno <= resultDesc->natts)			colname = NameStr(resultDesc->attrs[colno - 1]->attname);		else			colname = tle->resdom->resname;		if (colname)			/* resname could be NULL */		{			/* Check if we must say AS ... */			bool		tell_as;			if (!IsA(tle->expr, Var))				tell_as = (strcmp(colname, "?column?") != 0);			else			{				Var		   *var = (Var *) (tle->expr);				char	   *schemaname;				char	   *refname;				char	   *attname;				get_names_for_var(var, context,								  &schemaname, &refname, &attname);				tell_as = (attname == NULL ||						   strcmp(attname, colname) != 0);			}			/* and do if so */			if (tell_as)				appendStringInfo(buf, " AS %s", quote_identifier(colname));		}	}	/* Add the FROM clause if needed */	get_from_clause(query, context);	/* Add the WHERE clause if given */	if (query->jointree->quals != NULL)	{		appendContextKeyword(context, " WHERE ",							 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);		get_rule_expr(query->jointree->quals, context, false);	}	/* Add the GROUP BY clause if given */	if (query->groupClause != NULL)	{		appendContextKeyword(context, " GROUP BY ",							 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);		sep = "";		foreach(l, query->groupClause)		{			GroupClause *grp = (GroupClause *) lfirst(l);			appendStringInfo(buf, sep);			get_rule_sortgroupclause(grp, query->targetList,									 false, context);			sep = ", ";		}	}	/* Add the HAVING clause if given */	if (query->havingQual != NULL)

⌨️ 快捷键说明

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