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

📄 parse_func.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
 *		is returned to the caller, reflecting the structure of the *		inheritance tree above the supplied arguments. * *		The order of this vector is as follows:  all superclasses of the *		rightmost complex class are explored first.  The exploration *		continues from right to left.  This policy means that we favor *		keeping the leftmost argument type as low in the inheritance tree *		as possible.  This is intentional; it is exactly what we need to *		do for method dispatch.  The last type array we return is all *		zeroes.  This will match any functions for which return types are *		not defined.  There are lots of these (mostly builtins) in the *		catalogs. */static Oid **argtype_inherit(int nargs, Oid *oid_array){	Oid			relid;	int			i;	InhPaths	arginh[MAXFARGS];	for (i = 0; i < MAXFARGS; i++)	{		if (i < nargs)		{			arginh[i].self = oid_array[i];			if ((relid = typeidTypeRelid(oid_array[i])) != InvalidOid)				arginh[i].nsupers = find_inheritors(relid, &(arginh[i].supervec));			else			{				arginh[i].nsupers = 0;				arginh[i].supervec = (Oid *) NULL;			}		}		else		{			arginh[i].self = InvalidOid;			arginh[i].nsupers = 0;			arginh[i].supervec = (Oid *) NULL;		}	}	/* return an ordered cross-product of the classes involved */	return gen_cross_product(arginh, nargs);}static intfind_inheritors(Oid relid, Oid **supervec){	Oid		   *relidvec;	Relation	inhrel;	HeapScanDesc inhscan;	ScanKeyData skey;	HeapTuple	inhtup;	TupleDesc	inhtupdesc;	int			nvisited;	SuperQE    *qentry,			   *vnode;	Dllist	   *visited,			   *queue;	Dlelem	   *qe,			   *elt;	Relation	rd;	Datum		d;	bool		newrelid;	char		isNull;	nvisited = 0;	queue = DLNewList();	visited = DLNewList();	inhrel = heap_openr(InheritsRelationName);	inhtupdesc = RelationGetDescr(inhrel);	/*	 * Use queue to do a breadth-first traversal of the inheritance graph	 * from the relid supplied up to the root.	 */	do	{		ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrel,							   F_OIDEQ,							   ObjectIdGetDatum(relid));		inhscan = heap_beginscan(inhrel, 0, SnapshotNow, 1, &skey);		while (HeapTupleIsValid(inhtup = heap_getnext(inhscan, 0)))		{			qentry = (SuperQE *) palloc(sizeof(SuperQE));			d = fastgetattr(inhtup, Anum_pg_inherits_inhparent,							inhtupdesc, &isNull);			qentry->sqe_relid = DatumGetObjectId(d);			/* put this one on the queue */			DLAddTail(queue, DLNewElem(qentry));		}		heap_endscan(inhscan);		/* pull next unvisited relid off the queue */		do		{			qe = DLRemHead(queue);			qentry = qe ? (SuperQE *) DLE_VAL(qe) : NULL;			if (qentry == (SuperQE *) NULL)				break;			relid = qentry->sqe_relid;			newrelid = true;			for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt))			{				vnode = (SuperQE *) DLE_VAL(elt);				if (vnode && (qentry->sqe_relid == vnode->sqe_relid))				{					newrelid = false;					break;				}			}		} while (!newrelid);		if (qentry != (SuperQE *) NULL)		{			/* save the type id, rather than the relation id */			if ((rd = heap_open(qentry->sqe_relid)) == (Relation) NULL)				elog(ERROR, "Relid %u does not exist", qentry->sqe_relid);			qentry->sqe_relid = typeTypeId(typenameType(RelationGetRelationName(rd)->data));			heap_close(rd);			DLAddTail(visited, qe);			nvisited++;		}	} while (qentry != (SuperQE *) NULL);	heap_close(inhrel);	if (nvisited > 0)	{		relidvec = (Oid *) palloc(nvisited * sizeof(Oid));		*supervec = relidvec;		for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt))		{			vnode = (SuperQE *) DLE_VAL(elt);			*relidvec++ = vnode->sqe_relid;		}	}	else		*supervec = (Oid *) NULL;	return nvisited;}static Oid **gen_cross_product(InhPaths *arginh, int nargs){	int			nanswers;	Oid		  **result,			  **iter;	Oid		   *oneres;	int			i,				j;	int			cur[MAXFARGS];	nanswers = 1;	for (i = 0; i < nargs; i++)	{		nanswers *= (arginh[i].nsupers + 2);		cur[i] = 0;	}	iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers);	/* compute the cross product from right to left */	for (;;)	{		oneres = (Oid *) palloc(MAXFARGS * sizeof(Oid));		MemSet(oneres, 0, MAXFARGS * sizeof(Oid));		for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--)			continue;		/* if we're done, terminate with NULL pointer */		if (i < 0)		{			*iter = NULL;			return result;		}		/* no, increment this column and zero the ones after it */		cur[i] = cur[i] + 1;		for (j = nargs - 1; j > i; j--)			cur[j] = 0;		for (i = 0; i < nargs; i++)		{			if (cur[i] == 0)				oneres[i] = arginh[i].self;			else if (cur[i] > arginh[i].nsupers)				oneres[i] = 0;	/* wild card */			else				oneres[i] = arginh[i].supervec[cur[i] - 1];		}		*iter++ = oneres;	}}/* make_arguments() * Given the number and types of arguments to a function, and the *	actual arguments and argument types, do the necessary typecasting. * * There are two ways an input typeid can differ from a function typeid: *	1) the input type inherits the function type, so no typecasting required *	2) the input type can be typecast into the function type * Right now, we only typecast unknowns, and that is all we check for. * * func_get_detail() now can find coersions for function arguments which *	will make this function executable. So, we need to recover these *	results here too. * - thomas 1998-03-25 */static voidmake_arguments(ParseState *pstate,			   int nargs,			   List *fargs,			   Oid *input_typeids,			   Oid *function_typeids){	List	   *current_fargs;	int			i;	for (i = 0, current_fargs = fargs;		 i < nargs;		 i++, current_fargs = lnext(current_fargs))	{		/*		 * unspecified type for string constant? then use heuristics for		 * conversion...		 */		if (input_typeids[i] == UNKNOWNOID && function_typeids[i] != InvalidOid)		{			lfirst(current_fargs) = parser_typecast2(lfirst(current_fargs),													 input_typeids[i],										 typeidType(function_typeids[i]),													 -1);		}		/* types don't match? then force coersion using a function call... */		else if (input_typeids[i] != function_typeids[i])		{			lfirst(current_fargs) = coerce_type(pstate,												lfirst(current_fargs),												input_typeids[i],												function_typeids[i], -1);		}	}}/* ** setup_tlist **		Build a tlist that says which attribute to project to. **		This routine is called by ParseFuncOrColumn() to set up a target list **		on a tuple parameter or return value.  Due to a bug in 4.0, **		it's not possible to refer to system attributes in this case. */static List *setup_tlist(char *attname, Oid relid){	TargetEntry *tle;	Resdom	   *resnode;	Var		   *varnode;	Oid			typeid;	int32		type_mod;	int			attno;	attno = get_attnum(relid, attname);	if (attno < 0)		elog(ERROR, "Cannot reference attribute '%s'"			 " of tuple params/return values for functions", attname);	typeid = get_atttype(relid, attno);	type_mod = get_atttypmod(relid, attno);	resnode = makeResdom(1,						 typeid,						 type_mod,						 get_attname(relid, attno),						 0,						 InvalidOid,						 false);	varnode = makeVar(-1, attno, typeid, type_mod, 0, -1, attno);	tle = makeTargetEntry(resnode, (Node *) varnode);	return lcons(tle, NIL);}/* ** setup_base_tlist **		Build a tlist that extracts a base type from the tuple **		returned by the executor. */static List *setup_base_tlist(Oid typeid){	TargetEntry *tle;	Resdom	   *resnode;	Var		   *varnode;	resnode = makeResdom(1,						 typeid,						 -1,						 "<noname>",						 0,						 InvalidOid,						 false);	varnode = makeVar(-1, 1, typeid, -1, 0, -1, 1);	tle = makeTargetEntry(resnode, (Node *) varnode);	return lcons(tle, NIL);}/* * ParseComplexProjection - *	  handles function calls with a single argument that is of complex type. *	  This routine returns NULL if it can't handle the projection (eg. sets). */static Node *ParseComplexProjection(ParseState *pstate,					   char *funcname,					   Node *first_arg,					   bool *attisset){	Oid			argtype;	Oid			argrelid;	Relation	rd;	Oid			relid;	int			attnum;	switch (nodeTag(first_arg))	{		case T_Iter:			{				Func	   *func;				Iter	   *iter;				iter = (Iter *) first_arg;				func = (Func *) ((Expr *) iter->iterexpr)->oper;				argtype = funcid_get_rettype(func->funcid);				argrelid = typeidTypeRelid(argtype);				if (argrelid &&					((attnum = get_attnum(argrelid, funcname))					 != InvalidAttrNumber))				{					/*					 * the argument is a function returning a tuple, so					 * funcname may be a projection					 */					/* add a tlist to the func node and return the Iter */					rd = heap_openr(typeidTypeName(argtype));					if (RelationIsValid(rd))					{						relid = RelationGetRelid(rd);						heap_close(rd);					}					if (RelationIsValid(rd))					{						func->func_tlist = setup_tlist(funcname, argrelid);						iter->itertype = attnumTypeId(rd, attnum);						return (Node *) iter;					}					else					{						elog(ERROR, "Function '%s' has bad return type %d",							 funcname, argtype);					}				}				else				{					/* drop through */					;				}				break;			}		case T_Var:			{				/*				 * The argument is a set, so this is either a projection				 * or a function call on this set.				 */				*attisset = true;				break;			}		case T_Expr:			{				Expr	   *expr = (Expr *) first_arg;				Func	   *funcnode;				if (expr->opType != FUNC_EXPR)					break;				funcnode = (Func *) expr->oper;				argtype = funcid_get_rettype(funcnode->funcid);				argrelid = typeidTypeRelid(argtype);				/*				 * the argument is a function returning a tuple, so				 * funcname may be a projection				 */				if (argrelid &&					(attnum = get_attnum(argrelid, funcname))					!= InvalidAttrNumber)				{					/* add a tlist to the func node */					rd = heap_openr(typeidTypeName(argtype));					if (RelationIsValid(rd))					{						relid = RelationGetRelid(rd);						heap_close(rd);					}					if (RelationIsValid(rd))					{						Expr	   *newexpr;						funcnode->func_tlist = setup_tlist(funcname, argrelid);						funcnode->functype = attnumTypeId(rd, attnum);						newexpr = makeNode(Expr);						newexpr->typeOid = funcnode->functype;						newexpr->opType = FUNC_EXPR;						newexpr->oper = (Node *) funcnode;						newexpr->args = expr->args;						return (Node *) newexpr;					}				}				break;			}		case T_Param:			{				Param	   *param = (Param *) first_arg;				/*				 * If the Param is a complex type, this could be a				 * projection				 */				rd = heap_openr(typeidTypeName(param->paramtype));				if (RelationIsValid(rd))				{					relid = RelationGetRelid(rd);					heap_close(rd);					if ((attnum = get_attnum(relid, funcname))						!= InvalidAttrNumber)					{						param->paramtype = attnumTypeId(rd, attnum);						param->param_tlist = setup_tlist(funcname, relid);						return (Node *) param;					}				}				break;			}		default:			break;	}	return NULL;}/* * Error message when function lookup fails that gives details of the * argument types */voidfunc_error(char *caller, char *funcname, int nargs, Oid *argtypes, char *msg){	char		p[(NAMEDATALEN + 2) * MAXFMGRARGS],			   *ptr;	int			i;	ptr = p;	*ptr = '\0';	for (i = 0; i < nargs; i++)	{		if (i)		{			*ptr++ = ',';			*ptr++ = ' ';		}		if (argtypes[i] != 0)		{			strcpy(ptr, typeidTypeName(argtypes[i]));			*(ptr + NAMEDATALEN) = '\0';		}		else			strcpy(ptr, "opaque");		ptr += strlen(ptr);	}	if (caller == NULL)	{		elog(ERROR, "Function '%s(%s)' does not exist%s%s",			 funcname, p, ((msg != NULL) ? "\n\t" : ""), ((msg != NULL) ? msg : ""));	}	else	{		elog(ERROR, "%s: function '%s(%s)' does not exist%s%s",			 caller, funcname, p, ((msg != NULL) ? "\n\t" : ""), ((msg != NULL) ? msg : ""));	}}

⌨️ 快捷键说明

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