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 + -
显示快捷键?