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

📄 parse_target.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
				 errmsg("SELECT * with no tables specified is not valid")));	foreach(l, pstate->p_varnamespace)	{		RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);		int			rtindex = RTERangeTablePosn(pstate, rte, NULL);		target = list_concat(target,							 expandRelAttrs(pstate, rte, rtindex, 0));	}	return target;}/* * ExpandIndirectionStar() *		Turns foo.* (in the target list) into a list of targetlist entries. * * This handles the case where '*' appears as the last item in A_Indirection. */static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind){	Node	   *expr;	TupleDesc	tupleDesc;	int			numAttrs;	int			i;	List	   *te_list = NIL;	/* Strip off the '*' to create a reference to the rowtype object */	ind = copyObject(ind);	ind->indirection = list_truncate(ind->indirection,									 list_length(ind->indirection) - 1);	/* And transform that */	expr = transformExpr(pstate, (Node *) ind);	/*	 * Verify it's a composite type, and get the tupdesc.  We use	 * get_expr_result_type() because that can handle references to functions	 * returning anonymous record types.  If that fails, use	 * lookup_rowtype_tupdesc(), which will almost certainly fail as well, but	 * it will give an appropriate error message.	 *	 * If it's a Var of type RECORD, we have to work even harder: we have to	 * find what the Var refers to, and pass that to get_expr_result_type.	 * That task is handled by expandRecordVariable().	 */	if (IsA(expr, Var) &&		((Var *) expr)->vartype == RECORDOID)		tupleDesc = expandRecordVariable(pstate, (Var *) expr, 0);	else if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)		tupleDesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(exprType(expr),															   exprTypmod(expr)));	Assert(tupleDesc);	/* Generate a list of references to the individual fields */	numAttrs = tupleDesc->natts;	for (i = 0; i < numAttrs; i++)	{		Form_pg_attribute att = tupleDesc->attrs[i];		Node	   *fieldnode;		TargetEntry *te;		if (att->attisdropped)			continue;		/*		 * If we got a whole-row Var from the rowtype reference, we can expand		 * the fields as simple Vars.  Otherwise we must generate multiple		 * copies of the rowtype reference and do FieldSelects.		 */		if (IsA(expr, Var) &&			((Var *) expr)->varattno == InvalidAttrNumber)		{			Var		   *var = (Var *) expr;			fieldnode = (Node *) makeVar(var->varno,										 i + 1,										 att->atttypid,										 att->atttypmod,										 var->varlevelsup);		}		else		{			FieldSelect *fselect = makeNode(FieldSelect);			fselect->arg = (Expr *) copyObject(expr);			fselect->fieldnum = i + 1;			fselect->resulttype = att->atttypid;			fselect->resulttypmod = att->atttypmod;			fieldnode = (Node *) fselect;		}		te = makeTargetEntry((Expr *) fieldnode,							 (AttrNumber) pstate->p_next_resno++,							 pstrdup(NameStr(att->attname)),							 false);		te_list = lappend(te_list, te);	}	return te_list;}/* * expandRecordVariable *		Get the tuple descriptor for a Var of type RECORD, if possible. * * Since no actual table or view column is allowed to have type RECORD, such * a Var must refer to a JOIN or FUNCTION RTE or to a subquery output.	We * drill down to find the ultimate defining expression and attempt to infer * the tupdesc from it.  We ereport if we can't determine the tupdesc. * * levelsup is an extra offset to interpret the Var's varlevelsup correctly. */TupleDescexpandRecordVariable(ParseState *pstate, Var *var, int levelsup){	TupleDesc	tupleDesc;	int			netlevelsup;	RangeTblEntry *rte;	AttrNumber	attnum;	Node	   *expr;	/* Check my caller didn't mess up */	Assert(IsA(var, Var));	Assert(var->vartype == RECORDOID);	netlevelsup = var->varlevelsup + levelsup;	rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);	attnum = var->varattno;	if (attnum == InvalidAttrNumber)	{		/* Whole-row reference to an RTE, so expand the known fields */		List	   *names,				   *vars;		ListCell   *lname,				   *lvar;		int			i;		expandRTE(rte, var->varno, 0, false,				  &names, &vars);		tupleDesc = CreateTemplateTupleDesc(list_length(vars), false);		i = 1;		forboth(lname, names, lvar, vars)		{			char	   *label = strVal(lfirst(lname));			Node	   *varnode = (Node *) lfirst(lvar);			TupleDescInitEntry(tupleDesc, i,							   label,							   exprType(varnode),							   exprTypmod(varnode),							   0);			i++;		}		Assert(lname == NULL && lvar == NULL);	/* lists same length? */		return tupleDesc;	}	expr = (Node *) var;		/* default if we can't drill down */	switch (rte->rtekind)	{		case RTE_RELATION:		case RTE_SPECIAL:			/*			 * This case should not occur: a column of a table shouldn't have			 * type RECORD.  Fall through and fail (most likely) at the			 * bottom.			 */			break;		case RTE_SUBQUERY:			{				/* Subselect-in-FROM: examine sub-select's output expr */				TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,													attnum);				if (ste == NULL || ste->resjunk)					elog(ERROR, "subquery %s does not have attribute %d",						 rte->eref->aliasname, attnum);				expr = (Node *) ste->expr;				if (IsA(expr, Var))				{					/*					 * Recurse into the sub-select to see what its Var refers					 * to.	We have to build an additional level of ParseState					 * to keep in step with varlevelsup in the subselect.					 */					ParseState	mypstate;					MemSet(&mypstate, 0, sizeof(mypstate));					mypstate.parentParseState = pstate;					mypstate.p_rtable = rte->subquery->rtable;					/* don't bother filling the rest of the fake pstate */					return expandRecordVariable(&mypstate, (Var *) expr, 0);				}				/* else fall through to inspect the expression */			}			break;		case RTE_JOIN:			/* Join RTE --- recursively inspect the alias variable */			Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));			expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1);			if (IsA(expr, Var))				return expandRecordVariable(pstate, (Var *) expr, netlevelsup);			/* else fall through to inspect the expression */			break;		case RTE_FUNCTION:			/*			 * We couldn't get here unless a function is declared with one of			 * its result columns as RECORD, which is not allowed.			 */			break;	}	/*	 * We now have an expression we can't expand any more, so see if	 * get_expr_result_type() can do anything with it.	If not, pass to	 * lookup_rowtype_tupdesc() which will probably fail, but will give an	 * appropriate error message while failing.	 */	if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)		tupleDesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(exprType(expr),															   exprTypmod(expr)));	return tupleDesc;}/* * FigureColname - *	  if the name of the resulting column is not specified in the target *	  list, we have to guess a suitable name.  The SQL spec provides some *	  guidance, but not much... * * Note that the argument is the *untransformed* parse tree for the target * item.  This is a shade easier to work with than the transformed tree. */char *FigureColname(Node *node){	char	   *name = NULL;	FigureColnameInternal(node, &name);	if (name != NULL)		return name;	/* default result if we can't guess anything */	return "?column?";}static intFigureColnameInternal(Node *node, char **name){	int			strength = 0;	if (node == NULL)		return strength;	switch (nodeTag(node))	{		case T_ColumnRef:			{				char	   *fname = NULL;				ListCell   *l;				/* find last field name, if any, ignoring "*" */				foreach(l, ((ColumnRef *) node)->fields)				{					Node	   *i = lfirst(l);					if (strcmp(strVal(i), "*") != 0)						fname = strVal(i);				}				if (fname)				{					*name = fname;					return 2;				}			}			break;		case T_A_Indirection:			{				A_Indirection *ind = (A_Indirection *) node;				char	   *fname = NULL;				ListCell   *l;				/* find last field name, if any, ignoring "*" */				foreach(l, ind->indirection)				{					Node	   *i = lfirst(l);					if (IsA(i, String) &&						strcmp(strVal(i), "*") != 0)						fname = strVal(i);				}				if (fname)				{					*name = fname;					return 2;				}				return FigureColnameInternal(ind->arg, name);			}			break;		case T_FuncCall:			*name = strVal(llast(((FuncCall *) node)->funcname));			return 2;		case T_A_Expr:			/* make nullif() act like a regular function */			if (((A_Expr *) node)->kind == AEXPR_NULLIF)			{				*name = "nullif";				return 2;			}			break;		case T_A_Const:			if (((A_Const *) node)->typename != NULL)			{				*name = strVal(llast(((A_Const *) node)->typename->names));				return 1;			}			break;		case T_TypeCast:			strength = FigureColnameInternal(((TypeCast *) node)->arg,											 name);			if (strength <= 1)			{				if (((TypeCast *) node)->typename != NULL)				{					*name = strVal(llast(((TypeCast *) node)->typename->names));					return 1;				}			}			break;		case T_CaseExpr:			strength = FigureColnameInternal((Node *) ((CaseExpr *) node)->defresult,											 name);			if (strength <= 1)			{				*name = "case";				return 1;			}			break;		case T_ArrayExpr:			/* make ARRAY[] act like a function */			*name = "array";			return 2;		case T_RowExpr:			/* make ROW() act like a function */			*name = "row";			return 2;		case T_CoalesceExpr:			/* make coalesce() act like a regular function */			*name = "coalesce";			return 2;		case T_MinMaxExpr:			/* make greatest/least act like a regular function */			switch (((MinMaxExpr *) node)->op)			{				case IS_GREATEST:					*name = "greatest";					return 2;				case IS_LEAST:					*name = "least";					return 2;			}			break;		default:			break;	}	return strength;}

⌨️ 快捷键说明

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