tuplestore.c

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

C
927
字号
 * Backward scan is only allowed if randomAccess was set true or * EXEC_FLAG_BACKWARD was specified to tuplestore_set_eflags(). */static void *tuplestore_gettuple(Tuplestorestate *state, bool forward,					bool *should_free){	unsigned int tuplen;	void	   *tup;	Assert(forward || (state->eflags & EXEC_FLAG_BACKWARD));	switch (state->status)	{		case TSS_INMEM:			*should_free = false;			if (forward)			{				if (state->current < state->memtupcount)					return state->memtuples[state->current++];				state->eof_reached = true;				return NULL;			}			else			{				if (state->current <= 0)					return NULL;				/*				 * if all tuples are fetched already then we return last				 * tuple, else - tuple before last returned.				 */				if (state->eof_reached)					state->eof_reached = false;				else				{					state->current--;	/* last returned tuple */					if (state->current <= 0)						return NULL;				}				return state->memtuples[state->current - 1];			}			break;		case TSS_WRITEFILE:			/* Skip state change if we'll just return NULL */			if (state->eof_reached && forward)				return NULL;			/*			 * Switch from writing to reading.			 */			BufFileTell(state->myfile,						&state->writepos_file, &state->writepos_offset);			if (!state->eof_reached)				if (BufFileSeek(state->myfile,								state->readpos_file, state->readpos_offset,								SEEK_SET) != 0)					elog(ERROR, "seek failed");			state->status = TSS_READFILE;			/* FALL THRU into READFILE case */		case TSS_READFILE:			*should_free = true;			if (forward)			{				if ((tuplen = getlen(state, true)) != 0)				{					tup = READTUP(state, tuplen);					return tup;				}				else				{					state->eof_reached = true;					return NULL;				}			}			/*			 * Backward.			 *			 * if all tuples are fetched already then we return last tuple,			 * else - tuple before last returned.			 *			 * Back up to fetch previously-returned tuple's ending length			 * word. If seek fails, assume we are at start of file.			 */			if (BufFileSeek(state->myfile, 0, -(long) sizeof(unsigned int),							SEEK_CUR) != 0)				return NULL;			tuplen = getlen(state, false);			if (state->eof_reached)			{				state->eof_reached = false;				/* We will return the tuple returned before returning NULL */			}			else			{				/*				 * Back up to get ending length word of tuple before it.				 */				if (BufFileSeek(state->myfile, 0,								-(long) (tuplen + 2 * sizeof(unsigned int)),								SEEK_CUR) != 0)				{					/*					 * If that fails, presumably the prev tuple is the first					 * in the file.  Back up so that it becomes next to read					 * in forward direction (not obviously right, but that is					 * what in-memory case does).					 */					if (BufFileSeek(state->myfile, 0,									-(long) (tuplen + sizeof(unsigned int)),									SEEK_CUR) != 0)						elog(ERROR, "bogus tuple length in backward scan");					return NULL;				}				tuplen = getlen(state, false);			}			/*			 * Now we have the length of the prior tuple, back up and read it.			 * Note: READTUP expects we are positioned after the initial			 * length word of the tuple, so back up to that point.			 */			if (BufFileSeek(state->myfile, 0,							-(long) tuplen,							SEEK_CUR) != 0)				elog(ERROR, "bogus tuple length in backward scan");			tup = READTUP(state, tuplen);			return tup;		default:			elog(ERROR, "invalid tuplestore state");			return NULL;		/* keep compiler quiet */	}}/* * tuplestore_gettupleslot - exported function to fetch a MinimalTuple * * If successful, put tuple in slot and return TRUE; else, clear the slot * and return FALSE. */booltuplestore_gettupleslot(Tuplestorestate *state, bool forward,						TupleTableSlot *slot){	MinimalTuple tuple;	bool		should_free;	tuple = (MinimalTuple) tuplestore_gettuple(state, forward, &should_free);	if (tuple)	{		ExecStoreMinimalTuple(tuple, slot, should_free);		return true;	}	else	{		ExecClearTuple(slot);		return false;	}}/* * tuplestore_advance - exported function to adjust position without fetching * * We could optimize this case to avoid palloc/pfree overhead, but for the * moment it doesn't seem worthwhile. */booltuplestore_advance(Tuplestorestate *state, bool forward){	void	   *tuple;	bool		should_free;	tuple = tuplestore_gettuple(state, forward, &should_free);	if (tuple)	{		if (should_free)			pfree(tuple);		return true;	}	else	{		return false;	}}/* * dumptuples - remove tuples from memory and write to tape * * As a side effect, we must set readpos and markpos to the value * corresponding to "current"; otherwise, a dump would lose the current read * position. */static voiddumptuples(Tuplestorestate *state){	int			i;	for (i = 0;; i++)	{		if (i == state->current)			BufFileTell(state->myfile,						&state->readpos_file, &state->readpos_offset);		if (i == state->markpos_current)			BufFileTell(state->myfile,						&state->markpos_file, &state->markpos_offset);		if (i >= state->memtupcount)			break;		WRITETUP(state, state->memtuples[i]);	}	state->memtupcount = 0;}/* * tuplestore_rescan		- rewind and replay the scan */voidtuplestore_rescan(Tuplestorestate *state){	Assert(state->eflags & EXEC_FLAG_REWIND);	switch (state->status)	{		case TSS_INMEM:			state->eof_reached = false;			state->current = 0;			break;		case TSS_WRITEFILE:			state->eof_reached = false;			state->readpos_file = 0;			state->readpos_offset = 0L;			break;		case TSS_READFILE:			state->eof_reached = false;			if (BufFileSeek(state->myfile, 0, 0L, SEEK_SET) != 0)				elog(ERROR, "seek to start failed");			break;		default:			elog(ERROR, "invalid tuplestore state");			break;	}}/* * tuplestore_markpos	- saves current position in the tuple sequence */voidtuplestore_markpos(Tuplestorestate *state){	Assert(state->eflags & EXEC_FLAG_MARK);	switch (state->status)	{		case TSS_INMEM:			state->markpos_current = state->current;			/*			 * We can truncate the tuplestore if neither backward scan nor			 * rewind capability are required by the caller.  There will never			 * be a need to back up past the mark point.			 *			 * Note: you might think we could remove all the tuples before			 * "current", since that one is the next to be returned.  However,			 * since tuplestore_gettuple returns a direct pointer to our			 * internal copy of the tuple, it's likely that the caller has			 * still got the tuple just before "current" referenced in a slot.			 * Don't free it yet.			 */			if (!(state->eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_REWIND)))				tuplestore_trim(state, 1);			break;		case TSS_WRITEFILE:			if (state->eof_reached)			{				/* Need to record the implicit read position */				BufFileTell(state->myfile,							&state->markpos_file,							&state->markpos_offset);			}			else			{				state->markpos_file = state->readpos_file;				state->markpos_offset = state->readpos_offset;			}			break;		case TSS_READFILE:			BufFileTell(state->myfile,						&state->markpos_file,						&state->markpos_offset);			break;		default:			elog(ERROR, "invalid tuplestore state");			break;	}}/* * tuplestore_restorepos - restores current position in tuple sequence to *						  last saved position */voidtuplestore_restorepos(Tuplestorestate *state){	Assert(state->eflags & EXEC_FLAG_MARK);	switch (state->status)	{		case TSS_INMEM:			state->eof_reached = false;			state->current = state->markpos_current;			break;		case TSS_WRITEFILE:			state->eof_reached = false;			state->readpos_file = state->markpos_file;			state->readpos_offset = state->markpos_offset;			break;		case TSS_READFILE:			state->eof_reached = false;			if (BufFileSeek(state->myfile,							state->markpos_file,							state->markpos_offset,							SEEK_SET) != 0)				elog(ERROR, "tuplestore_restorepos failed");			break;		default:			elog(ERROR, "invalid tuplestore state");			break;	}}/* * tuplestore_trim	- remove all but ntuples tuples before current */static voidtuplestore_trim(Tuplestorestate *state, int ntuples){	int			nremove;	int			i;	/*	 * We don't bother trimming temp files since it usually would mean more	 * work than just letting them sit in kernel buffers until they age out.	 */	if (state->status != TSS_INMEM)		return;	nremove = state->current - ntuples;	if (nremove <= 0)		return;					/* nothing to do */	Assert(nremove <= state->memtupcount);	/* Release no-longer-needed tuples */	for (i = 0; i < nremove; i++)	{		FREEMEM(state, GetMemoryChunkSpace(state->memtuples[i]));		pfree(state->memtuples[i]);	}	/*	 * Slide the array down and readjust pointers.	This may look pretty	 * stupid, but we expect that there will usually not be very many	 * tuple-pointers to move, so this isn't that expensive; and it keeps a	 * lot of other logic simple.	 *	 * In fact, in the current usage for merge joins, it's demonstrable that	 * there will always be exactly one non-removed tuple; so optimize that	 * case.	 */	if (nremove + 1 == state->memtupcount)		state->memtuples[0] = state->memtuples[nremove];	else		memmove(state->memtuples, state->memtuples + nremove,				(state->memtupcount - nremove) * sizeof(void *));	state->memtupcount -= nremove;	state->current -= nremove;	state->markpos_current -= nremove;}/* * Tape interface routines */static unsigned intgetlen(Tuplestorestate *state, bool eofOK){	unsigned int len;	size_t		nbytes;	nbytes = BufFileRead(state->myfile, (void *) &len, sizeof(len));	if (nbytes == sizeof(len))		return len;	if (nbytes != 0)		elog(ERROR, "unexpected end of tape");	if (!eofOK)		elog(ERROR, "unexpected end of data");	return 0;}/* * Routines specialized for HeapTuple case * * The stored form is actually a MinimalTuple, but for largely historical * reasons we allow COPYTUP to work from a HeapTuple. * * Since MinimalTuple already has length in its first word, we don't need * to write that separately. */static void *copytup_heap(Tuplestorestate *state, void *tup){	MinimalTuple tuple;	tuple = minimal_tuple_from_heap_tuple((HeapTuple) tup);	USEMEM(state, GetMemoryChunkSpace(tuple));	return (void *) tuple;}static voidwritetup_heap(Tuplestorestate *state, void *tup){	MinimalTuple tuple = (MinimalTuple) tup;	unsigned int tuplen = tuple->t_len;	if (BufFileWrite(state->myfile, (void *) tuple, tuplen) != (size_t) tuplen)		elog(ERROR, "write failed");	if (state->eflags & EXEC_FLAG_BACKWARD)		/* need trailing length word? */		if (BufFileWrite(state->myfile, (void *) &tuplen,						 sizeof(tuplen)) != sizeof(tuplen))			elog(ERROR, "write failed");	FREEMEM(state, GetMemoryChunkSpace(tuple));	heap_free_minimal_tuple(tuple);}static void *readtup_heap(Tuplestorestate *state, unsigned int len){	MinimalTuple tuple = (MinimalTuple) palloc(len);	unsigned int tuplen;	USEMEM(state, GetMemoryChunkSpace(tuple));	/* read in the tuple proper */	tuple->t_len = len;	if (BufFileRead(state->myfile, (void *) ((char *) tuple + sizeof(int)),					len - sizeof(int)) != (size_t) (len - sizeof(int)))		elog(ERROR, "unexpected end of data");	if (state->eflags & EXEC_FLAG_BACKWARD)		/* need trailing length word? */		if (BufFileRead(state->myfile, (void *) &tuplen,						sizeof(tuplen)) != sizeof(tuplen))			elog(ERROR, "unexpected end of data");	return (void *) tuple;}

⌨️ 快捷键说明

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