tuplesort.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,177 行 · 第 1/5 页

C
2,177
字号
	return state;}Tuplesortstate *tuplesort_begin_heap(TupleDesc tupDesc,					 int nkeys,					 Oid *sortOperators, AttrNumber *attNums,					 bool randomAccess){	Tuplesortstate *state = tuplesort_begin_common(randomAccess);	int			i;	AssertArg(nkeys > 0);	state->comparetup = comparetup_heap;	state->copytup = copytup_heap;	state->writetup = writetup_heap;	state->readtup = readtup_heap;	state->tupDesc = tupDesc;	state->nKeys = nkeys;	state->scanKeys = (ScanKey) palloc0(nkeys * sizeof(ScanKeyData));	state->sortFnKinds = (SortFunctionKind *)		palloc0(nkeys * sizeof(SortFunctionKind));	for (i = 0; i < nkeys; i++)	{		RegProcedure sortFunction;		AssertArg(sortOperators[i] != 0);		AssertArg(attNums[i] != 0);		/* select a function that implements the sort operator */		SelectSortFunction(sortOperators[i], &sortFunction,						   &state->sortFnKinds[i]);		ScanKeyEntryInitialize(&state->scanKeys[i],							   0x0,							   attNums[i],							   sortFunction,							   (Datum) 0);	}	return state;}Tuplesortstate *tuplesort_begin_index(Relation indexRel,					  bool enforceUnique,					  bool randomAccess){	Tuplesortstate *state = tuplesort_begin_common(randomAccess);	state->comparetup = comparetup_index;	state->copytup = copytup_index;	state->writetup = writetup_index;	state->readtup = readtup_index;	state->indexRel = indexRel;	/* see comments below about btree dependence of this code... */	state->indexScanKey = _bt_mkscankey_nodata(indexRel);	state->enforceUnique = enforceUnique;	return state;}Tuplesortstate *tuplesort_begin_datum(Oid datumType,					  Oid sortOperator,					  bool randomAccess){	Tuplesortstate *state = tuplesort_begin_common(randomAccess);	RegProcedure sortFunction;	int16		typlen;	bool		typbyval;	state->comparetup = comparetup_datum;	state->copytup = copytup_datum;	state->writetup = writetup_datum;	state->readtup = readtup_datum;	state->datumType = datumType;	state->sortOperator = sortOperator;	/* select a function that implements the sort operator */	SelectSortFunction(sortOperator, &sortFunction, &state->sortFnKind);	/* and look up the function */	fmgr_info(sortFunction, &state->sortOpFn);	/* lookup necessary attributes of the datum type */	get_typlenbyval(datumType, &typlen, &typbyval);	state->datumTypeLen = typlen;	state->datumTypeByVal = typbyval;	return state;}/* * tuplesort_end * *	Release resources and clean up. */voidtuplesort_end(Tuplesortstate *state){	int			i;	if (state->tapeset)		LogicalTapeSetClose(state->tapeset);	if (state->memtuples)	{		for (i = 0; i < state->memtupcount; i++)			pfree(state->memtuples[i]);		pfree(state->memtuples);	}	if (state->memtupindex)		pfree(state->memtupindex);	/*	 * this stuff might better belong in a variant-specific shutdown	 * routine	 */	if (state->scanKeys)		pfree(state->scanKeys);	if (state->sortFnKinds)		pfree(state->sortFnKinds);	pfree(state);}/* * Accept one tuple while collecting input data for sort. * * Note that the input tuple is always copied; the caller need not save it. */voidtuplesort_puttuple(Tuplesortstate *state, void *tuple){	/*	 * Copy the given tuple into memory we control, and decrease availMem.	 * Then call the code shared with the Datum case.	 */	tuple = COPYTUP(state, tuple);	puttuple_common(state, tuple);}/* * Accept one Datum while collecting input data for sort. * * If the Datum is pass-by-ref type, the value will be copied. */voidtuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull){	DatumTuple *tuple;	/*	 * Build pseudo-tuple carrying the datum, and decrease availMem.	 */	if (isNull || state->datumTypeByVal)	{		tuple = (DatumTuple *) palloc(sizeof(DatumTuple));		tuple->val = val;		tuple->isNull = isNull;	}	else	{		Size		datalen;		Size		tuplelen;		char	   *newVal;		datalen = datumGetSize(val, false, state->datumTypeLen);		tuplelen = datalen + MAXALIGN(sizeof(DatumTuple));		tuple = (DatumTuple *) palloc(tuplelen);		newVal = ((char *) tuple) + MAXALIGN(sizeof(DatumTuple));		memcpy(newVal, DatumGetPointer(val), datalen);		tuple->val = PointerGetDatum(newVal);		tuple->isNull = false;	}	USEMEM(state, GetMemoryChunkSpace(tuple));	puttuple_common(state, (void *) tuple);}/* * Shared code for tuple and datum cases. */static voidputtuple_common(Tuplesortstate *state, void *tuple){	switch (state->status)	{		case TSS_INITIAL:			/*			 * Save the copied tuple into the unsorted array.			 */			if (state->memtupcount >= state->memtupsize)			{				/* Grow the unsorted array as needed. */				FREEMEM(state, GetMemoryChunkSpace(state->memtuples));				state->memtupsize *= 2;				state->memtuples = (void **)					repalloc(state->memtuples,							 state->memtupsize * sizeof(void *));				USEMEM(state, GetMemoryChunkSpace(state->memtuples));			}			state->memtuples[state->memtupcount++] = tuple;			/*			 * Done if we still fit in available memory.			 */			if (!LACKMEM(state))				return;			/*			 * Nope; time to switch to tape-based operation.			 */			inittapes(state);			/*			 * Dump tuples until we are back under the limit.			 */			dumptuples(state, false);			break;		case TSS_BUILDRUNS:			/*			 * Insert the copied tuple into the heap, with run number			 * currentRun if it can go into the current run, else run			 * number currentRun+1.  The tuple can go into the current run			 * if it is >= the first not-yet-output tuple.	(Actually, it			 * could go into the current run if it is >= the most recently			 * output tuple ... but that would require keeping around the			 * tuple we last output, and it's simplest to let writetup			 * free each tuple as soon as it's written.)			 *			 * Note there will always be at least one tuple in the heap at			 * this point; see dumptuples.			 */			Assert(state->memtupcount > 0);			if (COMPARETUP(state, tuple, state->memtuples[0]) >= 0)				tuplesort_heap_insert(state, tuple, state->currentRun, true);			else				tuplesort_heap_insert(state, tuple, state->currentRun + 1, true);			/*			 * If we are over the memory limit, dump tuples till we're			 * under.			 */			dumptuples(state, false);			break;		default:			elog(ERROR, "invalid tuplesort state");			break;	}}/* * All tuples have been provided; finish the sort. */voidtuplesort_performsort(Tuplesortstate *state){	switch (state->status)	{		case TSS_INITIAL:			/*			 * We were able to accumulate all the tuples within the			 * allowed amount of memory.  Just qsort 'em and we're done.			 */			if (state->memtupcount > 1)			{				qsort_tuplesortstate = state;				qsort((void *) state->memtuples, state->memtupcount,					  sizeof(void *), qsort_comparetup);			}			state->current = 0;			state->eof_reached = false;			state->markpos_offset = 0;			state->markpos_eof = false;			state->status = TSS_SORTEDINMEM;			break;		case TSS_BUILDRUNS:			/*			 * Finish tape-based sort.	First, flush all tuples remaining			 * in memory out to tape; then merge until we have a single			 * remaining run (or, if !randomAccess, one run per tape).			 * Note that mergeruns sets the correct state->status.			 */			dumptuples(state, true);			mergeruns(state);			state->eof_reached = false;			state->markpos_block = 0L;			state->markpos_offset = 0;			state->markpos_eof = false;			break;		default:			elog(ERROR, "invalid tuplesort state");			break;	}}/* * Fetch the next tuple in either forward or back direction. * Returns NULL if no more tuples.	If should_free is set, the * caller must pfree the returned tuple when done with it. */void *tuplesort_gettuple(Tuplesortstate *state, bool forward,				   bool *should_free){	unsigned int tuplen;	void	   *tup;	switch (state->status)	{		case TSS_SORTEDINMEM:			Assert(forward || state->randomAccess);			*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_SORTEDONTAPE:			Assert(forward || state->randomAccess);			*should_free = true;			if (forward)			{				if (state->eof_reached)					return NULL;				if ((tuplen = getlen(state, state->result_tape, true)) != 0)				{					tup = READTUP(state, state->result_tape, 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.			 */			if (state->eof_reached)			{				/*				 * Seek position is pointing just past the zero tuplen at				 * the end of file; back up to fetch last tuple's ending				 * length word.  If seek fails we must have a completely				 * empty file.				 */				if (!LogicalTapeBackspace(state->tapeset,										  state->result_tape,										  2 * sizeof(unsigned int)))					return NULL;				state->eof_reached = false;			}			else			{				/*				 * Back up and fetch previously-returned tuple's ending				 * length word.  If seek fails, assume we are at start of				 * file.				 */				if (!LogicalTapeBackspace(state->tapeset,										  state->result_tape,										  sizeof(unsigned int)))					return NULL;				tuplen = getlen(state, state->result_tape, false);				/*				 * Back up to get ending length word of tuple before it.				 */				if (!LogicalTapeBackspace(state->tapeset,										  state->result_tape,									  tuplen + 2 * sizeof(unsigned int)))				{					/*					 * 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 (!LogicalTapeBackspace(state->tapeset,											  state->result_tape,										  tuplen + sizeof(unsigned int)))						elog(ERROR, "bogus tuple length in backward scan");					return NULL;				}			}			tuplen = getlen(state, state->result_tape, 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 (!LogicalTapeBackspace(state->tapeset,									  state->result_tape,									  tuplen))

⌨️ 快捷键说明

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