aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/spgist
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/spgist')
-rw-r--r--src/backend/access/spgist/spgdoinsert.c41
-rw-r--r--src/backend/access/spgist/spgutils.c62
2 files changed, 71 insertions, 32 deletions
diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c
index 7bd269fd2a0..e14c71abd07 100644
--- a/src/backend/access/spgist/spgdoinsert.c
+++ b/src/backend/access/spgist/spgdoinsert.c
@@ -731,13 +731,6 @@ doPickSplit(Relation index, SpGistState *state,
* also, count up the amount of space that will be freed from current.
* (Note that in the non-root case, we won't actually delete the old
* tuples, only replace them with redirects or placeholders.)
- *
- * Note: the SGLTDATUM calls here are safe even when dealing with a nulls
- * page. For a pass-by-value data type we will fetch a word that must
- * exist even though it may contain garbage (because of the fact that leaf
- * tuples must have size at least SGDTSIZE). For a pass-by-reference type
- * we are just computing a pointer that isn't going to get dereferenced.
- * So it's not worth guarding the calls with isNulls checks.
*/
nToInsert = 0;
nToDelete = 0;
@@ -757,7 +750,8 @@ doPickSplit(Relation index, SpGistState *state,
PageGetItemId(current->page, i));
if (it->tupstate == SPGIST_LIVE)
{
- in.datums[nToInsert] = SGLTDATUM(it, state);
+ in.datums[nToInsert] =
+ isNulls ? (Datum) 0 : SGLTDATUM(it, state);
heapPtrs[nToInsert] = it->heapPtr;
nToInsert++;
toDelete[nToDelete] = i;
@@ -782,7 +776,8 @@ doPickSplit(Relation index, SpGistState *state,
PageGetItemId(current->page, i));
if (it->tupstate == SPGIST_LIVE)
{
- in.datums[nToInsert] = SGLTDATUM(it, state);
+ in.datums[nToInsert] =
+ isNulls ? (Datum) 0 : SGLTDATUM(it, state);
heapPtrs[nToInsert] = it->heapPtr;
nToInsert++;
toDelete[nToDelete] = i;
@@ -814,7 +809,8 @@ doPickSplit(Relation index, SpGistState *state,
* space to include it; and in any case it has to be included in the input
* for the picksplit function. So don't increment nToInsert yet.
*/
- in.datums[in.nTuples] = SGLTDATUM(newLeafTuple, state);
+ in.datums[in.nTuples] =
+ isNulls ? (Datum) 0 : SGLTDATUM(newLeafTuple, state);
heapPtrs[in.nTuples] = newLeafTuple->heapPtr;
in.nTuples++;
@@ -1940,17 +1936,21 @@ spgdoinsert(Relation index, SpGistState *state,
leafDatum = (Datum) 0;
/*
- * Compute space needed for a leaf tuple containing the given datum.
- *
- * If it isn't gonna fit, and the opclass can't reduce the datum size by
- * suffixing, bail out now rather than getting into an endless loop.
+ * Compute space needed for a leaf tuple containing the given datum. This
+ * must match spgFormLeafTuple.
*/
+ leafSize = SGLTHDRSZ;
if (!isnull)
- leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
- SpGistGetTypeSize(&state->attLeafType, leafDatum);
- else
- leafSize = SGDTSIZE + sizeof(ItemIdData);
+ leafSize += SpGistGetLeafTypeSize(&state->attLeafType, leafDatum);
+ if (leafSize < SGDTSIZE)
+ leafSize = SGDTSIZE;
+ /* Account for an item pointer, too */
+ leafSize += sizeof(ItemIdData);
+ /*
+ * If it isn't gonna fit, and the opclass can't reduce the datum size by
+ * suffixing, bail out now rather than getting into an endless loop.
+ */
if (leafSize > SPGIST_PAGE_CAPACITY && !state->config.longValuesOK)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
@@ -2161,8 +2161,9 @@ spgdoinsert(Relation index, SpGistState *state,
if (!isnull)
{
leafDatum = out.result.matchNode.restDatum;
- leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
- SpGistGetTypeSize(&state->attLeafType, leafDatum);
+ leafSize = SGLTHDRSZ +
+ SpGistGetLeafTypeSize(&state->attLeafType, leafDatum);
+ leafSize += sizeof(ItemIdData);
}
/*
diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c
index d8b18150612..949352ada76 100644
--- a/src/backend/access/spgist/spgutils.c
+++ b/src/backend/access/spgist/spgutils.c
@@ -603,13 +603,14 @@ spgoptions(Datum reloptions, bool validate)
}
/*
- * Get the space needed to store a non-null datum of the indicated type.
+ * Get the space needed to store a non-null datum of the indicated type
+ * in an inner tuple (that is, as a prefix or node label).
* Note the result is already rounded up to a MAXALIGN boundary.
- * Also, we follow the SPGiST convention that pass-by-val types are
- * just stored in their Datum representation (compare memcpyDatum).
+ * Here we follow the convention that pass-by-val types are just stored
+ * in their Datum representation (compare memcpyInnerDatum).
*/
unsigned int
-SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
+SpGistGetInnerTypeSize(SpGistTypeDesc *att, Datum datum)
{
unsigned int size;
@@ -624,10 +625,28 @@ SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
}
/*
- * Copy the given non-null datum to *target
+ * Get the space needed to store a non-null datum of the indicated type
+ * in a leaf tuple. This is just the usual storage space for the type,
+ * but rounded up to a MAXALIGN boundary.
+ */
+unsigned int
+SpGistGetLeafTypeSize(SpGistTypeDesc *att, Datum datum)
+{
+ unsigned int size;
+
+ if (att->attlen > 0)
+ size = att->attlen;
+ else
+ size = VARSIZE_ANY(datum);
+
+ return MAXALIGN(size);
+}
+
+/*
+ * Copy the given non-null datum to *target, in the inner-tuple case
*/
static void
-memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
+memcpyInnerDatum(void *target, SpGistTypeDesc *att, Datum datum)
{
unsigned int size;
@@ -643,6 +662,25 @@ memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
}
/*
+ * Copy the given non-null datum to *target, in the leaf-tuple case
+ */
+static void
+memcpyLeafDatum(void *target, SpGistTypeDesc *att, Datum datum)
+{
+ unsigned int size;
+
+ if (att->attbyval)
+ {
+ store_att_byval(target, datum, att->attlen);
+ }
+ else
+ {
+ size = (att->attlen > 0) ? att->attlen : VARSIZE_ANY(datum);
+ memcpy(target, DatumGetPointer(datum), size);
+ }
+}
+
+/*
* Construct a leaf tuple containing the given heap TID and datum value
*/
SpGistLeafTuple
@@ -655,7 +693,7 @@ spgFormLeafTuple(SpGistState *state, ItemPointer heapPtr,
/* compute space needed (note result is already maxaligned) */
size = SGLTHDRSZ;
if (!isnull)
- size += SpGistGetTypeSize(&state->attLeafType, datum);
+ size += SpGistGetLeafTypeSize(&state->attLeafType, datum);
/*
* Ensure that we can replace the tuple with a dead tuple later. This
@@ -671,7 +709,7 @@ spgFormLeafTuple(SpGistState *state, ItemPointer heapPtr,
tup->nextOffset = InvalidOffsetNumber;
tup->heapPtr = *heapPtr;
if (!isnull)
- memcpyDatum(SGLTDATAPTR(tup), &state->attLeafType, datum);
+ memcpyLeafDatum(SGLTDATAPTR(tup), &state->attLeafType, datum);
return tup;
}
@@ -692,7 +730,7 @@ spgFormNodeTuple(SpGistState *state, Datum label, bool isnull)
/* compute space needed (note result is already maxaligned) */
size = SGNTHDRSZ;
if (!isnull)
- size += SpGistGetTypeSize(&state->attLabelType, label);
+ size += SpGistGetInnerTypeSize(&state->attLabelType, label);
/*
* Here we make sure that the size will fit in the field reserved for it
@@ -716,7 +754,7 @@ spgFormNodeTuple(SpGistState *state, Datum label, bool isnull)
ItemPointerSetInvalid(&tup->t_tid);
if (!isnull)
- memcpyDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
+ memcpyInnerDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
return tup;
}
@@ -736,7 +774,7 @@ spgFormInnerTuple(SpGistState *state, bool hasPrefix, Datum prefix,
/* Compute size needed */
if (hasPrefix)
- prefixSize = SpGistGetTypeSize(&state->attPrefixType, prefix);
+ prefixSize = SpGistGetInnerTypeSize(&state->attPrefixType, prefix);
else
prefixSize = 0;
@@ -781,7 +819,7 @@ spgFormInnerTuple(SpGistState *state, bool hasPrefix, Datum prefix,
tup->size = size;
if (hasPrefix)
- memcpyDatum(SGITDATAPTR(tup), &state->attPrefixType, prefix);
+ memcpyInnerDatum(SGITDATAPTR(tup), &state->attPrefixType, prefix);
ptr = (char *) SGITNODEPTR(tup);