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

📄 nodefunctionscan.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
字号:
/*------------------------------------------------------------------------- * * nodeFunctionscan.c *	  Support routines for scanning RangeFunctions (functions in rangetable). * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.35 2005/10/15 02:49:17 momjian Exp $ * *------------------------------------------------------------------------- *//* * INTERFACE ROUTINES *		ExecFunctionScan		scans a function. *		ExecFunctionNext		retrieve next tuple in sequential order. *		ExecInitFunctionScan	creates and initializes a functionscan node. *		ExecEndFunctionScan		releases any storage allocated. *		ExecFunctionReScan		rescans the function */#include "postgres.h"#include "executor/nodeFunctionscan.h"#include "funcapi.h"#include "parser/parsetree.h"#include "utils/builtins.h"static TupleTableSlot *FunctionNext(FunctionScanState *node);static void tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc);/* ---------------------------------------------------------------- *						Scan Support * ---------------------------------------------------------------- *//* ---------------------------------------------------------------- *		FunctionNext * *		This is a workhorse for ExecFunctionScan * ---------------------------------------------------------------- */static TupleTableSlot *FunctionNext(FunctionScanState *node){	TupleTableSlot *slot;	EState	   *estate;	ScanDirection direction;	Tuplestorestate *tuplestorestate;	bool		should_free;	HeapTuple	heapTuple;	/*	 * get information from the estate and scan state	 */	estate = node->ss.ps.state;	direction = estate->es_direction;	tuplestorestate = node->tuplestorestate;	/*	 * If first time through, read all tuples from function and put them in a	 * tuplestore. Subsequent calls just fetch tuples from tuplestore.	 */	if (tuplestorestate == NULL)	{		ExprContext *econtext = node->ss.ps.ps_ExprContext;		TupleDesc	funcTupdesc;		node->tuplestorestate = tuplestorestate =			ExecMakeTableFunctionResult(node->funcexpr,										econtext,										node->tupdesc,										&funcTupdesc);		/*		 * If function provided a tupdesc, cross-check it.	We only really		 * need to do this for functions returning RECORD, but might as well		 * do it always.		 */		if (funcTupdesc)			tupledesc_match(node->tupdesc, funcTupdesc);	}	/*	 * Get the next tuple from tuplestore. Return NULL if no more tuples.	 */	heapTuple = tuplestore_getheaptuple(tuplestorestate,										ScanDirectionIsForward(direction),										&should_free);	slot = node->ss.ss_ScanTupleSlot;	if (heapTuple)		return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);	else		return ExecClearTuple(slot);}/* ---------------------------------------------------------------- *		ExecFunctionScan(node) * *		Scans the function sequentially and returns the next qualifying *		tuple. *		It calls the ExecScan() routine and passes it the access method *		which retrieves tuples sequentially. * */TupleTableSlot *ExecFunctionScan(FunctionScanState *node){	/*	 * use FunctionNext as access method	 */	return ExecScan(&node->ss, (ExecScanAccessMtd) FunctionNext);}/* ---------------------------------------------------------------- *		ExecInitFunctionScan * ---------------------------------------------------------------- */FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate){	FunctionScanState *scanstate;	RangeTblEntry *rte;	Oid			funcrettype;	TypeFuncClass functypclass;	TupleDesc	tupdesc = NULL;	/*	 * FunctionScan should not have any children.	 */	Assert(outerPlan(node) == NULL);	Assert(innerPlan(node) == NULL);	/*	 * create new ScanState for node	 */	scanstate = makeNode(FunctionScanState);	scanstate->ss.ps.plan = (Plan *) node;	scanstate->ss.ps.state = estate;	/*	 * Miscellaneous initialization	 *	 * create expression context for node	 */	ExecAssignExprContext(estate, &scanstate->ss.ps);#define FUNCTIONSCAN_NSLOTS 2	/*	 * tuple table initialization	 */	ExecInitResultTupleSlot(estate, &scanstate->ss.ps);	ExecInitScanTupleSlot(estate, &scanstate->ss);	/*	 * initialize child expressions	 */	scanstate->ss.ps.targetlist = (List *)		ExecInitExpr((Expr *) node->scan.plan.targetlist,					 (PlanState *) scanstate);	scanstate->ss.ps.qual = (List *)		ExecInitExpr((Expr *) node->scan.plan.qual,					 (PlanState *) scanstate);	/*	 * get info about function	 */	rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);	Assert(rte->rtekind == RTE_FUNCTION);	/*	 * Now determine if the function returns a simple or composite type, and	 * build an appropriate tupdesc.	 */	functypclass = get_expr_result_type(rte->funcexpr,										&funcrettype,										&tupdesc);	if (functypclass == TYPEFUNC_COMPOSITE)	{		/* Composite data type, e.g. a table's row type */		Assert(tupdesc);		/* Must copy it out of typcache for safety */		tupdesc = CreateTupleDescCopy(tupdesc);	}	else if (functypclass == TYPEFUNC_SCALAR)	{		/* Base data type, i.e. scalar */		char	   *attname = strVal(linitial(rte->eref->colnames));		tupdesc = CreateTemplateTupleDesc(1, false);		TupleDescInitEntry(tupdesc,						   (AttrNumber) 1,						   attname,						   funcrettype,						   -1,						   0);	}	else if (functypclass == TYPEFUNC_RECORD)	{		tupdesc = BuildDescForRelation(rte->coldeflist);	}	else	{		/* crummy error message, but parser should have caught this */		elog(ERROR, "function in FROM has unsupported return type");	}	/*	 * For RECORD results, make sure a typmod has been assigned.  (The	 * function should do this for itself, but let's cover things in case it	 * doesn't.)	 */	BlessTupleDesc(tupdesc);	scanstate->tupdesc = tupdesc;	ExecAssignScanType(&scanstate->ss, tupdesc, false);	/*	 * Other node-specific setup	 */	scanstate->tuplestorestate = NULL;	scanstate->funcexpr = ExecInitExpr((Expr *) rte->funcexpr,									   (PlanState *) scanstate);	scanstate->ss.ps.ps_TupFromTlist = false;	/*	 * Initialize result tuple type and projection info.	 */	ExecAssignResultTypeFromTL(&scanstate->ss.ps);	ExecAssignScanProjectionInfo(&scanstate->ss);	return scanstate;}intExecCountSlotsFunctionScan(FunctionScan *node){	return ExecCountSlotsNode(outerPlan(node)) +		ExecCountSlotsNode(innerPlan(node)) +		FUNCTIONSCAN_NSLOTS;}/* ---------------------------------------------------------------- *		ExecEndFunctionScan * *		frees any storage allocated through C routines. * ---------------------------------------------------------------- */voidExecEndFunctionScan(FunctionScanState *node){	/*	 * Free the exprcontext	 */	ExecFreeExprContext(&node->ss.ps);	/*	 * clean out the tuple table	 */	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);	ExecClearTuple(node->ss.ss_ScanTupleSlot);	/*	 * Release tuplestore resources	 */	if (node->tuplestorestate != NULL)		tuplestore_end(node->tuplestorestate);	node->tuplestorestate = NULL;}/* ---------------------------------------------------------------- *		ExecFunctionMarkPos * *		Calls tuplestore to save the current position in the stored file. * ---------------------------------------------------------------- */voidExecFunctionMarkPos(FunctionScanState *node){	/*	 * if we haven't materialized yet, just return.	 */	if (!node->tuplestorestate)		return;	tuplestore_markpos(node->tuplestorestate);}/* ---------------------------------------------------------------- *		ExecFunctionRestrPos * *		Calls tuplestore to restore the last saved file position. * ---------------------------------------------------------------- */voidExecFunctionRestrPos(FunctionScanState *node){	/*	 * if we haven't materialized yet, just return.	 */	if (!node->tuplestorestate)		return;	tuplestore_restorepos(node->tuplestorestate);}/* ---------------------------------------------------------------- *		ExecFunctionReScan * *		Rescans the relation. * ---------------------------------------------------------------- */voidExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt){	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);	/*	 * If we haven't materialized yet, just return.	 */	if (!node->tuplestorestate)		return;	/*	 * Here we have a choice whether to drop the tuplestore (and recompute the	 * function outputs) or just rescan it.  This should depend on whether the	 * function expression contains parameters and/or is marked volatile.	 * FIXME soon.	 */	if (node->ss.ps.chgParam != NULL)	{		tuplestore_end(node->tuplestorestate);		node->tuplestorestate = NULL;	}	else		tuplestore_rescan(node->tuplestorestate);}/* * Check that function result tuple type (src_tupdesc) matches or can * be considered to match what the query expects (dst_tupdesc). If * they don't match, ereport. * * We really only care about number of attributes and data type. * Also, we can ignore type mismatch on columns that are dropped in the * destination type, so long as the physical storage matches.  This is * helpful in some cases involving out-of-date cached plans. */static voidtupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc){	int			i;	if (dst_tupdesc->natts != src_tupdesc->natts)		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),				 errmsg("function return row and query-specified return row do not match"),				 errdetail("Returned row contains %d attributes, but query expects %d.",						   src_tupdesc->natts, dst_tupdesc->natts)));	for (i = 0; i < dst_tupdesc->natts; i++)	{		Form_pg_attribute dattr = dst_tupdesc->attrs[i];		Form_pg_attribute sattr = src_tupdesc->attrs[i];		if (dattr->atttypid == sattr->atttypid)			continue;			/* no worries */		if (!dattr->attisdropped)			ereport(ERROR,					(errcode(ERRCODE_DATATYPE_MISMATCH),					 errmsg("function return row and query-specified return row do not match"),					 errdetail("Returned type %s at ordinal position %d, but query expects %s.",							   format_type_be(sattr->atttypid),							   i + 1,							   format_type_be(dattr->atttypid))));		if (dattr->attlen != sattr->attlen ||			dattr->attalign != sattr->attalign)			ereport(ERROR,					(errcode(ERRCODE_DATATYPE_MISMATCH),					 errmsg("function return row and query-specified return row do not match"),					 errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",							   i + 1)));	}}

⌨️ 快捷键说明

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