99 *
1010 *
1111 * IDENTIFICATION
12- * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.96 2005/01/27 23:23:49 neilc Exp $
12+ * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.97 2005/03/14 04:41:12 tgl Exp $
1313 *
1414 * NOTES
1515 * The old interface functions have been converted to macros
2323#include "access/heapam.h"
2424#include "access/tuptoaster.h"
2525#include "catalog/pg_type.h"
26+ #include "executor/tuptable.h"
2627
2728
2829/* ----------------------------------------------------------------
@@ -751,6 +752,7 @@ heap_deformtuple(HeapTuple tuple,
751752char * nulls )
752753{
753754HeapTupleHeader tup = tuple -> t_data ;
755+ bool hasnulls = HeapTupleHasNulls (tuple );
754756Form_pg_attribute * att = tupleDesc -> attrs ;
755757int tdesc_natts = tupleDesc -> natts ;
756758int natts ;/* number of atts to extract */
@@ -775,7 +777,9 @@ heap_deformtuple(HeapTuple tuple,
775777
776778for (attnum = 0 ;attnum < natts ;attnum ++ )
777779{
778- if (HeapTupleHasNulls (tuple )&& att_isnull (attnum ,bp ))
780+ Form_pg_attribute thisatt = att [attnum ];
781+
782+ if (hasnulls && att_isnull (attnum ,bp ))
779783{
780784values [attnum ]= (Datum )0 ;
781785nulls [attnum ]= 'n' ;
@@ -785,21 +789,21 @@ heap_deformtuple(HeapTuple tuple,
785789
786790nulls [attnum ]= ' ' ;
787791
788- if (!slow && att [ attnum ] -> attcacheoff >=0 )
789- off = att [ attnum ] -> attcacheoff ;
792+ if (!slow && thisatt -> attcacheoff >=0 )
793+ off = thisatt -> attcacheoff ;
790794else
791795{
792- off = att_align (off ,att [ attnum ] -> attalign );
796+ off = att_align (off ,thisatt -> attalign );
793797
794798if (!slow )
795- att [ attnum ] -> attcacheoff = off ;
799+ thisatt -> attcacheoff = off ;
796800}
797801
798- values [attnum ]= fetchatt (att [ attnum ] ,tp + off );
802+ values [attnum ]= fetchatt (thisatt ,tp + off );
799803
800- off = att_addlength (off ,att [ attnum ] -> attlen ,tp + off );
804+ off = att_addlength (off ,thisatt -> attlen ,tp + off );
801805
802- if (att [ attnum ] -> attlen <=0 )
806+ if (thisatt -> attlen <=0 )
803807slow = true;/* can't use attcacheoff anymore */
804808}
805809
@@ -814,6 +818,177 @@ heap_deformtuple(HeapTuple tuple,
814818}
815819}
816820
821+ /* ----------------
822+ *slot_deformtuple
823+ *
824+ *Given a TupleTableSlot, extract data into cache_values array
825+ *from the slot's tuple.
826+ *
827+ *This is essentially an incremental version of heap_deformtuple:
828+ *on each call we extract attributes up to the one needed, without
829+ *re-computing information about previously extracted attributes.
830+ *slot->cache_natts is the number of attributes already extracted.
831+ *
832+ *This only gets called from slot_getattr. Note that slot_getattr
833+ *must check for a null attribute since we don't create an array
834+ *of null indicators.
835+ * ----------------
836+ */
837+ static void
838+ slot_deformtuple (TupleTableSlot * slot ,int natts )
839+ {
840+ HeapTuple tuple = slot -> val ;
841+ TupleDesc tupleDesc = slot -> ttc_tupleDescriptor ;
842+ Datum * values = slot -> cache_values ;
843+ HeapTupleHeader tup = tuple -> t_data ;
844+ bool hasnulls = HeapTupleHasNulls (tuple );
845+ Form_pg_attribute * att = tupleDesc -> attrs ;
846+ int attnum ;
847+ char * tp ;/* ptr to tuple data */
848+ long off ;/* offset in tuple data */
849+ bits8 * bp = tup -> t_bits ;/* ptr to null bitmask in tuple */
850+ bool slow ;/* can we use/set attcacheoff? */
851+
852+ /*
853+ * Check whether the first call for this tuple, and initialize or
854+ * restore loop state.
855+ */
856+ attnum = slot -> cache_natts ;
857+ if (attnum == 0 )
858+ {
859+ /* Start from the first attribute */
860+ off = 0 ;
861+ slow = false;
862+ }
863+ else
864+ {
865+ /* Restore state from previous execution */
866+ off = slot -> cache_off ;
867+ slow = slot -> cache_slow ;
868+ }
869+
870+ tp = (char * )tup + tup -> t_hoff ;
871+
872+ for (;attnum < natts ;attnum ++ )
873+ {
874+ Form_pg_attribute thisatt = att [attnum ];
875+
876+ if (hasnulls && att_isnull (attnum ,bp ))
877+ {
878+ values [attnum ]= (Datum )0 ;
879+ slow = true;/* can't use attcacheoff anymore */
880+ continue ;
881+ }
882+
883+ if (!slow && thisatt -> attcacheoff >=0 )
884+ off = thisatt -> attcacheoff ;
885+ else
886+ {
887+ off = att_align (off ,thisatt -> attalign );
888+
889+ if (!slow )
890+ thisatt -> attcacheoff = off ;
891+ }
892+
893+ values [attnum ]= fetchatt (thisatt ,tp + off );
894+
895+ off = att_addlength (off ,thisatt -> attlen ,tp + off );
896+
897+ if (thisatt -> attlen <=0 )
898+ slow = true;/* can't use attcacheoff anymore */
899+ }
900+
901+ /*
902+ * Save state for next execution
903+ */
904+ slot -> cache_natts = attnum ;
905+ slot -> cache_off = off ;
906+ slot -> cache_slow = slow ;
907+ }
908+
909+ /* --------------------------------
910+ *slot_getattr
911+ *
912+ *This function fetches an attribute of the slot's current tuple.
913+ *It is functionally equivalent to heap_getattr, but fetches of
914+ *multiple attributes of the same tuple will be optimized better,
915+ *because we avoid O(N^2) behavior from multiple calls of
916+ *nocachegetattr(), even when attcacheoff isn't usable.
917+ * --------------------------------
918+ */
919+ Datum
920+ slot_getattr (TupleTableSlot * slot ,int attnum ,bool * isnull )
921+ {
922+ HeapTuple tuple = slot -> val ;
923+ TupleDesc tupleDesc = slot -> ttc_tupleDescriptor ;
924+ HeapTupleHeader tup ;
925+
926+ /*
927+ * system attributes are handled by heap_getsysattr
928+ */
929+ if (attnum <=0 )
930+ return heap_getsysattr (tuple ,attnum ,tupleDesc ,isnull );
931+
932+ /*
933+ * check if attnum is out of range according to either the tupdesc
934+ * or the tuple itself; if so return NULL
935+ */
936+ tup = tuple -> t_data ;
937+
938+ if (attnum > tup -> t_natts || attnum > tupleDesc -> natts )
939+ {
940+ * isnull = true;
941+ return (Datum )0 ;
942+ }
943+
944+ /*
945+ * check if target attribute is null
946+ */
947+ if (HeapTupleHasNulls (tuple )&& att_isnull (attnum - 1 ,tup -> t_bits ))
948+ {
949+ * isnull = true;
950+ return (Datum )0 ;
951+ }
952+
953+ /*
954+ * If the attribute's column has been dropped, we force a NULL
955+ * result. This case should not happen in normal use, but it could
956+ * happen if we are executing a plan cached before the column was
957+ * dropped.
958+ */
959+ if (tupleDesc -> attrs [attnum - 1 ]-> attisdropped )
960+ {
961+ * isnull = true;
962+ return (Datum )0 ;
963+ }
964+
965+ /*
966+ * If attribute wasn't already extracted, extract it and preceding
967+ * attributes.
968+ */
969+ if (attnum > slot -> cache_natts )
970+ {
971+ /*
972+ * If first time for this TupleTableSlot, allocate the cache
973+ * workspace. It must have the same lifetime as the slot, so allocate
974+ * it in the slot's own context. We size the array according to what
975+ * the tupdesc says, NOT the tuple.
976+ */
977+ if (slot -> cache_values == NULL )
978+ slot -> cache_values = (Datum * )
979+ MemoryContextAlloc (slot -> ttc_mcxt ,
980+ tupleDesc -> natts * sizeof (Datum ));
981+
982+ slot_deformtuple (slot ,attnum );
983+ }
984+
985+ /*
986+ * The result is acquired from cache_values array.
987+ */
988+ * isnull = false;
989+ return slot -> cache_values [attnum - 1 ];
990+ }
991+
817992/* ----------------
818993 *heap_freetuple
819994 * ----------------