ruleutils.c

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

C
2,475
字号
	{		appendContextKeyword(context, " HAVING ",							 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);		get_rule_expr(query->havingQual, context, false);	}}static voidget_setop_query(Node *setOp, Query *query, deparse_context *context,				TupleDesc resultDesc){	StringInfo	buf = context->buf;	bool		need_paren;	if (IsA(setOp, RangeTblRef))	{		RangeTblRef *rtr = (RangeTblRef *) setOp;		RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);		Query	   *subquery = rte->subquery;		Assert(subquery != NULL);		Assert(subquery->setOperations == NULL);		/* Need parens if ORDER BY, FOR UPDATE, or LIMIT; see gram.y */		need_paren = (subquery->sortClause ||					  subquery->rowMarks ||					  subquery->limitOffset ||					  subquery->limitCount);		if (need_paren)			appendStringInfoChar(buf, '(');		get_query_def(subquery, buf, context->namespaces, resultDesc,					  context->prettyFlags, context->indentLevel);		if (need_paren)			appendStringInfoChar(buf, ')');	}	else if (IsA(setOp, SetOperationStmt))	{		SetOperationStmt *op = (SetOperationStmt *) setOp;		/*		 * We force parens whenever nesting two SetOperationStmts.		 * There are some cases in which parens are needed around a leaf		 * query too, but those are more easily handled at the next level		 * down (see code above).		 */		need_paren = !IsA(op->larg, RangeTblRef);		if (need_paren)			appendStringInfoChar(buf, '(');		get_setop_query(op->larg, query, context, resultDesc);		if (need_paren)			appendStringInfoChar(buf, ')');		if (!PRETTY_INDENT(context))			appendStringInfoChar(buf, ' ');		switch (op->op)		{			case SETOP_UNION:				appendContextKeyword(context, "UNION ",									 -PRETTYINDENT_STD, 0, 0);				break;			case SETOP_INTERSECT:				appendContextKeyword(context, "INTERSECT ",									 -PRETTYINDENT_STD, 0, 0);				break;			case SETOP_EXCEPT:				appendContextKeyword(context, "EXCEPT ",									 -PRETTYINDENT_STD, 0, 0);				break;			default:				elog(ERROR, "unrecognized set op: %d",					 (int) op->op);		}		if (op->all)			appendStringInfo(buf, "ALL ");		if (PRETTY_INDENT(context))			appendStringInfoChar(buf, '\n');		need_paren = !IsA(op->rarg, RangeTblRef);		if (need_paren)			appendStringInfoChar(buf, '(');		get_setop_query(op->rarg, query, context, resultDesc);		if (need_paren)			appendStringInfoChar(buf, ')');	}	else	{		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(setOp));	}}/* * Display a sort/group clause. * * Also returns the expression tree, so caller need not find it again. */static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist, bool force_colno,						 deparse_context *context){	StringInfo	buf = context->buf;	TargetEntry *tle;	Node	   *expr;	tle = get_sortgroupclause_tle(srt, tlist);	expr = (Node *) tle->expr;	/*	 * Use column-number form if requested by caller or if expression is a	 * constant --- a constant is ambiguous (and will be misinterpreted by	 * findTargetlistEntry()) if we dump it explicitly.	 */	if (force_colno || (expr && IsA(expr, Const)))	{		Assert(!tle->resdom->resjunk);		appendStringInfo(buf, "%d", tle->resdom->resno);	}	else		get_rule_expr(expr, context, true);	return expr;}/* ---------- * get_insert_query_def			- Parse back an INSERT parsetree * ---------- */static voidget_insert_query_def(Query *query, deparse_context *context){	StringInfo	buf = context->buf;	RangeTblEntry *select_rte = NULL;	RangeTblEntry *rte;	char	   *sep;	List	   *l;	/*	 * If it's an INSERT ... SELECT there will be a single subquery RTE	 * for the SELECT.	 */	foreach(l, query->rtable)	{		rte = (RangeTblEntry *) lfirst(l);		if (rte->rtekind != RTE_SUBQUERY)			continue;		if (select_rte)			elog(ERROR, "too many RTEs in INSERT");		select_rte = rte;	}	/*	 * Start the query with INSERT INTO relname	 */	rte = rt_fetch(query->resultRelation, query->rtable);	Assert(rte->rtekind == RTE_RELATION);	if (PRETTY_INDENT(context))	{		context->indentLevel += PRETTYINDENT_STD;		appendStringInfoChar(buf, ' ');	}	appendStringInfo(buf, "INSERT INTO %s",					 generate_relation_name(rte->relid));	/* Add the insert-column-names list */	sep = " (";	foreach(l, query->targetList)	{		TargetEntry *tle = (TargetEntry *) lfirst(l);		if (tle->resdom->resjunk)			continue;			/* ignore junk entries */		appendStringInfo(buf, sep);		sep = ", ";		appendStringInfo(buf, "%s",						 quote_identifier(get_relid_attribute_name(rte->relid,														tle->resdom->resno)));	}	appendStringInfo(buf, ") ");	/* Add the VALUES or the SELECT */	if (select_rte == NULL)	{		appendContextKeyword(context, "VALUES (",							 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);		sep = "";		foreach(l, query->targetList)		{			TargetEntry *tle = (TargetEntry *) lfirst(l);			if (tle->resdom->resjunk)				continue;		/* ignore junk entries */			appendStringInfo(buf, sep);			sep = ", ";			get_rule_expr((Node *) tle->expr, context, false);		}		appendStringInfoChar(buf, ')');	}	else		get_query_def(select_rte->subquery, buf, NIL, NULL,					  context->prettyFlags, context->indentLevel);}/* ---------- * get_update_query_def			- Parse back an UPDATE parsetree * ---------- */static voidget_update_query_def(Query *query, deparse_context *context){	StringInfo	buf = context->buf;	char	   *sep;	RangeTblEntry *rte;	List	   *l;	/*	 * Start the query with UPDATE relname SET	 */	rte = rt_fetch(query->resultRelation, query->rtable);	Assert(rte->rtekind == RTE_RELATION);	if (PRETTY_INDENT(context))	{		appendStringInfoChar(buf, ' ');		context->indentLevel += PRETTYINDENT_STD;	}	appendStringInfo(buf, "UPDATE %s%s SET ",					 only_marker(rte),					 generate_relation_name(rte->relid));	/* Add the comma separated list of 'attname = value' */	sep = "";	foreach(l, query->targetList)	{		TargetEntry *tle = (TargetEntry *) lfirst(l);		if (tle->resdom->resjunk)			continue;			/* ignore junk entries */		appendStringInfo(buf, sep);		sep = ", ";		/*		 * If the update expression is an array assignment, we mustn't put		 * out "attname =" here; it will come out of the display of the		 * ArrayRef node instead.		 */		if (!tleIsArrayAssign(tle))			appendStringInfo(buf, "%s = ",						quote_identifier(get_relid_attribute_name(rte->relid,														tle->resdom->resno)));		get_rule_expr((Node *) tle->expr, context, false);	}	/* Add the FROM clause if needed */	get_from_clause(query, context);	/* Finally add a 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);	}}/* ---------- * get_delete_query_def			- Parse back a DELETE parsetree * ---------- */static voidget_delete_query_def(Query *query, deparse_context *context){	StringInfo	buf = context->buf;	RangeTblEntry *rte;	/*	 * Start the query with DELETE FROM relname	 */	rte = rt_fetch(query->resultRelation, query->rtable);	Assert(rte->rtekind == RTE_RELATION);	if (PRETTY_INDENT(context))	{		context->indentLevel += PRETTYINDENT_STD;		appendStringInfoChar(buf, ' ');	}	appendStringInfo(buf, "DELETE FROM %s%s",					 only_marker(rte),					 generate_relation_name(rte->relid));	/* Add a 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);	}}/* ---------- * get_utility_query_def			- Parse back a UTILITY parsetree * ---------- */static voidget_utility_query_def(Query *query, deparse_context *context){	StringInfo	buf = context->buf;	if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))	{		NotifyStmt *stmt = (NotifyStmt *) query->utilityStmt;		appendContextKeyword(context, "",							 0, PRETTYINDENT_STD, 1);		appendStringInfo(buf, "NOTIFY %s",				   quote_qualified_identifier(stmt->relation->schemaname,											  stmt->relation->relname));	}	else	{		/* Currently only NOTIFY utility commands can appear in rules */		elog(ERROR, "unexpected utility statement type");	}}/* * Get the schemaname, refname and attname for a (possibly nonlocal) Var. * * schemaname is usually returned as NULL.	It will be non-null only if * use of the unqualified refname would find the wrong RTE. * * refname will be returned as NULL if the Var references an unnamed join. * In this case the Var *must* be displayed without any qualification. * * attname will be returned as NULL if the Var represents a whole tuple * of the relation.  (Typically we'd want to display the Var as "foo.*", * but it's convenient to return NULL to make it easier for callers to * distinguish this case.) */static voidget_names_for_var(Var *var, deparse_context *context,				  char **schemaname, char **refname, char **attname){	List	   *nslist = context->namespaces;	int			sup = var->varlevelsup;	deparse_namespace *dpns;	RangeTblEntry *rte;	/* Find appropriate nesting depth */	while (sup-- > 0 && nslist != NIL)		nslist = lnext(nslist);	if (nslist == NIL)		elog(ERROR, "bogus varlevelsup: %d", var->varlevelsup);	dpns = (deparse_namespace *) lfirst(nslist);	/* Find the relevant RTE */	if (var->varno >= 1 && var->varno <= length(dpns->rtable))		rte = rt_fetch(var->varno, dpns->rtable);	else if (var->varno == dpns->outer_varno)		rte = dpns->outer_rte;	else if (var->varno == dpns->inner_varno)		rte = dpns->inner_rte;	else		rte = NULL;	if (rte == NULL)		elog(ERROR, "bogus varno: %d", var->varno);	/* Emit results */	*schemaname = NULL;			/* default assumptions */	*refname = rte->eref->aliasname;	/* Exceptions occur only if the RTE is alias-less */	if (rte->alias == NULL)	{		if (rte->rtekind == RTE_RELATION)		{			/*			 * It's possible that use of the bare refname would find			 * another more-closely-nested RTE, or be ambiguous, in which			 * case we need to specify the schemaname to avoid these			 * errors.			 */			if (find_rte_by_refname(rte->eref->aliasname, context) != rte)				*schemaname =					get_namespace_name(get_rel_namespace(rte->relid));		}		else if (rte->rtekind == RTE_JOIN)		{			/* Unnamed join has neither schemaname nor refname */			*refname = NULL;		}	}	if (var->varattno == InvalidAttrNumber)		*attname = NULL;	else		*attname = get_rte_attribute_name(rte, var->varattno);}/* * find_rte_by_refname		- look up an RTE by refname in a deparse context * * Returns NULL if there is no matching RTE or the refname is ambiguous. * * NOTE: this code is not really correct since it does not take account of * the fact that not all the RTEs in a rangetable may be visible from the * point where a Var reference appears.  For the purposes we need, however, * the only consequence of a false match is that we might stick a schema * qualifier on a Var that doesn't really need it.  So it seems close * enough. */static RangeTblEntry *find_rte_by_refname(const char *refname, deparse_context *context){	RangeTblEntry *result = NULL;	List	   *nslist;	foreach(nslist, context->namespaces)	{		deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);		List	   *rtlist;		foreach(rtlist, dpns->rtable)		{			RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtlist);			if (strcmp(rte->eref->aliasname, refname) == 0)			{				if (result)					return NULL;	/* it's ambiguous */				result = rte;			}		}		if (dpns->outer_rte &&			strcmp(dpns->outer_rte->eref->aliasname, refname) == 0)		{			if (result)				return NULL;	/* it's ambiguous */			result = dpns->outer_rte;		}		if (dpns->inner_rte &&			strcmp(dpns->inner_rte->eref->aliasname, refname) == 0)		{			if (result)				return NULL;	/* it's ambiguous */			result = dpns->inner_rte;		}		if (result)			break;	}	return result;}/* * get_simple_binary_op_name * * helper function for isSimpleNode * will return single char binary operator name, or NULL if it's not */static const char *get_simple_binary_op_name(OpExpr *expr){	List	   *args = expr->args;	if (length(args) == 2)	{		/* binary operator */		Node	   *arg1 = (Node *) lfirst(args);		Node	   *arg2 = (Node *) lsecond(args);		const char *op;		op = generate_operator_name(expr->opno, exprType(arg1), exprType(arg2));		if (strlen(op) == 1)			return op;	}	return NULL;}/* * isSimpleNode - check if given node is simple (doesn't need parenthesizing) * *	true   : simple in the context of parent node's type *	false  : not simple */static boolisSimpleNode(Node *n

⌨️ 快捷键说明

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