Example #1
0
static IndexTuple
gistFormTuple(GISTSTATE *giststate, Relation r,
			  Datum attdata[], int datumsize[], bool isnull[])
{
	IndexTuple	tup;
	char		isnullchar[INDEX_MAX_KEYS];
	bool		whatfree[INDEX_MAX_KEYS];
	GISTENTRY	centry[INDEX_MAX_KEYS];
	Datum		compatt[INDEX_MAX_KEYS];
	int			j;

	for (j = 0; j < r->rd_att->natts; j++)
	{
		if (isnull[j])
		{
			isnullchar[j] = 'n';
			compatt[j] = (Datum) 0;
			whatfree[j] = FALSE;
		}
		else
		{
			gistcentryinit(giststate, j, &centry[j], attdata[j],
						   NULL, NULL, (OffsetNumber) 0,
						   datumsize[j], FALSE, FALSE);
			isnullchar[j] = ' ';
			compatt[j] = centry[j].key;
			if (!isAttByVal(giststate, j))
			{
				whatfree[j] = TRUE;
				if (centry[j].key != attdata[j])
					pfree(DatumGetPointer(attdata[j]));
			}
			else
				whatfree[j] = FALSE;
		}
	}

	tup = (IndexTuple) index_formtuple(giststate->tupdesc, compatt, isnullchar);
	for (j = 0; j < r->rd_att->natts; j++)
		if (whatfree[j])
			pfree(DatumGetPointer(compatt[j]));

	return tup;
}
Example #2
0
/*
 *	hashinsert() -- insert an index tuple into a hash table.
 *
 *	Hash on the index tuple's key, find the appropriate location
 *	for the new tuple, put it there, and return an InsertIndexResult
 *	to the caller.
 */
Datum
hashinsert(PG_FUNCTION_ARGS)
{
	Relation	rel = (Relation) PG_GETARG_POINTER(0);
	Datum	   *datum = (Datum *) PG_GETARG_POINTER(1);
	char	   *nulls = (char *) PG_GETARG_POINTER(2);
	ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);

#ifdef NOT_USED
	Relation	heapRel = (Relation) PG_GETARG_POINTER(4);
	bool		checkUnique = PG_GETARG_BOOL(5);
#endif
	InsertIndexResult res;
	HashItem	hitem;
	IndexTuple	itup;

	/* generate an index tuple */
	itup = index_formtuple(RelationGetDescr(rel), datum, nulls);
	itup->t_tid = *ht_ctid;

	/*
	 * If the single index key is null, we don't insert it into the index.
	 * Hash tables support scans on '='. Relational algebra says that A =
	 * B returns null if either A or B is null.  This means that no
	 * qualification used in an index scan could ever return true on a
	 * null attribute.	It also means that indices can't be used by ISNULL
	 * or NOTNULL scans, but that's an artifact of the strategy map
	 * architecture chosen in 1986, not of the way nulls are handled here.
	 */
	if (IndexTupleHasNulls(itup))
	{
		pfree(itup);
		PG_RETURN_POINTER((InsertIndexResult) NULL);
	}

	hitem = _hash_formitem(itup);

	res = _hash_doinsert(rel, hitem);

	pfree(hitem);
	pfree(itup);

	PG_RETURN_POINTER(res);
}
Example #3
0
/*
** Given an IndexTuple to be inserted on a page, this routine replaces
** the key with another key, which may involve generating a new IndexTuple
** if the sizes don't match or if the null status changes.
**
** XXX this only works for a single-column index tuple!
*/
static IndexTuple
gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t)
{
	bool		IsNull;
	Datum		datum = index_getattr(t, 1, r->rd_att, &IsNull);

	/*
	 * If new entry fits in index tuple, copy it in.  To avoid worrying
	 * about null-value bitmask, pass it off to the general
	 * index_formtuple routine if either the previous or new value is
	 * NULL.
	 */
	if (!IsNull && DatumGetPointer(entry.key) != NULL &&
		(Size) entry.bytes <= ATTSIZE(datum, r, 1, IsNull))
	{
		memcpy(DatumGetPointer(datum),
			   DatumGetPointer(entry.key),
			   entry.bytes);
		/* clear out old size */
		t->t_info &= ~INDEX_SIZE_MASK;
		/* or in new size */
		t->t_info |= MAXALIGN(entry.bytes + sizeof(IndexTupleData));

		return t;
	}
	else
	{
		/* generate a new index tuple for the compressed entry */
		TupleDesc	tupDesc = r->rd_att;
		IndexTuple	newtup;
		char		isnull;

		isnull = DatumGetPointer(entry.key) != NULL ? ' ' : 'n';
		newtup = (IndexTuple) index_formtuple(tupDesc,
											  &(entry.key),
											  &isnull);
		newtup->t_tid = t->t_tid;
		return newtup;
	}
}
Example #4
0
/*
 * Per-tuple callback from IndexBuildHeapScan
 */
static void
hashbuildCallback(Relation index,
				  HeapTuple htup,
				  Datum *attdata,
				  char *nulls,
				  bool tupleIsAlive,
				  void *state)
{
	HashBuildState *buildstate = (HashBuildState *) state;
	IndexTuple	itup;
	HashItem	hitem;
	InsertIndexResult res;

	/* form an index tuple and point it at the heap tuple */
	itup = index_formtuple(RelationGetDescr(index), attdata, nulls);
	itup->t_tid = htup->t_self;

	/* Hash indexes don't index nulls, see notes in hashinsert */
	if (IndexTupleHasNulls(itup))
	{
		pfree(itup);
		return;
	}

	hitem = _hash_formitem(itup);

	res = _hash_doinsert(index, hitem);

	if (res)
		pfree(res);

	buildstate->indtuples += 1;

	pfree(hitem);
	pfree(itup);
}
Example #5
0
/*
 * Forms union of oldtup and addtup, if union == oldtup then return NULL
 */
static IndexTuple
gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
{
	GistEntryVector *evec;
	Datum		datum;
	int			datumsize;
	bool		result,
				neednew = false;
	char		isnull[INDEX_MAX_KEYS],
				whatfree[INDEX_MAX_KEYS];
	Datum		attr[INDEX_MAX_KEYS];
	GISTENTRY	centry[INDEX_MAX_KEYS],
				oldatt[INDEX_MAX_KEYS],
				addatt[INDEX_MAX_KEYS],
			   *ev0p,
			   *ev1p;
	bool		olddec[INDEX_MAX_KEYS],
				adddec[INDEX_MAX_KEYS];
	bool		oldisnull[INDEX_MAX_KEYS],
				addisnull[INDEX_MAX_KEYS];
	IndexTuple	newtup = NULL;
	int			j;

	evec = palloc(2 * sizeof(GISTENTRY) + GEVHDRSZ);
	evec->n = 2;
	ev0p = &(evec->vector[0]);
	ev1p = &(evec->vector[1]);

	gistDeCompressAtt(giststate, r, oldtup, NULL,
					  (OffsetNumber) 0, oldatt, olddec, oldisnull);

	gistDeCompressAtt(giststate, r, addtup, NULL,
					  (OffsetNumber) 0, addatt, adddec, addisnull);


	for (j = 0; j < r->rd_att->natts; j++)
	{
		if (oldisnull[j] && addisnull[j])
		{
			isnull[j] = 'n';
			attr[j] = (Datum) 0;
			whatfree[j] = FALSE;
		}
		else
		{
			FILLEV(
				   oldisnull[j], oldatt[j].key, oldatt[j].bytes,
				   addisnull[j], addatt[j].key, addatt[j].bytes
				);

			datum = FunctionCall2(&giststate->unionFn[j],
								  PointerGetDatum(evec),
								  PointerGetDatum(&datumsize));

			if (oldisnull[j] || addisnull[j])
			{
				if (oldisnull[j])
					neednew = true;
			}
			else
			{
				FunctionCall3(&giststate->equalFn[j],
							  ev0p->key,
							  datum,
							  PointerGetDatum(&result));

				if (!result)
					neednew = true;
			}

			if (olddec[j])
				pfree(DatumGetPointer(oldatt[j].key));
			if (adddec[j])
				pfree(DatumGetPointer(addatt[j].key));

			gistcentryinit(giststate, j, &centry[j], datum,
						   NULL, NULL, (OffsetNumber) 0,
						   datumsize, FALSE, FALSE);

			isnull[j] = ' ';
			attr[j] = centry[j].key;
			if ((!isAttByVal(giststate, j)))
			{
				whatfree[j] = TRUE;
				if (centry[j].key != datum)
					pfree(DatumGetPointer(datum));
			}
			else
				whatfree[j] = FALSE;
		}
	}
	pfree(evec);

	if (neednew)
	{
		/* need to update key */
		newtup = (IndexTuple) index_formtuple(giststate->tupdesc, attr, isnull);
		newtup->t_tid = oldtup->t_tid;
	}

	for (j = 0; j < r->rd_att->natts; j++)
		if (whatfree[j])
			pfree(DatumGetPointer(attr[j]));

	return newtup;
}
Example #6
0
/*
 * return union of itup vector
 */
static IndexTuple
gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
{
	Datum		attr[INDEX_MAX_KEYS];
	bool		whatfree[INDEX_MAX_KEYS];
	char		isnull[INDEX_MAX_KEYS];
	GistEntryVector *evec;
	Datum		datum;
	int			datumsize,
				i,
				j;
	GISTENTRY	centry[INDEX_MAX_KEYS];
	bool	   *needfree;
	IndexTuple	newtup;
	bool		IsNull;
	int			reallen;

	needfree = (bool *) palloc(((len == 1) ? 2 : len) * sizeof(bool));
	evec = (GistEntryVector *) palloc(((len == 1) ? 2 : len) * sizeof(GISTENTRY) + GEVHDRSZ);

	for (j = 0; j < r->rd_att->natts; j++)
	{
		reallen = 0;
		for (i = 0; i < len; i++)
		{
			datum = index_getattr(itvec[i], j + 1, giststate->tupdesc, &IsNull);
			if (IsNull)
				continue;

			gistdentryinit(giststate, j,
						   &(evec->vector[reallen]),
						   datum,
						   NULL, NULL, (OffsetNumber) 0,
						   ATTSIZE(datum, giststate->tupdesc, j + 1, IsNull), FALSE, IsNull);
			if ((!isAttByVal(giststate, j)) &&
				evec->vector[reallen].key != datum)
				needfree[reallen] = TRUE;
			else
				needfree[reallen] = FALSE;
			reallen++;
		}

		if (reallen == 0)
		{
			attr[j] = (Datum) 0;
			isnull[j] = 'n';
			whatfree[j] = FALSE;
		}
		else
		{
			if (reallen == 1)
			{
				evec->n = 2;
				gistentryinit(evec->vector[1],
							  evec->vector[0].key, r, NULL,
						 (OffsetNumber) 0, evec->vector[0].bytes, FALSE);

			}
			else
				evec->n = reallen;
			datum = FunctionCall2(&giststate->unionFn[j],
								  PointerGetDatum(evec),
								  PointerGetDatum(&datumsize));

			for (i = 0; i < reallen; i++)
				if (needfree[i])
					pfree(DatumGetPointer(evec->vector[i].key));

			gistcentryinit(giststate, j, &centry[j], datum,
						   NULL, NULL, (OffsetNumber) 0,
						   datumsize, FALSE, FALSE);
			isnull[j] = ' ';
			attr[j] = centry[j].key;
			if (!isAttByVal(giststate, j))
			{
				whatfree[j] = TRUE;
				if (centry[j].key != datum)
					pfree(DatumGetPointer(datum));
			}
			else
				whatfree[j] = FALSE;
		}
	}

	pfree(evec);
	pfree(needfree);

	newtup = (IndexTuple) index_formtuple(giststate->tupdesc, attr, isnull);
	for (j = 0; j < r->rd_att->natts; j++)
		if (whatfree[j])
			pfree(DatumGetPointer(attr[j]));

	return newtup;
}
Example #7
0
/*
 *	gistinsert -- wrapper for GiST tuple insertion.
 *
 *	  This is the public interface routine for tuple insertion in GiSTs.
 *	  It doesn't do any work; just locks the relation and passes the buck.
 */
Datum
gistinsert(PG_FUNCTION_ARGS)
{
	Relation	r = (Relation) PG_GETARG_POINTER(0);
	Datum	   *datum = (Datum *) PG_GETARG_POINTER(1);
	char	   *nulls = (char *) PG_GETARG_POINTER(2);
	ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);

#ifdef NOT_USED
	Relation	heapRel = (Relation) PG_GETARG_POINTER(4);
	bool		checkUnique = PG_GETARG_BOOL(5);
#endif
	InsertIndexResult res;
	IndexTuple	itup;
	GISTSTATE	giststate;
	GISTENTRY	tmpentry;
	int			i;
	bool		compvec[INDEX_MAX_KEYS];

	/*
	 * Since GIST is not marked "amconcurrent" in pg_am, caller should
	 * have acquired exclusive lock on index relation.	We need no locking
	 * here.
	 */

	/* GiST cannot index tuples with leading NULLs */
	if (nulls[0] == 'n')
	{
		res = NULL;
		PG_RETURN_POINTER(res);
	}

	initGISTstate(&giststate, r);

	/* immediately compress keys to normalize */
	for (i = 0; i < r->rd_att->natts; i++)
	{
		if (nulls[i] == 'n')
		{
			datum[i] = (Datum) 0;
			compvec[i] = FALSE;
		}
		else
		{
			gistcentryinit(&giststate, i, &tmpentry, datum[i],
						   NULL, NULL, (OffsetNumber) 0,
						 -1 /* size is currently bogus */ , TRUE, FALSE);
			if (datum[i] != tmpentry.key && !(isAttByVal(&giststate, i)))
				compvec[i] = TRUE;
			else
				compvec[i] = FALSE;
			datum[i] = tmpentry.key;
		}
	}
	itup = index_formtuple(giststate.tupdesc, datum, nulls);
	itup->t_tid = *ht_ctid;

	res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
	gistdoinsert(r, itup, &res, &giststate);

	for (i = 0; i < r->rd_att->natts; i++)
		if (compvec[i] == TRUE)
			pfree(DatumGetPointer(datum[i]));
	pfree(itup);
	freeGISTstate(&giststate);

	PG_RETURN_POINTER(res);
}
Example #8
0
/*
 * Per-tuple callback from IndexBuildHeapScan
 */
static void
gistbuildCallback(Relation index,
				  HeapTuple htup,
				  Datum *attdata,
				  char *nulls,
				  bool tupleIsAlive,
				  void *state)
{
	GISTBuildState *buildstate = (GISTBuildState *) state;
	IndexTuple	itup;
	bool		compvec[INDEX_MAX_KEYS];
	GISTENTRY	tmpcentry;
	int			i;

	/* GiST cannot index tuples with leading NULLs */
	if (nulls[0] == 'n')
		return;

	/* immediately compress keys to normalize */
	for (i = 0; i < buildstate->numindexattrs; i++)
	{
		if (nulls[i] == 'n')
		{
			attdata[i] = (Datum) 0;
			compvec[i] = FALSE;
		}
		else
		{
			gistcentryinit(&buildstate->giststate, i, &tmpcentry, attdata[i],
						   NULL, NULL, (OffsetNumber) 0,
						 -1 /* size is currently bogus */ , TRUE, FALSE);
			if (attdata[i] != tmpcentry.key &&
				!(isAttByVal(&buildstate->giststate, i)))
				compvec[i] = TRUE;
			else
				compvec[i] = FALSE;
			attdata[i] = tmpcentry.key;
		}
	}

	/* form an index tuple and point it at the heap tuple */
	itup = index_formtuple(buildstate->giststate.tupdesc, attdata, nulls);
	itup->t_tid = htup->t_self;

	/*
	 * Since we already have the index relation locked, we call
	 * gistdoinsert directly.  Normal access method calls dispatch through
	 * gistinsert, which locks the relation for write.	This is the right
	 * thing to do if you're inserting single tups, but not when you're
	 * initializing the whole index at once.
	 */
	gistdoinsert(index, itup, NULL, &buildstate->giststate);

	buildstate->indtuples += 1;

	for (i = 0; i < buildstate->numindexattrs; i++)
		if (compvec[i])
			pfree(DatumGetPointer(attdata[i]));

	pfree(itup);
}