diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execJunk.c | 34 | ||||
-rw-r--r-- | src/backend/executor/execQual.c | 43 | ||||
-rw-r--r-- | src/backend/executor/execTuples.c | 254 |
3 files changed, 124 insertions, 207 deletions
diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c index 5087c7bfc39..f747976acfa 100644 --- a/src/backend/executor/execJunk.c +++ b/src/backend/executor/execJunk.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.46 2004/12/31 21:59:45 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.47 2005/03/14 04:41:12 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -209,20 +209,13 @@ ExecGetJunkAttribute(JunkFilter *junkfilter, Datum *value, bool *isNull) { - List *targetList; ListCell *t; - AttrNumber resno; - TupleDesc tupType; - HeapTuple tuple; /* - * first look in the junkfilter's target list for an attribute with + * Look in the junkfilter's target list for an attribute with * the given name */ - resno = InvalidAttrNumber; - targetList = junkfilter->jf_targetList; - - foreach(t, targetList) + foreach(t, junkfilter->jf_targetList) { TargetEntry *tle = lfirst(t); Resdom *resdom = tle->resdom; @@ -231,26 +224,13 @@ ExecGetJunkAttribute(JunkFilter *junkfilter, (strcmp(resdom->resname, attrName) == 0)) { /* We found it ! */ - resno = resdom->resno; - break; + *value = slot_getattr(slot, resdom->resno, isNull); + return true; } } - if (resno == InvalidAttrNumber) - { - /* Ooops! We couldn't find this attribute... */ - return false; - } - - /* - * Now extract the attribute value from the tuple. - */ - tuple = slot->val; - tupType = slot->ttc_tupleDescriptor; - - *value = heap_getattr(tuple, resno, tupType, isNull); - - return true; + /* Ooops! We couldn't find this attribute... */ + return false; } /* diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 0199df0f719..87cc201a3e3 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.171 2004/12/31 21:59:45 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.172 2005/03/14 04:41:12 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -438,11 +438,8 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone) { Var *variable = (Var *) exprstate->expr; - Datum result; TupleTableSlot *slot; AttrNumber attnum; - HeapTuple heapTuple; - TupleDesc tuple_type; if (isDone) *isDone = ExprSingleResult; @@ -475,35 +472,19 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext, break; } - /* - * extract tuple information from the slot - */ - heapTuple = slot->val; - tuple_type = slot->ttc_tupleDescriptor; - +#ifdef USE_ASSERT_CHECKING /* * Some checks that are only applied for user attribute numbers (bogus - * system attnums will be caught inside heap_getattr). + * system attnums will be caught inside slot_getattr). */ if (attnum > 0) { - /* - * This assert checks that the attnum is valid. - */ - Assert(attnum <= tuple_type->natts && - tuple_type->attrs[attnum - 1] != NULL); + TupleDesc tuple_type = slot->ttc_tupleDescriptor; /* - * If the attribute's column has been dropped, we force a NULL - * result. This case should not happen in normal use, but it could - * happen if we are executing a plan cached before the column was - * dropped. + * This assert checks that the attnum is valid. */ - if (tuple_type->attrs[attnum - 1]->attisdropped) - { - *isNull = true; - return (Datum) 0; - } + Assert(attnum <= tuple_type->natts); /* * This assert checks that the datatype the plan expects to get @@ -515,16 +496,12 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext, * Note that we can't check dropped columns, since their atttypid has * been zeroed. */ - Assert(variable->vartype == tuple_type->attrs[attnum - 1]->atttypid); + Assert(variable->vartype == tuple_type->attrs[attnum - 1]->atttypid || + tuple_type->attrs[attnum - 1]->attisdropped); } +#endif /* USE_ASSERT_CHECKING */ - result = heap_getattr(heapTuple, /* tuple containing attribute */ - attnum, /* attribute number of desired - * attribute */ - tuple_type, /* tuple descriptor of tuple */ - isNull); /* return: is attribute null? */ - - return result; + return slot_getattr(slot, attnum, isNull); } /* ---------------------------------------------------------------- diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 2864589ebb3..8574efc95d8 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.83 2004/12/31 21:59:45 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.84 2005/03/14 04:41:12 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -31,13 +31,11 @@ * * SLOT ACCESSORS * ExecStoreTuple - store a tuple in the table - * ExecFetchTuple - fetch a tuple from the table * ExecClearTuple - clear contents of a table slot * ExecSetSlotDescriptor - set a slot's tuple descriptor - * ExecSetSlotDescriptorIsNew - diddle the slot-desc-is-new flag * * SLOT STATUS PREDICATES - * TupIsNull - true when slot contains no tuple(Macro) + * TupIsNull - true when slot contains no tuple (macro) * * CONVENIENCE INITIALIZATION ROUTINES * ExecInitResultTupleSlot \ convenience routines to initialize @@ -60,7 +58,7 @@ * - ExecInitSeqScan() calls ExecInitScanTupleSlot() and * ExecInitResultTupleSlot() to reserve places in the tuple * table for the tuples returned by the access methods and the - * tuples resulting from preforming target list projections. + * tuples resulting from performing target list projections. * * During ExecRun() * ---------------- @@ -71,8 +69,8 @@ * tuple from ExecProject() and place it into the result tuple slot. * * - ExecutePlan() calls ExecRetrieve() which gets the tuple out of - * the slot passed to it by calling ExecFetchTuple(). this tuple - * is then returned. + * the slot passed to it (by direct access to slot->val, which is + * ugly but not worth changing). this tuple is then returned. * * At ExecEnd() * ---------------- @@ -87,23 +85,6 @@ * this information is also kept in the ExprContext of each node. * Soon the executor will be redesigned and ExprContext's will contain * only slot pointers. -cim 3/14/91 - * - * NOTES - * The tuple table stuff is relatively new, put here to alleviate - * the process growth problems in the executor. The other routines - * are old (from the original lisp system) and may someday become - * obsolete. -cim 6/23/90 - * - * In the implementation of nested-dot queries such as - * "retrieve (EMP.hobbies.all)", a single scan may return tuples - * of many types, so now we return pointers to tuple descriptors - * along with tuples returned via the tuple table. This means - * we now have a bunch of routines to diddle the slot descriptors - * too. -cim 1/18/90 - * - * The tuple table stuff depends on the executor/tuptable.h macros, - * and the TupleTableSlot node in execnodes.h. - * */ #include "postgres.h" @@ -124,43 +105,52 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList, * tuple table create/delete functions * ---------------------------------------------------------------- */ + /* -------------------------------- * ExecCreateTupleTable * - * This creates a new tuple table of the specified initial - * size. If the size is insufficient, ExecAllocTableSlot() - * will grow the table as necessary. + * This creates a new tuple table of the specified size. * * This should be used by InitPlan() to allocate the table. * The table's address will be stored in the EState structure. * -------------------------------- */ -TupleTable /* return: address of table */ -ExecCreateTupleTable(int initialSize) /* initial number of slots in - * table */ +TupleTable +ExecCreateTupleTable(int tableSize) { - TupleTable newtable; /* newly allocated table */ - TupleTableSlot *array; /* newly allocated slot array */ + TupleTable newtable; + int i; /* * sanity checks */ - Assert(initialSize >= 1); + Assert(tableSize >= 1); /* - * Now allocate our new table along with space for the pointers to the - * tuples. Zero out the slots. + * allocate the table itself */ - - newtable = (TupleTable) palloc(sizeof(TupleTableData)); - array = (TupleTableSlot *) palloc0(initialSize * sizeof(TupleTableSlot)); + newtable = (TupleTable) palloc(sizeof(TupleTableData) + + (tableSize - 1) * sizeof(TupleTableSlot)); + newtable->size = tableSize; + newtable->next = 0; /* - * initialize the new table and return it to the caller. + * initialize all the slots to empty states */ - newtable->size = initialSize; - newtable->next = 0; - newtable->array = array; + for (i = 0; i < tableSize; i++) + { + TupleTableSlot *slot = &(newtable->array[i]); + + slot->type = T_TupleTableSlot; + slot->val = NULL; + slot->ttc_tupleDescriptor = NULL; + slot->ttc_shouldFree = false; + slot->ttc_shouldFreeDesc = false; + slot->ttc_buffer = InvalidBuffer; + slot->ttc_mcxt = CurrentMemoryContext; + slot->cache_values = NULL; + slot->cache_natts = 0; /* mark slot_getattr state invalid */ + } return newtable; } @@ -178,22 +168,12 @@ ExecDropTupleTable(TupleTable table, /* tuple table */ bool shouldFree) /* true if we should free slot * contents */ { - int next; /* next available slot */ - TupleTableSlot *array; /* start of table array */ - int i; /* counter */ - /* * sanity checks */ Assert(table != NULL); /* - * get information from the table - */ - array = table->array; - next = table->next; - - /* * first free all the valid pointers in the tuple array and drop * refcounts of any referenced buffers, if that's what the caller * wants. (There is probably no good reason for the caller ever not @@ -201,27 +181,60 @@ ExecDropTupleTable(TupleTable table, /* tuple table */ */ if (shouldFree) { + int next = table->next; + int i; + for (i = 0; i < next; i++) { - ExecClearTuple(&array[i]); - if (array[i].ttc_shouldFreeDesc && - array[i].ttc_tupleDescriptor != NULL) - FreeTupleDesc(array[i].ttc_tupleDescriptor); + TupleTableSlot *slot = &(table->array[i]); + + ExecClearTuple(slot); + if (slot->ttc_shouldFreeDesc) + FreeTupleDesc(slot->ttc_tupleDescriptor); + if (slot->cache_values) + pfree(slot->cache_values); } } /* - * finally free the tuple array and the table itself. + * finally free the tuple table itself. */ - pfree(array); pfree(table); } +/* -------------------------------- + * MakeTupleTableSlot + * + * This routine makes an empty standalone TupleTableSlot. + * It really shouldn't exist, but there are a few places + * that do this, so we may as well centralize the knowledge + * of what's in one ... + * -------------------------------- + */ +TupleTableSlot * +MakeTupleTableSlot(void) +{ + TupleTableSlot *slot = makeNode(TupleTableSlot); + + /* This should match ExecCreateTupleTable() */ + slot->val = NULL; + slot->ttc_tupleDescriptor = NULL; + slot->ttc_shouldFree = false; + slot->ttc_shouldFreeDesc = false; + slot->ttc_buffer = InvalidBuffer; + slot->ttc_mcxt = CurrentMemoryContext; + slot->cache_values = NULL; + slot->cache_natts = 0; /* mark slot_getattr state invalid */ + + return slot; +} + /* ---------------------------------------------------------------- * tuple table slot reservation functions * ---------------------------------------------------------------- */ + /* -------------------------------- * ExecAllocTableSlot * @@ -236,7 +249,6 @@ TupleTableSlot * ExecAllocTableSlot(TupleTable table) { int slotnum; /* new slot number */ - TupleTableSlot *slot; /* * sanity checks @@ -244,66 +256,17 @@ ExecAllocTableSlot(TupleTable table) Assert(table != NULL); /* - * if our table is full we have to allocate a larger size table. Since - * ExecAllocTableSlot() is only called before the table is ever used - * to store tuples, we don't have to worry about the contents of the - * old table. If this changes, then we will have to preserve the - * contents. -cim 6/23/90 - * - * Unfortunately, we *cannot* do this. All of the nodes in the plan that - * have already initialized their slots will have pointers into - * _freed_ memory. This leads to bad ends. We now count the number - * of slots we will need and create all the slots we will need ahead - * of time. The if below should never happen now. Fail if it does. - * -mer 4 Aug 1992 + * We expect that the table was made big enough to begin with. + * We cannot reallocate it on the fly since previous plan nodes + * have already got pointers to individual entries. */ if (table->next >= table->size) elog(ERROR, "plan requires more slots than are available"); - /* - * at this point, space in the table is guaranteed so we reserve the - * next slot, initialize and return it. - */ slotnum = table->next; table->next++; - slot = &(table->array[slotnum]); - - /* 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; -} - -/* -------------------------------- - * MakeTupleTableSlot - * - * This routine makes an empty standalone TupleTableSlot. - * It really shouldn't exist, but there are a few places - * that do this, so we may as well centralize the knowledge - * of what's in one ... - * -------------------------------- - */ -TupleTableSlot * -MakeTupleTableSlot(void) -{ - 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; + return &(table->array[slotnum]); } /* ---------------------------------------------------------------- @@ -356,21 +319,22 @@ ExecStoreTuple(HeapTuple tuple, /* passing shouldFree=true for a tuple on a disk page is not sane */ Assert(BufferIsValid(buffer) ? (!shouldFree) : true); - /* clear out any old contents of the slot */ + /* + * clear out any old contents of the slot + */ ExecClearTuple(slot); /* - * store the new tuple into the specified slot and return the slot - * into which we stored the tuple. + * store the new tuple into the specified slot. */ slot->val = tuple; - slot->ttc_buffer = buffer; slot->ttc_shouldFree = shouldFree; /* * If tuple is on a disk page, keep the page pinned as long as we hold - * a pointer into it. + * a pointer into it. We assume the caller already has such a pin. */ + slot->ttc_buffer = buffer; if (BufferIsValid(buffer)) IncrBufferRefCount(buffer); @@ -388,27 +352,23 @@ ExecStoreTuple(HeapTuple tuple, TupleTableSlot * /* return: slot passed */ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */ { - HeapTuple oldtuple; /* prior contents of slot */ - /* * sanity checks */ Assert(slot != NULL); /* - * get information from the tuple table - */ - oldtuple = slot->val; - - /* - * free the old contents of the specified slot if necessary. + * Free the old contents of the specified slot if necessary. (Note: + * we allow slot->val to be null even when shouldFree is true, because + * there are a few callers of ExecStoreTuple that are too lazy to + * distinguish whether they are passing a NULL tuple, and always pass + * shouldFree = true.) */ - if (slot->ttc_shouldFree && oldtuple != NULL) - heap_freetuple(oldtuple); + if (slot->ttc_shouldFree && slot->val != NULL) + heap_freetuple(slot->val); slot->val = NULL; - - slot->ttc_shouldFree = true; /* probably useless code... */ + slot->ttc_shouldFree = false; /* * Drop the pin on the referenced buffer, if there is one. @@ -418,6 +378,11 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */ slot->ttc_buffer = InvalidBuffer; + /* + * mark slot_getattr state invalid + */ + slot->cache_natts = 0; + return slot; } @@ -433,36 +398,31 @@ ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */ TupleDesc tupdesc, /* new tuple descriptor */ bool shouldFree) /* is desc owned by slot? */ { - if (slot->ttc_shouldFreeDesc && - slot->ttc_tupleDescriptor != NULL) + if (slot->ttc_shouldFreeDesc) FreeTupleDesc(slot->ttc_tupleDescriptor); slot->ttc_tupleDescriptor = tupdesc; slot->ttc_shouldFreeDesc = shouldFree; -} -/* -------------------------------- - * ExecSetSlotDescriptorIsNew - * - * This function is used to change the setting of the "isNew" flag - * -------------------------------- - */ -void -ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, /* slot to change */ - bool isNew) /* "isNew" setting */ -{ - slot->ttc_descIsNew = isNew; + /* + * mark slot_getattr state invalid + */ + slot->cache_natts = 0; + + /* + * release any old cache array since tupledesc's natts may have changed + */ + if (slot->cache_values) + pfree(slot->cache_values); + slot->cache_values = NULL; } -/* ---------------------------------------------------------------- - * tuple table slot status predicates - * ---------------------------------------------------------------- - */ /* ---------------------------------------------------------------- * convenience initialization routines * ---------------------------------------------------------------- */ + /* -------------------------------- * ExecInit{Result,Scan,Extra}TupleSlot * |