diff options
Diffstat (limited to 'src/backend/access/spgist')
-rw-r--r-- | src/backend/access/spgist/spgdoinsert.c | 41 | ||||
-rw-r--r-- | src/backend/access/spgist/spgutils.c | 62 |
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); |