1 /*-------------------------------------------------------------------------
4 * This file contains index tuple accessor and mutator routines,
5 * as well as a few various tuple utilities.
7 * Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.26 1998/02/06 20:17:51 momjian Exp $
13 *-------------------------------------------------------------------------
18 #include <access/heapam.h>
19 #include <access/ibit.h>
20 #include <access/itup.h>
21 #include <access/tupmacs.h>
22 #include <catalog/pg_type.h>
25 #include <regex/utils.h>
30 /* ----------------------------------------------------------------
31 * index_ tuple interface routines
32 * ----------------------------------------------------------------
40 index_formtuple(TupleDesc tupleDescriptor,
44 register char *tp; /* tuple pointer */
45 IndexTuple tuple; /* return tuple */
49 unsigned short infomask = 0;
52 int numberOfAttributes = tupleDescriptor->natts;
54 if (numberOfAttributes > MaxIndexAttributeNumber)
55 elog(ERROR, "index_formtuple: numberOfAttributes of %d > %d",
56 numberOfAttributes, MaxIndexAttributeNumber);
59 for (i = 0; i < numberOfAttributes && !hasnull; i++)
66 infomask |= INDEX_NULL_MASK;
68 hoff = IndexInfoFindDataOffset(infomask);
70 + ComputeDataSize(tupleDescriptor,
72 size = DOUBLEALIGN(size); /* be conservative */
74 tp = (char *) palloc(size);
75 tuple = (IndexTuple) tp;
76 MemSet(tp, 0, (int) size);
78 DataFill((char *) tp + hoff,
83 (hasnull ? (bits8 *) tp + sizeof(*tuple) : NULL));
86 * We do this because DataFill wants to initialize a "tupmask" which
87 * is used for HeapTuples, but we want an indextuple infomask. The
88 * only "relevent" info is the "has variable attributes" field, which
89 * is in mask position 0x02. We have already set the null mask above.
93 infomask |= INDEX_VAR_MASK;
96 * Here we make sure that we can actually hold the size. We also want
97 * to make sure that size is not aligned oddly. This actually is a
98 * rather odd way to make sure the size is not too large overall.
102 elog(ERROR, "index_formtuple: data takes %d bytes: too big", size);
108 * initialize metadata
111 tuple->t_info = infomask;
116 * nocache_index_getattr
118 * This gets called from index_getattr() macro, and only in cases
119 * where we can't use cacheoffset and the value is not null.
121 * This caches attribute offsets in the attribute descriptor.
123 * an alternate way to speed things up would be to cache offsets
124 * with the tuple, but that seems more difficult unless you take
125 * the storage hit of actually putting those offsets into the
126 * tuple you send to disk. Yuck.
128 * This scheme will be slightly slower than that, but should
129 * preform well for queries which hit large #'s of tuples. After
130 * you cache the offsets once, examining all the other tuples using
131 * the same attribute descriptor will go much quicker. -cim 5/4/91
135 nocache_index_getattr(IndexTuple tup,
140 register char *tp; /* ptr to att in tuple */
141 register char *bp = NULL; /* ptr to att in tuple */
142 int slow; /* do we have to walk nulls? */
143 register int data_off; /* tuple data offset */
144 AttributeTupleForm *att = tupleDesc->attrs;
154 * 1: No nulls and no variable length attributes.
155 * 2: Has a null or a varlena AFTER att.
156 * 3: Has nulls or varlenas BEFORE att.
161 /* This is handled in the macro */
162 Assert(PointerIsValid(isnull));
168 data_off = IndexTupleHasMinHeader(tup) ? sizeof *tup :
169 IndexInfoFindDataOffset(tup->t_info);
171 if (IndexTupleNoNulls(tup))
176 /* This is handled in the macro */
178 /* first attribute is always at position zero */
182 return (Datum) fetchatt(&(att[0]), (char *) tup + data_off);
184 if (att[attnum]->attcacheoff != -1)
186 return (Datum) fetchatt(&(att[attnum]),
187 (char *) tup + data_off +
188 att[attnum]->attcacheoff);
195 { /* there's a null somewhere in the tuple */
199 * check to see if desired att is null
205 bp = (char *) tup + sizeof(*tup); /* "knows" t_bits are
208 /* This is handled in the macro */
210 if (att_isnull(attnum, bp))
218 * Now check to see if any preceeding bits are null...
222 register int i = 0; /* current offset in bp */
223 register int mask; /* bit in byte we're looking at */
224 register char n; /* current byte in bp */
229 finalbit = attnum & 0x07;
231 for (; i <= byte && !slow; i++)
236 /* check for nulls in any "earlier" bytes */
242 /* check for nulls "before" final bit of last byte */
243 mask = (1 << finalbit) - 1;
251 tp = (char *) tup + data_off;
253 /* now check for any non-fixed length attrs before our attribute */
257 if (att[attnum]->attcacheoff != -1)
259 return (Datum) fetchatt(&(att[attnum]),
260 tp + att[attnum]->attcacheoff);
262 else if (attnum == 0)
264 return ((Datum) fetchatt(&(att[0]), (char *) tp));
266 else if (!IndexTupleAllFixed(tup))
270 for (j = 0; j < attnum && !slow; j++)
271 if (att[j]->attlen < 1 && !VARLENA_FIXED_SIZE(att[j]))
277 * if slow is zero, and we got here, we know that we have a tuple with
278 * no nulls. We also know that we have to initialize the remainder of
279 * the attribute cached offset values.
288 * need to set cache for some atts
291 att[0]->attcacheoff = 0;
293 while (att[j]->attcacheoff != -1)
296 if (!VARLENA_FIXED_SIZE(att[j-1]))
297 off = att[j - 1]->attcacheoff + att[j - 1]->attlen;
299 off = att[j - 1]->attcacheoff + att[j - 1]->atttypmod;
301 for (; j < attnum + 1; j++)
304 * Fix me when going to a machine with more than a four-byte
308 switch (att[j]->attlen)
311 off = (att[j]->attalign == 'd') ?
312 DOUBLEALIGN(off) : INTALIGN(off);
317 off = SHORTALIGN(off);
323 if (att[j]->attlen > sizeof(int32))
324 off = (att[j]->attalign == 'd') ?
325 DOUBLEALIGN(off) : LONGALIGN(off);
327 elog(ERROR, "nocache_index_getattr: attribute %d has len %d",
333 att[j]->attcacheoff = off;
335 /* The only varlena/-1 length value to get here is this */
336 if (!VARLENA_FIXED_SIZE(att[j]))
337 off += att[j]->attlen;
340 Assert(att[j]->atttypmod == VARSIZE(tp + off));
341 off += att[j]->atttypmod;
345 return (Datum) fetchatt(&(att[attnum]), tp + att[attnum]->attcacheoff);
349 register bool usecache = true;
350 register int off = 0;
354 * Now we know that we have to walk the tuple CAREFULLY.
357 for (i = 0; i < attnum; i++)
359 if (!IndexTupleNoNulls(tup))
361 if (att_isnull(i, bp))
368 /* If we know the next offset, we can skip the rest */
369 if (usecache && att[i]->attcacheoff != -1)
370 off = att[i]->attcacheoff;
373 switch (att[i]->attlen)
376 off = (att[i]->attalign == 'd') ?
377 DOUBLEALIGN(off) : INTALIGN(off);
382 off = SHORTALIGN(off);
388 if (att[i]->attlen < sizeof(int32))
390 "nocachegetiattr2: attribute %d has len %d",
392 if (att[i]->attalign == 'd')
393 off = DOUBLEALIGN(off);
395 off = LONGALIGN(off);
399 att[i]->attcacheoff = off;
402 switch (att[i]->attlen)
408 off += sizeof(short);
411 off += sizeof(int32);
414 Assert(!VARLENA_FIXED_SIZE(att[i]) ||
415 att[i]->atttypmod == VARSIZE(tp + off));
416 off += VARSIZE(tp + off);
417 if (!VARLENA_FIXED_SIZE(att[i]))
421 off += att[i]->attlen;
426 switch (att[attnum]->attlen)
429 off = (att[attnum]->attalign == 'd') ?
430 DOUBLEALIGN(off) : INTALIGN(off);
435 off = SHORTALIGN(off);
441 if (att[attnum]->attlen < sizeof(int32))
442 elog(ERROR, "nocache_index_getattr: attribute %d has len %d",
443 attnum, att[attnum]->attlen);
444 if (att[attnum]->attalign == 'd')
445 off = DOUBLEALIGN(off);
447 off = LONGALIGN(off);
451 return (Datum) fetchatt(&att[attnum], tp + off);
456 FormRetrieveIndexResult(ItemPointer indexItemPointer,
457 ItemPointer heapItemPointer)
459 RetrieveIndexResult result;
461 Assert(ItemPointerIsValid(indexItemPointer));
462 Assert(ItemPointerIsValid(heapItemPointer));
464 result = (RetrieveIndexResult) palloc(sizeof *result);
466 result->index_iptr = *indexItemPointer;
467 result->heap_iptr = *heapItemPointer;
473 * Copies source into target. If *target == NULL, we palloc space; otherwise
474 * we assume we have space that is already palloc'ed.
477 CopyIndexTuple(IndexTuple source, IndexTuple *target)
482 size = IndexTupleSize(source);
485 *target = (IndexTuple) palloc(size);
489 memmove((char *) ret, (char *) source, size);