ruleutils.c

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

C
2,446
字号
			((Const *) query->limitCount)->constisnull)			appendStringInfo(buf, "ALL");		else			get_rule_expr(query->limitCount, context, false);	}	/* Add FOR UPDATE/SHARE clauses if present */	foreach(l, query->rowMarks)	{		RowMarkClause *rc = (RowMarkClause *) lfirst(l);		RangeTblEntry *rte = rt_fetch(rc->rti, query->rtable);		if (rc->forUpdate)			appendContextKeyword(context, " FOR UPDATE",								 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);		else			appendContextKeyword(context, " FOR SHARE",								 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);		appendStringInfo(buf, " OF %s",						 quote_identifier(rte->eref->aliasname));		if (rc->noWait)			appendStringInfo(buf, " NOWAIT");	}}static voidget_basic_select_query(Query *query, deparse_context *context,					   TupleDesc resultDesc){	StringInfo	buf = context->buf;	char	   *sep;	ListCell   *l;	if (PRETTY_INDENT(context))	{		context->indentLevel += PRETTYINDENT_STD;		appendStringInfoChar(buf, ' ');	}	/*	 * If the query looks like SELECT * FROM (VALUES ...), then print just the	 * VALUES part.  This reverses what transformValuesClause() did at parse	 * time.  If the jointree contains just a single VALUES RTE, we assume	 * this case applies (without looking at the targetlist...)	 */	if (list_length(query->jointree->fromlist) == 1)	{		RangeTblRef *rtr = (RangeTblRef *) linitial(query->jointree->fromlist);		if (IsA(rtr, RangeTblRef))		{			RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);			if (rte->rtekind == RTE_VALUES)			{				get_values_def(rte->values_lists, context);				return;			}		}	}	/*	 * Build up the query string - first we say SELECT	 */	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);				appendStringInfoString(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) */	get_target_list(query->targetList, context, resultDesc);	/* Add the FROM clause if needed */	get_from_clause(query, " FROM ", 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);			appendStringInfoString(buf, sep);			get_rule_sortgroupclause(grp, query->targetList,									 false, context);			sep = ", ";		}	}	/* Add the HAVING clause if given */	if (query->havingQual != NULL)	{		appendContextKeyword(context, " HAVING ",							 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);		get_rule_expr(query->havingQual, context, false);	}}/* ---------- * get_target_list			- Parse back a SELECT target list * * This is also used for RETURNING lists in INSERT/UPDATE/DELETE. * ---------- */static voidget_target_list(List *targetList, deparse_context *context,				TupleDesc resultDesc){	StringInfo	buf = context->buf;	char	   *sep;	int			colno;	ListCell   *l;	sep = " ";	colno = 0;	foreach(l, targetList)	{		TargetEntry *tle = (TargetEntry *) lfirst(l);		char	   *colname;		char	   *attname;		if (tle->resjunk)			continue;			/* ignore junk entries */		appendStringInfoString(buf, sep);		sep = ", ";		colno++;		/*		 * We special-case Var nodes rather than using get_rule_expr. This is		 * needed because get_rule_expr will display a whole-row Var as		 * "foo.*", which is the preferred notation in most contexts, but at		 * the top level of a SELECT list it's not right (the parser will		 * expand that notation into multiple columns, yielding behavior		 * different from a whole-row Var).  We want just "foo", instead.		 */		if (tle->expr && IsA(tle->expr, Var))		{			attname = get_variable((Var *) tle->expr, 0, false, context);		}		else		{			get_rule_expr((Node *) tle->expr, context, true);			/* We'll show the AS name unless it's this: */			attname = "?column?";		}		/*		 * 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->resname;		/* Show AS unless the column's name is correct as-is */		if (colname)			/* resname could be NULL */		{			if (attname == NULL || strcmp(attname, colname) != 0)				appendStringInfo(buf, " AS %s", quote_identifier(colname));		}	}}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, PRETTYINDENT_STD, 0);				break;			case SETOP_INTERSECT:				appendContextKeyword(context, "INTERSECT ",									 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);				break;			case SETOP_EXCEPT:				appendContextKeyword(context, "EXCEPT ",									 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);				break;			default:				elog(ERROR, "unrecognized set op: %d",					 (int) op->op);		}		if (op->all)			appendStringInfo(buf, "ALL ");		if (PRETTY_INDENT(context))			appendContextKeyword(context, "", 0, 0, 0);		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.  Otherwise, if	 * expression is a constant, force it to be dumped with an explicit	 * cast as decoration --- this is because a simple integer constant	 * is ambiguous (and will be misinterpreted by findTargetlistEntry())	 * if we dump it without any decoration.  Otherwise, just dump the	 * expression normally.	 */	if (force_colno)	{		Assert(!tle->resjunk);		appendStringInfo(buf, "%d", tle->resno);	}	else if (expr && IsA(expr, Const))		get_const_expr((Const *) expr, context, 1);	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 *values_rte = NULL;	RangeTblEntry *rte;	char	   *sep;	ListCell   *values_cell;	ListCell   *l;	List	   *strippedexprs;	/*	 * If it's an INSERT ... SELECT or VALUES (...), (...), ... there will be	 * a single RTE for the SELECT or VALUES.	 */	foreach(l, query->rtable)	{		rte = (RangeTblEntry *) lfirst(l);		if (rte->rtekind == RTE_SUBQUERY)		{			if (select_rte)				elog(ERROR, "too many subquery RTEs in INSERT");			select_rte = rte;		}		if (rte->rtekind == RTE_VALUES)		{			if (values_rte)				elog(ERROR, "too many values RTEs in INSERT");			values_rte = rte;		}	}	if (select_rte && values_rte)		elog(ERROR, "both subquery and values RTEs in INSERT");	/*	 * 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.  To handle indirection properly, we	 * need to look for indirection nodes in the top targetlist (if it's	 * INSERT ... SELECT or INSERT ... single VALUES), or in the first	 * expression list of the VALUES RTE (if it's INSERT ... multi VALUES). We	 * assume that all the expression lists will have similar indirection in	 * the latter case.	 */	if (values_rte)		values_cell = list_head((List *) linitial(values_rte->values_lists));	else		values_cell = NULL;	strippedexprs = NIL;	sep = "";	foreach(l, query->targetList)	{		TargetEntry *tle = (TargetEntry *) lfirst(l);		if (tle->resjunk)			continue;			/* ignore junk entries */		appendStringInfoString(buf, sep);		sep = ", ";		/*		 * Put out name of target column; look in the catalogs, not at		 * tle->resname, since resname will fail to track RENAME.		 */		appendStringInfoString(buf,						quote_identifier(get_relid_attribute_name(rte->relid,															   tle->resno)));		/*		 * Print any indirection needed (subfields or subscripts), and strip		 * off the top-level nodes representing the indirection assignments.		 */		if (values_cell)		{			/* we discard the stripped expression in this case */			processIndirection((Node *) lfirst(values_cell), context, true);			values_cell = lnext(values_cell);		}		else		{			/* we keep a list of the stripped expressions in this case */			strippedexprs = lappend(strippedexprs,									processIndirection((Node *) tle->expr,													   context, true));		}	}	appendStringInfo(buf, ") ");	if (select_rte)	{		/* Add the SELECT */		get_query_def(select_rte->subquery, buf, NIL, NULL,					  context->prettyFlags, context->indentLevel);	}	else if (values_rte)	{		/* Add the multi-VALUES expression lists */		get_values_def(values_rte->values_lists, context);	}	else	{		/* Add the single-VALUES expression list */		appendContextKeyword(context, "VALUES (",							 -PRETTYINDENT_STD, PRETTYINDENT_STD, 2);		get_rule_expr((Node *) strippedexprs, context, false);		appendStringInfoChar(buf, ')');	}	/* Add RETURNING if present */	if (query->returningList)	{		appendContextKeyword(context, " RETURNING",							 -PRETTYINDENT_STD, PRETTYINDENT_STD, 1);		get_target_list(query->returningList, context, NULL);	}}/* ---------- * 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;	ListCell   *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",					 only_marker(rte),					 generate_relation_name(rte->relid));	if (rte->alias != NULL)		appendStringInfo(buf, " %s",						 quote_identifier(rte->alias->aliasname));	appendStringInfoString(buf, "

⌨️ 快捷键说明

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