Skip to content
Snippets Groups Projects
Select Git revision
  • benchmark-tools
  • postgres-lambda
  • master default
  • REL9_4_25
  • REL9_5_20
  • REL9_6_16
  • REL_10_11
  • REL_11_6
  • REL_12_1
  • REL_12_0
  • REL_12_RC1
  • REL_12_BETA4
  • REL9_4_24
  • REL9_5_19
  • REL9_6_15
  • REL_10_10
  • REL_11_5
  • REL_12_BETA3
  • REL9_4_23
  • REL9_5_18
  • REL9_6_14
  • REL_10_9
  • REL_11_4
23 results

indextuple.c

Blame
  • indextuple.c 10.69 KiB
    /*-------------------------------------------------------------------------
     *
     * indextuple.c--
     *	   This file contains index tuple accessor and mutator routines,
     *	   as well as a few various tuple utilities.
     *
     * Copyright (c) 1994, Regents of the University of California
     *
     *
     * IDENTIFICATION
     *	  $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.28 1998/02/26 04:29:18 momjian Exp $
     *
     *-------------------------------------------------------------------------
     */
    
    #include <postgres.h>
    
    #include <access/heapam.h>
    #include <access/ibit.h>
    #include <access/itup.h>
    #include <access/tupmacs.h>
    #include <catalog/pg_type.h>
    
    #ifndef HAVE_MEMMOVE
    #include <regex/utils.h>
    #else
    #include <string.h>
    #endif
    
    /* ----------------------------------------------------------------
     *				  index_ tuple interface routines
     * ----------------------------------------------------------------
     */
    
    /* ----------------
     *		index_formtuple
     * ----------------
     */
    IndexTuple
    index_formtuple(TupleDesc tupleDescriptor,
    				Datum value[],
    				char null[])
    {
    	char	   *tp;				/* tuple pointer */
    	IndexTuple	tuple;			/* return tuple */
    	Size		size,
    				hoff;
    	int			i;
    	unsigned short infomask = 0;
    	bool		hasnull = false;
    	uint16		tupmask = 0;
    	int			numberOfAttributes = tupleDescriptor->natts;
    
    	if (numberOfAttributes > MaxIndexAttributeNumber)
    		elog(ERROR, "index_formtuple: numberOfAttributes of %d > %d",
    			 numberOfAttributes, MaxIndexAttributeNumber);
    
    
    	for (i = 0; i < numberOfAttributes && !hasnull; i++)
    	{
    		if (null[i] != ' ')
    			hasnull = true;
    	}
    
    	if (hasnull)
    		infomask |= INDEX_NULL_MASK;
    
    	hoff = IndexInfoFindDataOffset(infomask);
    	size = hoff
    		+ ComputeDataSize(tupleDescriptor,
    						  value, null);
    	size = DOUBLEALIGN(size);	/* be conservative */
    
    	tp = (char *) palloc(size);
    	tuple = (IndexTuple) tp;
    	MemSet(tp, 0, (int) size);
    
    	DataFill((char *) tp + hoff,
    			 tupleDescriptor,
    			 value,
    			 null,
    			 &tupmask,
    			 (hasnull ? (bits8 *) tp + sizeof(*tuple) : NULL));
    
    	/*
    	 * We do this because DataFill wants to initialize a "tupmask" which
    	 * is used for HeapTuples, but we want an indextuple infomask.	The
    	 * only "relevent" info is the "has variable attributes" field, which
    	 * is in mask position 0x02.  We have already set the null mask above.
    	 */
    
    	if (tupmask & 0x02)
    		infomask |= INDEX_VAR_MASK;
    
    	/*
    	 * Here we make sure that we can actually hold the size.  We also want
    	 * to make sure that size is not aligned oddly.  This actually is a
    	 * rather odd way to make sure the size is not too large overall.
    	 */
    
    	if (size & 0xE000)
    		elog(ERROR, "index_formtuple: data takes %d bytes: too big", size);
    
    
    	infomask |= size;
    
    	/* ----------------
    	 * initialize metadata
    	 * ----------------
    	 */
    	tuple->t_info = infomask;
    	return (tuple);
    }
    
    /* ----------------
     *		nocache_index_getattr
     *
     *		This gets called from index_getattr() macro, and only in cases
     *		where we can't use cacheoffset and the value is not null.
     *
     *		This caches attribute offsets in the attribute descriptor.
     *
     *		an alternate way to speed things up would be to cache offsets
     *		with the tuple, but that seems more difficult unless you take
     *		the storage hit of actually putting those offsets into the
     *		tuple you send to disk.  Yuck.
     *
     *		This scheme will be slightly slower than that, but should
     *		preform well for queries which hit large #'s of tuples.  After
     *		you cache the offsets once, examining all the other tuples using
     *		the same attribute descriptor will go much quicker. -cim 5/4/91
     * ----------------
     */
    Datum
    nocache_index_getattr(IndexTuple tup,
    					  int attnum,
    					  TupleDesc tupleDesc,
    					  bool *isnull)
    {
    	char	   *tp;				/* ptr to att in tuple */
    	char	   *bp = NULL;		/* ptr to att in tuple */
    	int			slow;			/* do we have to walk nulls? */
    	int			data_off;		/* tuple data offset */
    	AttributeTupleForm *att = tupleDesc->attrs;
    
    	/* ----------------
    	 *	sanity checks
    	 * ----------------
    	 */
    
    	/* ----------------
    	 *	 Three cases:
    	 *
    	 *	 1: No nulls and no variable length attributes.
    	 *	 2: Has a null or a varlena AFTER att.
    	 *	 3: Has nulls or varlenas BEFORE att.
    	 * ----------------
    	 */
    
    #ifdef IN_MACRO
    /* This is handled in the macro */
    	Assert(PointerIsValid(isnull));
    	Assert(attnum > 0);
    
    	*isnull = false;
    #endif
    
    	data_off = IndexTupleHasMinHeader(tup) ? sizeof *tup :
    		IndexInfoFindDataOffset(tup->t_info);
    
    	if (IndexTupleNoNulls(tup))
    	{
    		attnum--;
    
    #ifdef IN_MACRO
    /* This is handled in the macro */
    
    		/* first attribute is always at position zero */
    
    		if (attnum == 1)
    		{
    			return (Datum) fetchatt(&(att[0]), (char *) tup + data_off);
    		}
    		if (att[attnum]->attcacheoff != -1)
    		{
    			return (Datum) fetchatt(&(att[attnum]),
    									(char *) tup + data_off +
    									att[attnum]->attcacheoff);
    		}
    #endif
    
    		slow = 0;
    	}
    	else
    	{							/* there's a null somewhere in the tuple */
    
    		slow = 0;
    		/* ----------------
    		 *		check to see if desired att is null
    		 * ----------------
    		 */
    
    		attnum--;
    
    		bp = (char *) tup + sizeof(*tup);		/* "knows" t_bits are
    												 * here! */
    #ifdef IN_MACRO
    /* This is handled in the macro */
    
    		if (att_isnull(attnum, bp))
    		{
    			*isnull = true;
    			return (Datum) NULL;
    		}
    #endif
    
    		/* ----------------
    		 *		Now check to see if any preceeding bits are null...
    		 * ----------------
    		 */
    		{
    			int			i = 0;	/* current offset in bp */
    			int			mask;	/* bit in byte we're looking at */
    			char		n;		/* current byte in bp */
    			int			byte,
    						finalbit;
    
    			byte = attnum >> 3;
    			finalbit = attnum & 0x07;
    
    			for (; i <= byte && !slow; i++)
    			{
    				n = bp[i];
    				if (i < byte)
    				{
    					/* check for nulls in any "earlier" bytes */
    					if ((~n) != 0)
    						slow = 1;
    				}
    				else
    				{
    					/* check for nulls "before" final bit of last byte */
    					mask = (1 << finalbit) - 1;
    					if ((~n) & mask)
    						slow = 1;
    				}
    			}
    		}
    	}
    
    	tp = (char *) tup + data_off;
    
    	/* now check for any non-fixed length attrs before our attribute */
    
    	if (!slow)
    	{
    		if (att[attnum]->attcacheoff != -1)
    		{
    			return (Datum) fetchatt(&(att[attnum]),
    									tp + att[attnum]->attcacheoff);
    		}
    		else if (attnum == 0)
    		{
    			return ((Datum) fetchatt(&(att[0]), (char *) tp));
    		}
    		else if (!IndexTupleAllFixed(tup))
    		{
    			int			j = 0;
    
    			for (j = 0; j < attnum && !slow; j++)
    				if (att[j]->attlen < 1 && !VARLENA_FIXED_SIZE(att[j]))
    					slow = 1;
    		}
    	}
    
    	/*
    	 * if slow is zero, and we got here, we know that we have a tuple with
    	 * no nulls.  We also know that we have to initialize the remainder of
    	 * the attribute cached offset values.
    	 */
    
    	if (!slow)
    	{
    		int			j = 1;
    		long		off;
    
    		/*
    		 * need to set cache for some atts
    		 */
    
    		att[0]->attcacheoff = 0;
    
    		while (att[j]->attcacheoff != -1)
    			j++;
    
    		if (!VARLENA_FIXED_SIZE(att[j - 1]))
    			off = att[j - 1]->attcacheoff + att[j - 1]->attlen;
    		else
    			off = att[j - 1]->attcacheoff + att[j - 1]->atttypmod;
    
    		for (; j < attnum + 1; j++)
    		{
    
    			/*
    			 * Fix me when going to a machine with more than a four-byte
    			 * word!
    			 */
    
    			switch (att[j]->attlen)
    			{
    				case -1:
    					off = (att[j]->attalign == 'd') ?
    						DOUBLEALIGN(off) : INTALIGN(off);
    					break;
    				case sizeof(char):
    					break;
    				case sizeof(short):
    					off = SHORTALIGN(off);
    					break;
    				case sizeof(int32):
    					off = INTALIGN(off);
    					break;
    				default:
    					if (att[j]->attlen > sizeof(int32))
    						off = (att[j]->attalign == 'd') ?
    							DOUBLEALIGN(off) : LONGALIGN(off);
    					else
    						elog(ERROR, "nocache_index_getattr: attribute %d has len %d",
    							 j, att[j]->attlen);
    					break;
    
    			}
    
    			att[j]->attcacheoff = off;
    
    			/* The only varlena/-1 length value to get here is this */
    			if (!VARLENA_FIXED_SIZE(att[j]))
    				off += att[j]->attlen;
    			else
    			{
    				Assert(att[j]->atttypmod == VARSIZE(tp + off));
    				off += att[j]->atttypmod;
    			}
    		}
    
    		return (Datum) fetchatt(&(att[attnum]), tp + att[attnum]->attcacheoff);
    	}
    	else
    	{
    		bool		usecache = true;
    		int			off = 0;
    		int			i;
    
    		/*
    		 * Now we know that we have to walk the tuple CAREFULLY.
    		 */
    
    		for (i = 0; i < attnum; i++)
    		{
    			if (!IndexTupleNoNulls(tup))
    			{
    				if (att_isnull(i, bp))
    				{
    					usecache = false;
    					continue;
    				}
    			}
    
    			/* If we know the next offset, we can skip the rest */
    			if (usecache && att[i]->attcacheoff != -1)
    				off = att[i]->attcacheoff;
    			else
    			{
    				switch (att[i]->attlen)
    				{
    					case -1:
    						off = (att[i]->attalign == 'd') ?
    							DOUBLEALIGN(off) : INTALIGN(off);
    						break;
    					case sizeof(char):
    						break;
    					case sizeof(short):
    						off = SHORTALIGN(off);
    						break;
    					case sizeof(int32):
    						off = INTALIGN(off);
    						break;
    					default:
    						if (att[i]->attlen < sizeof(int32))
    							elog(ERROR,
    							 "nocachegetiattr2: attribute %d has len %d",
    								 i, att[i]->attlen);
    						if (att[i]->attalign == 'd')
    							off = DOUBLEALIGN(off);
    						else
    							off = LONGALIGN(off);
    						break;
    				}
    				if (usecache)
    					att[i]->attcacheoff = off;
    			}
    
    			switch (att[i]->attlen)
    			{
    				case sizeof(char):
    					off++;
    					break;
    				case sizeof(short):
    					off += sizeof(short);
    					break;
    				case sizeof(int32):
    					off += sizeof(int32);
    					break;
    				case -1:
    					Assert(!VARLENA_FIXED_SIZE(att[i]) ||
    						   att[i]->atttypmod == VARSIZE(tp + off));
    					off += VARSIZE(tp + off);
    					if (!VARLENA_FIXED_SIZE(att[i]))
    						usecache = false;
    					break;
    				default:
    					off += att[i]->attlen;
    					break;
    			}
    		}
    
    		switch (att[attnum]->attlen)
    		{
    			case -1:
    				off = (att[attnum]->attalign == 'd') ?
    					DOUBLEALIGN(off) : INTALIGN(off);
    				break;
    			case sizeof(char):
    				break;
    			case sizeof(short):
    				off = SHORTALIGN(off);
    				break;
    			case sizeof(int32):
    				off = INTALIGN(off);
    				break;
    			default:
    				if (att[attnum]->attlen < sizeof(int32))
    					elog(ERROR, "nocache_index_getattr: attribute %d has len %d",
    						 attnum, att[attnum]->attlen);
    				if (att[attnum]->attalign == 'd')
    					off = DOUBLEALIGN(off);
    				else
    					off = LONGALIGN(off);
    				break;
    		}
    
    		return (Datum) fetchatt(&att[attnum], tp + off);
    	}
    }
    
    RetrieveIndexResult
    FormRetrieveIndexResult(ItemPointer indexItemPointer,
    						ItemPointer heapItemPointer)
    {
    	RetrieveIndexResult result;
    
    	Assert(ItemPointerIsValid(indexItemPointer));
    	Assert(ItemPointerIsValid(heapItemPointer));
    
    	result = (RetrieveIndexResult) palloc(sizeof *result);
    
    	result->index_iptr = *indexItemPointer;
    	result->heap_iptr = *heapItemPointer;
    
    	return (result);
    }
    
    /*
     * Copies source into target.  If *target == NULL, we palloc space; otherwise
     * we assume we have space that is already palloc'ed.
     */
    void
    CopyIndexTuple(IndexTuple source, IndexTuple *target)
    {
    	Size		size;
    	IndexTuple	ret;
    
    	size = IndexTupleSize(source);
    	if (*target == NULL)
    	{
    		*target = (IndexTuple) palloc(size);
    	}
    
    	ret = *target;
    	memmove((char *) ret, (char *) source, size);
    }