*** ./src/backend/access/common/heaptuple.c.orig Thu Oct 28 14:27:35 2004 --- ./src/backend/access/common/heaptuple.c Fri Oct 29 10:53:43 2004 *************** *** 731,741 **** } /* ---------------- ! * heap_deformtuple * * Given a tuple, extract data into values/nulls arrays; this is * the inverse of heap_formtuple. * * Storage for the values/nulls arrays is provided by the caller; * it should be sized according to tupleDesc->natts not tuple->t_natts. * --- 731,744 ---- } /* ---------------- ! * heap_deformtuple_incr * * Given a tuple, extract data into values/nulls arrays; this is * the inverse of heap_formtuple. * + * This function can extract attributes of tupple, incrementally. + * When you want all attributes, use heap_deformtuple(). + * * Storage for the values/nulls arrays is provided by the caller; * it should be sized according to tupleDesc->natts not tuple->t_natts. * *************** *** 746,783 **** * this routine will be significantly quicker than a loop around * heap_getattr; the loop will become O(N^2) as soon as any * noncacheable attribute offsets are involved. * ---------------- */ void ! heap_deformtuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, ! char *nulls) { HeapTupleHeader tup = tuple->t_data; Form_pg_attribute *att = tupleDesc->attrs; - int tdesc_natts = tupleDesc->natts; int natts; /* number of atts to extract */ int attnum; char *tp; /* ptr to tuple data */ long off; /* offset in tuple data */ bits8 *bp = tup->t_bits; /* ptr to null bitmask in tuple */ ! bool slow = false; /* can we use/set attcacheoff? */ ! ! natts = tup->t_natts; /* * In inheritance situations, it is possible that the given tuple * actually has more fields than the caller is expecting. Don't run * off the end of the caller's arrays. */ ! natts = Min(natts, tdesc_natts); ! tp = (char *) tup + tup->t_hoff; ! off = 0; ! for (attnum = 0; attnum < natts; attnum++) { if (HeapTupleHasNulls(tuple) && att_isnull(attnum, bp)) { --- 749,808 ---- * this routine will be significantly quicker than a loop around * heap_getattr; the loop will become O(N^2) as soon as any * noncacheable attribute offsets are involved. + * + * Fills the values/nulls arrays up to end_attnum. + * DeformTupleState is used in order to keep the running state of + * this function. + * + * Example: The tupple has 100 columns. + * - first call to get col5 will fill first 5 positions in the array. + * - next call to get col75 will fill starts from 5 and up to 75. + * - next call to get col60 will do nothing, because already extracted. * ---------------- */ void ! heap_deformtuple_incr(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, ! char *nulls, ! DeformTupleState *state, ! int end_attnum) { HeapTupleHeader tup = tuple->t_data; Form_pg_attribute *att = tupleDesc->attrs; int natts; /* number of atts to extract */ int attnum; char *tp; /* ptr to tuple data */ long off; /* offset in tuple data */ bits8 *bp = tup->t_bits; /* ptr to null bitmask in tuple */ ! bool slow; /* can we use/set attcacheoff? */ /* * In inheritance situations, it is possible that the given tuple * actually has more fields than the caller is expecting. Don't run * off the end of the caller's arrays. */ ! natts = Min(tup->t_natts, end_attnum); ! if (state) { ! /* ! * Restore state of previous execution. ! * Before the first execution of each tuple, state must ! * initialize by using InitDeformTupleState(). ! */ ! attnum = state->natts; ! off = state->off; ! slow = state->slow; ! } else { ! /* start from the first attribute */ ! attnum = 0; ! off = 0; ! slow = false; ! } ! tp = (char *) tup + tup->t_hoff; ! for (; attnum < natts; attnum++) { if (HeapTupleHasNulls(tuple) && att_isnull(attnum, bp)) { *************** *** 811,821 **** * If tuple doesn't have all the atts indicated by tupleDesc, read the * rest as null */ ! for (; attnum < tdesc_natts; attnum++) { values[attnum] = (Datum) 0; nulls[attnum] = 'n'; } } /* ---------------- --- 836,872 ---- * If tuple doesn't have all the atts indicated by tupleDesc, read the * rest as null */ ! for (; attnum < end_attnum; attnum++) { values[attnum] = (Datum) 0; nulls[attnum] = 'n'; } + + if (state) { + /* Save state for next execution */ + state->natts = attnum; + state->off = off; + state->slow = slow; + } + } + + /* ---------------- + * heap_deformtuple + * + * Given a tuple, extract data into values/nulls arrays; this is + * the inverse of heap_formtuple. + * + * more information, see also heap_deformtuple_incr. + * ---------------- + */ + void + heap_deformtuple(HeapTuple tuple, + TupleDesc tupleDesc, + Datum *values, + char *nulls) + { + heap_deformtuple_incr(tuple, tupleDesc, values, nulls, + NULL, tupleDesc->natts); } /* ---------------- *** ./src/backend/executor/execQual.c.orig Fri Oct 29 13:33:24 2004 --- ./src/backend/executor/execQual.c Fri Oct 29 16:19:28 2004 *************** *** 512,517 **** --- 512,556 ---- * been zeroed. */ Assert(variable->vartype == tuple_type->attrs[attnum - 1]->atttypid); + + /* + * Try not to use nocachegetattr(). + * + * If tuple has many columns, and it has varlen column or null data, + * time spent in nocachegetattr() is O(N^2) in the number of fields. + * When heap_deformtuple_incr() is used in place of nocachegetattr(), + * would reduce the time from O(N^2) to O(N). + */ + /* + * Check whether can use deformtuple_cache of TupleTableSlot. + */ + if (DeformTupleCacheIsValid(slot)) { + /* + * Check whether the attribute was extracted already. + */ + if (!AttributeIsDeformed(&(slot->deformtuple_cache.state), + attnum)) { + /* + * Fills the values/nulls arrays up to attnum. + */ + heap_deformtuple_incr(heapTuple, + tuple_type, + slot->deformtuple_cache.values, + slot->deformtuple_cache.nulls, + &(slot->deformtuple_cache.state), + attnum); + } + + /* + * The result is acquired from deformtuple_cache. + */ + if (slot->deformtuple_cache.nulls[attnum - 1] == 'n') { + *isNull = true; + return (Datum)NULL; + } + *isNull = false; + return slot->deformtuple_cache.values[attnum - 1]; + } } result = heap_getattr(heapTuple, /* tuple containing attribute */ *** ./src/backend/executor/execTuples.c.orig Fri Oct 29 13:05:04 2004 --- ./src/backend/executor/execTuples.c Fri Oct 29 16:29:02 2004 *************** *** 121,126 **** --- 121,174 ---- /* ---------------------------------------------------------------- + * deformtuple_cache create/delete functions + * ---------------------------------------------------------------- + */ + /* -------------------------------- + * ExecCreateDeformTupleCache + * + * This allocates values/null arrays for caching result of + * heap_defromtuple_incr(). + * -------------------------------- + */ + static void + ExecCreateDeformTupleCache(TupleTableSlot *slot) + { + MemoryContext oldcxt; + int natts; + + if (slot->deformtuple_cache.mcxt == NULL) return; + + oldcxt = MemoryContextSwitchTo(slot->deformtuple_cache.mcxt); + + natts = slot->ttc_tupleDescriptor->natts; + + slot->deformtuple_cache.values = palloc(natts * sizeof(Datum)); + slot->deformtuple_cache.nulls = palloc(natts * sizeof(char)); + + MemoryContextSwitchTo(oldcxt); + } + + /* -------------------------------- + * ExecDeleteDeformTupleCache + * + * This frees values/null arrays use by deformtuple_cache. + * -------------------------------- + */ + static void + ExecDeleteDeformTupleCache(TupleTableSlot *slot) + { + if (slot->deformtuple_cache.values) { + pfree(slot->deformtuple_cache.values); + slot->deformtuple_cache.values = NULL; + } + if (slot->deformtuple_cache.nulls) { + pfree(slot->deformtuple_cache.nulls); + slot->deformtuple_cache.nulls = NULL; + } + } + + /* ---------------------------------------------------------------- * tuple table create/delete functions * ---------------------------------------------------------------- */ *************** *** 161,166 **** --- 209,215 ---- newtable->size = initialSize; newtable->next = 0; newtable->array = array; + newtable->mcxt = CurrentMemoryContext; return newtable; } *************** *** 204,209 **** --- 253,259 ---- for (i = 0; i < next; i++) { ExecClearTuple(&array[i]); + ExecDeleteDeformTupleCache(&array[i]); if (array[i].ttc_shouldFreeDesc && array[i].ttc_tupleDescriptor != NULL) FreeTupleDesc(array[i].ttc_tupleDescriptor); *************** *** 222,227 **** --- 272,301 ---- * tuple table slot reservation functions * ---------------------------------------------------------------- */ + + /* -------------------------------- + * InitTupleTableSlot + * + * Initializes member of TupleTableSlot. + * -------------------------------- + */ + static void + InitTupleTableSlot(TupleTableSlot *slot) + { + slot->val = NULL; + slot->ttc_shouldFree = true; + slot->ttc_descIsNew = true; + slot->ttc_shouldFreeDesc = true; + slot->ttc_tupleDescriptor = NULL; + slot->ttc_buffer = InvalidBuffer; + + slot->deformtuple_cache.mcxt = NULL; + slot->deformtuple_cache.values = NULL; + slot->deformtuple_cache.nulls = NULL; + + InitDeformTupleState(&(slot->deformtuple_cache.state)); + } + /* -------------------------------- * ExecAllocTableSlot * *************** *** 271,282 **** /* Make sure the allocated slot is valid (and empty) */ slot->type = T_TupleTableSlot; ! slot->val = NULL; ! slot->ttc_shouldFree = true; ! slot->ttc_descIsNew = true; ! slot->ttc_shouldFreeDesc = true; ! slot->ttc_tupleDescriptor = NULL; ! slot->ttc_buffer = InvalidBuffer; return slot; } --- 345,354 ---- /* Make sure the allocated slot is valid (and empty) */ slot->type = T_TupleTableSlot; ! InitTupleTableSlot(slot); ! ! /* Set MemoryContext for allocates values/null array. */ ! slot->deformtuple_cache.mcxt = table->mcxt; return slot; } *************** *** 295,307 **** { TupleTableSlot *slot = makeNode(TupleTableSlot); ! /* This should match ExecAllocTableSlot() */ ! slot->val = NULL; ! slot->ttc_shouldFree = true; ! slot->ttc_descIsNew = true; ! slot->ttc_shouldFreeDesc = true; ! slot->ttc_tupleDescriptor = NULL; ! slot->ttc_buffer = InvalidBuffer; return slot; } --- 367,374 ---- { TupleTableSlot *slot = makeNode(TupleTableSlot); ! /* Make sure the allocated slot is valid (and empty) */ ! InitTupleTableSlot(slot); return slot; } *************** *** 418,423 **** --- 485,495 ---- slot->ttc_buffer = InvalidBuffer; + /* + * Reset the DeformTupleState for heap_deformtuple_incr(). + */ + InitDeformTupleState(&(slot->deformtuple_cache.state)); + return slot; } *************** *** 439,444 **** --- 511,522 ---- slot->ttc_tupleDescriptor = tupdesc; slot->ttc_shouldFreeDesc = shouldFree; + + /* Deletes the old deformtuple_cache */ + ExecDeleteDeformTupleCache(slot); + + /* Creates the deformtuple_cache from the provided tupledesc */ + ExecCreateDeformTupleCache(slot); } /* -------------------------------- *** ./src/include/access/heapam.h.orig Fri Oct 29 10:52:55 2004 --- ./src/include/access/heapam.h Fri Oct 29 10:53:36 2004 *************** *** 202,207 **** --- 202,210 ---- char *replActions); extern void heap_deformtuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, char *nulls); + extern void heap_deformtuple_incr(HeapTuple tuple, TupleDesc tupleDesc, + Datum *values, char *nulls, + DeformTupleState *state, int end_attnum); extern void heap_freetuple(HeapTuple tuple); extern HeapTuple heap_addheader(int natts, bool withoid, Size structlen, void *structure); *** ./src/include/access/htup.h.orig Thu Oct 28 11:06:05 2004 --- ./src/include/access/htup.h Fri Oct 29 15:06:59 2004 *************** *** 498,501 **** --- 498,525 ---- #define SizeOfHeapNewpage (offsetof(xl_heap_newpage, blkno) + sizeof(BlockNumber)) + /* + * DeformTupleState keeps the running state of heap_deformtuple_incr(). + * heap_deformtuple_incr() can extract attributes of tupple, incrementally. + * When we would like to execute this incrementally, it is necessary to + * keep the running state of that function. + */ + typedef struct DeformTupleState + { + int natts; /* number of attributes which was extracted */ + long off; + bool slow; + } DeformTupleState; + + /* Initialize or reset a DeformTupleState. */ + #define InitDeformTupleState(state) \ + do { \ + (state)->natts = 0; \ + (state)->off = 0; \ + (state)->slow = false; \ + } while(0) + + /* Check whether the attribute was extracted already. */ + #define AttributeIsDeformed(state, attnum) ((state)->natts >= (attnum)) + #endif /* HTUP_H */ *** ./src/include/executor/executor.h.orig Fri Oct 29 13:28:47 2004 --- ./src/include/executor/executor.h Fri Oct 29 13:32:32 2004 *************** *** 36,41 **** --- 36,49 ---- #define ExecEvalExpr(expr, econtext, isNull, isDone) \ ((*(expr)->evalfunc) (expr, econtext, isNull, isDone)) + /* + * DeformTupleCacheIsValid + * + * Check whether the deformtuple_cache of TableTupleSlot is valid. + */ + #define DeformTupleCacheIsValid(slot) \ + (slot->deformtuple_cache.values != NULL) + /* * prototypes from functions in execAmi.c *** ./src/include/executor/tuptable.h.orig Fri Oct 29 11:14:06 2004 --- ./src/include/executor/tuptable.h Fri Oct 29 13:47:06 2004 *************** *** 32,37 **** --- 32,38 ---- * tupleDescriptor type information for the tuple data * shouldFreeDesc boolean - should we free tupleDescriptor * buffer the buffer for tuples pointing to disk pages + * deformtuple_cache result of heap_deformtuple_incr() * * The executor stores pointers to tuples in a ``tuple table'' * which is composed of TupleTableSlots. Sometimes the tuples *************** *** 55,60 **** --- 56,64 ---- * See executor.h for decls of functions defined in execTuples.c * -jolly * + * deformtuple_cache is for caching result of heap_deformtuple_incr(). + * It is used in ExecEvalVar() for try not to use nocachegetattr(). + * more information, see ExecEvalVar(). * ---------------- */ typedef struct TupleTableSlot *************** *** 66,71 **** --- 70,83 ---- bool ttc_shouldFreeDesc; TupleDesc ttc_tupleDescriptor; Buffer ttc_buffer; + + struct { + MemoryContext mcxt; /* for values/nulls allocation */ + DeformTupleState state; /* running state of + heap_deformtuple_incr() */ + Datum *values; + char *nulls; + } deformtuple_cache; } TupleTableSlot; /* ---------------- *************** *** 77,82 **** --- 89,95 ---- int size; /* size of the table */ int next; /* next available slot number */ TupleTableSlot *array; /* array of TupleTableSlot's */ + MemoryContext mcxt; /* for deformtuple_cache of TupleTableSlot */ } TupleTableData; typedef TupleTableData *TupleTable;