⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parse_clause.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * parse_clause.c *	  handle clauses in parser * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.37 1999/05/26 12:55:35 momjian Exp $ * *------------------------------------------------------------------------- */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "postgres.h"#include "access/heapam.h"#include "catalog/pg_type.h"#include "parser/analyze.h"#include "parser/parse_clause.h"#include "parser/parse_expr.h"#include "parser/parse_node.h"#include "parser/parse_oper.h"#include "parser/parse_relation.h"#include "parser/parse_target.h"#include "parser/parse_coerce.h"#include "nodes/print.h"#include "parse.h"#define ORDER_CLAUSE 0#define GROUP_CLAUSE 1static char *clauseText[] = {"ORDER", "GROUP"};static TargetEntry *			findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause);static void parseFromClause(ParseState *pstate, List *frmList, Node **qual);#ifdef ENABLE_OUTER_JOINSNode	   *transformUsingClause(ParseState *pstate, List *onList, char *lname, char *rname);#endifstatic char	*transformTableEntry(ParseState *pstate, RangeVar *r);/* * makeRangeTable - *	  make a range table with the specified relation (optional) and the *	  from_clause. */voidmakeRangeTable(ParseState *pstate, char *relname, List *frmList, Node **qual){	RangeTblEntry *rte;	int			sublevels_up;	parseFromClause(pstate, frmList, qual);	if (relname == NULL)		return;	if ((refnameRangeTablePosn(pstate, relname, &sublevels_up) == 0)		|| (sublevels_up != 0))		rte = addRangeTableEntry(pstate, relname, relname, FALSE, FALSE);	else		rte = refnameRangeTableEntry(pstate, relname);	/* This could only happen for multi-action rules */	if (pstate->p_target_relation != NULL)		heap_close(pstate->p_target_relation);	pstate->p_target_rangetblentry = rte;	pstate->p_target_relation = heap_open(rte->relid);	/* will close relation later */}/* * transformWhereClause - *	  transforms the qualification and make sure it is of type Boolean * * Now accept an additional argument, which is a qualification derived * from the JOIN/ON or JOIN/USING syntax. * - thomas 1998-12-16 */Node *transformWhereClause(ParseState *pstate, Node *a_expr, Node *o_expr){	A_Expr	   *expr;	Node	   *qual;	if ((a_expr == NULL) && (o_expr == NULL))		return NULL;			/* no qualifiers */	if ((a_expr != NULL) && (o_expr != NULL))	{		A_Expr	   *a = makeNode(A_Expr);		a->oper = AND;		a->opname = NULL;		a->lexpr = o_expr;		a->rexpr = a_expr;		expr = a;	}	else if (o_expr != NULL)		expr = (A_Expr *) o_expr;	else		expr = (A_Expr *) a_expr;	pstate->p_in_where_clause = true;	qual = transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST);	pstate->p_in_where_clause = false;	if (exprType(qual) != BOOLOID)	{		elog(ERROR, "WHERE clause must return type bool, not type %s",			 typeidTypeName(exprType(qual)));	}	return qual;}#ifdef NOT_USEDstatic Attr *makeAttr(char *relname, char *attname){	Attr	   *a = makeNode(Attr);	a->relname = relname;	a->paramNo = NULL;	a->attrs = lcons(makeString(attname), NIL);	a->indirection = NULL;	return a;}#endif#ifdef ENABLE_OUTER_JOINS/* transformUsingClause() * Take an ON or USING clause from a join expression and expand if necessary. */Node *transformUsingClause(ParseState *pstate, List *onList, char *lname, char *rname){	A_Expr	   *expr = NULL;	List	   *on;	Node	   *qual;	foreach(on, onList)	{		qual = lfirst(on);		/*		 * Ident node means it is just a column name from a real USING		 * clause...		 */		if (IsA(qual, Ident))		{			Ident	   *i = (Ident *) qual;			Attr	   *lattr = makeAttr(lname, i->name);			Attr	   *rattr = makeAttr(rname, i->name);			A_Expr	   *e = makeNode(A_Expr);			e->oper = OP;			e->opname = "=";			e->lexpr = (Node *) lattr;			e->rexpr = (Node *) rattr;			if (expr != NULL)			{				A_Expr	   *a = makeNode(A_Expr);				a->oper = AND;				a->opname = NULL;				a->lexpr = (Node *) expr;				a->rexpr = (Node *) e;				expr = a;			}			else				expr = e;		}		/* otherwise, we have an expression from an ON clause... */		else		{			if (expr != NULL)			{				A_Expr	   *a = makeNode(A_Expr);				a->oper = AND;				a->opname = NULL;				a->lexpr = (Node *) expr;				a->rexpr = (Node *) qual;				expr = a;			}			else				expr = (A_Expr *) qual;		}	}	return ((Node *) transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST));}#endifstatic char *transformTableEntry(ParseState *pstate, RangeVar *r){	RelExpr    *baserel = r->relExpr;	char	   *relname = baserel->relname;	char	   *refname = r->name;	RangeTblEntry *rte;	if (refname == NULL)		refname = relname;	/*	 * marks this entry to indicate it comes from the FROM clause. In SQL,	 * the target list can only refer to range variables specified in the	 * from clause but we follow the more powerful POSTQUEL semantics and	 * automatically generate the range variable if not specified. However	 * there are times we need to know whether the entries are legitimate.	 *	 * eg. select * from foo f where f.x = 1; will generate wrong answer if	 * we expand * to foo.x.	 */	rte = addRangeTableEntry(pstate, relname, refname, baserel->inh, TRUE);	return refname;}/* * parseFromClause - *	  turns the table references specified in the from-clause into a *	  range table. The range table may grow as we transform the expressions *	  in the target list. (Note that this happens because in POSTQUEL, we *	  allow references to relations not specified in the from-clause. We *	  also allow now as an extension.) * * The FROM clause can now contain JoinExpr nodes, which contain parsing info * for inner and outer joins. The USING clause must be expanded into a qualification * for an inner join at least, since that is compatible with the old syntax. * Not sure yet how to handle outer joins, but it will become clear eventually? * - thomas 1998-12-16 */static voidparseFromClause(ParseState *pstate, List *frmList, Node **qual){	List	   *fl;	if (qual != NULL)		*qual = NULL;	foreach(fl, frmList)	{		Node	   *n = lfirst(fl);		/*		 * marks this entry to indicate it comes from the FROM clause. In		 * SQL, the target list can only refer to range variables		 * specified in the from clause but we follow the more powerful		 * POSTQUEL semantics and automatically generate the range		 * variable if not specified. However there are times we need to		 * know whether the entries are legitimate.		 *		 * eg. select * from foo f where f.x = 1; will generate wrong answer		 * if we expand * to foo.x.		 */		if (IsA(n, RangeVar))			transformTableEntry(pstate, (RangeVar *) n);		else if (IsA(n, JoinExpr))		{			JoinExpr   *j = (JoinExpr *) n;#ifdef ENABLE_OUTER_JOINS			char	   *lname = transformTableEntry(pstate, (RangeVar *) j->larg);#endif			char	   *rname;			if (IsA((Node *) j->rarg, RangeVar))				rname = transformTableEntry(pstate, (RangeVar *) j->rarg);			else				elog(ERROR, "Nested JOINs are not yet supported");#ifdef ENABLE_OUTER_JOINS			if (j->jointype == INNER_P)			{				/*				 * This is an inner join, so rip apart the join node and				 * transform into a traditional FROM list. NATURAL JOIN				 * and USING clauses both change the shape of the result.				 * Need to generate a list of result columns to use for				 * target list expansion and validation. Not doing this				 * yet though!				 */				if (IsA(j->quals, List))					j->quals = lcons(transformUsingClause(pstate, (List *) j->quals, lname, rname), NIL);				Assert(qual != NULL);				if (*qual == NULL)					*qual = lfirst(j->quals);				else					elog(ERROR, "Multiple JOIN/ON clauses not handled (internal error)");				/*				 * if we are transforming this node back into a FROM list,				 * then we will need to replace the node with two nodes.				 * Will need access to the previous list item to change				 * the link pointer to reference these new nodes. Try				 * accumulating and returning a new list. - thomas				 * 1999-01-08 Not doing this yet though!				 */			}			else if ((j->jointype == LEFT)					 || (j->jointype == RIGHT)					 || (j->jointype == FULL))				elog(ERROR, "OUTER JOIN is not implemented");			else				elog(ERROR, "Unrecognized JOIN clause; tag is %d (internal error)",					 j->jointype);#else			elog(ERROR, "JOIN expressions are not yet implemented");#endif		}		else			elog(ERROR, "parseFromClause: unexpected FROM clause node (internal error)"				 "\n\t%s", nodeToString(n));	}}/* *	findTargetlistEntry - *	  returns the Resdom in the target list matching the specified varname *	  and range. If none exist one is created. * *	  Rewritten for ver 6.4 to handle expressions in the GROUP/ORDER BY clauses. *	   - daveh@insightdist.com	1998-07-31 * */static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause){	List	   *l;	int			rtable_pos = 0,				target_pos = 0,				targetlist_pos = 0;	TargetEntry *target_result = NULL;	Value	   *val = NULL;	char	   *relname = NULL;	char	   *name = NULL;	Node	   *expr = NULL;	int			relCnt = 0;	/* Pull out some values before looping thru target list  */	switch (nodeTag(node))	{		case T_Attr:			relname = ((Attr *) node)->relname;			val = (Value *) lfirst(((Attr *) node)->attrs);			name = strVal(val);			rtable_pos = refnameRangeTablePosn(pstate, relname, NULL);			relCnt = length(pstate->p_rtable);			break;		case T_Ident:			name = ((Ident *) node)->name;			relCnt = length(pstate->p_rtable);			break;		case T_A_Const:			val = &((A_Const *) node)->val;			if (nodeTag(val) != T_Integer)				elog(ERROR, "Illegal Constant in %s BY", clauseText[clause]);			target_pos = intVal(val);			break;		case T_FuncCall:		case T_A_Expr:			expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);			break;		default:			elog(ERROR, "Illegal %s BY node = %d", clauseText[clause], nodeTag(node));	}	/*	 * Loop through target entries and try to match to node	 */	foreach(l, tlist)	{		TargetEntry *target = (TargetEntry *) lfirst(l);		Resdom	   *resnode = target->resdom;		Var		   *var = (Var *) target->expr;		char	   *resname = resnode->resname;		int			test_rtable_pos = var->varno;		++targetlist_pos;		switch (nodeTag(node))		{			case T_Attr:				if (strcmp(resname, name) == 0 && rtable_pos == test_rtable_pos)				{					/*					 * Check for only 1 table & ORDER BY -ambiguity does					 * not matter here					 */					if (clause == ORDER_CLAUSE && relCnt == 1)						return target;

⌨️ 快捷键说明

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