aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gist
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/gist')
-rw-r--r--src/backend/access/gist/gist.c41
-rw-r--r--src/backend/access/gist/gistget.c8
-rw-r--r--src/backend/access/gist/gistscan.c13
-rw-r--r--src/backend/access/gist/gistsplit.c14
-rw-r--r--src/backend/access/gist/gistutil.c53
5 files changed, 100 insertions, 29 deletions
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 5ea774661a9..2ce5425ef98 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -75,7 +75,7 @@ gisthandler(PG_FUNCTION_ARGS)
amroutine->amclusterable = true;
amroutine->ampredlocks = true;
amroutine->amcanparallel = false;
- amroutine->amcaninclude = false;
+ amroutine->amcaninclude = true;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = gistbuild;
@@ -1382,8 +1382,10 @@ gistSplit(Relation r,
IndexTupleSize(itup[0]), GiSTPageSize,
RelationGetRelationName(r))));
- memset(v.spl_lisnull, true, sizeof(bool) * giststate->tupdesc->natts);
- memset(v.spl_risnull, true, sizeof(bool) * giststate->tupdesc->natts);
+ memset(v.spl_lisnull, true,
+ sizeof(bool) * giststate->nonLeafTupdesc->natts);
+ memset(v.spl_risnull, true,
+ sizeof(bool) * giststate->nonLeafTupdesc->natts);
gistSplitByKey(r, page, itup, len, giststate, &v, 0);
/* form left and right vector */
@@ -1461,9 +1463,23 @@ initGISTstate(Relation index)
giststate->scanCxt = scanCxt;
giststate->tempCxt = scanCxt; /* caller must change this if needed */
- giststate->tupdesc = index->rd_att;
+ giststate->leafTupdesc = index->rd_att;
- for (i = 0; i < index->rd_att->natts; i++)
+ /*
+ * The truncated tupdesc for non-leaf index tuples, which doesn't contain
+ * the INCLUDE attributes.
+ *
+ * It is used to form tuples during tuple adjustement and page split.
+ * B-tree creates shortened tuple descriptor for every truncated tuple,
+ * because it is doing this less often: it does not have to form truncated
+ * tuples during page split. Also, B-tree is not adjusting tuples on
+ * internal pages the way GiST does.
+ */
+ giststate->nonLeafTupdesc = CreateTupleDescCopyConstr(index->rd_att);
+ giststate->nonLeafTupdesc->natts =
+ IndexRelationGetNumberOfKeyAttributes(index);
+
+ for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(index); i++)
{
fmgr_info_copy(&(giststate->consistentFn[i]),
index_getprocinfo(index, i + 1, GIST_CONSISTENT_PROC),
@@ -1531,6 +1547,21 @@ initGISTstate(Relation index)
giststate->supportCollation[i] = DEFAULT_COLLATION_OID;
}
+ /* No opclass information for INCLUDE attributes */
+ for (; i < index->rd_att->natts; i++)
+ {
+ giststate->consistentFn[i].fn_oid = InvalidOid;
+ giststate->unionFn[i].fn_oid = InvalidOid;
+ giststate->compressFn[i].fn_oid = InvalidOid;
+ giststate->decompressFn[i].fn_oid = InvalidOid;
+ giststate->penaltyFn[i].fn_oid = InvalidOid;
+ giststate->picksplitFn[i].fn_oid = InvalidOid;
+ giststate->equalFn[i].fn_oid = InvalidOid;
+ giststate->distanceFn[i].fn_oid = InvalidOid;
+ giststate->fetchFn[i].fn_oid = InvalidOid;
+ giststate->supportCollation[i] = InvalidOid;
+ }
+
MemoryContextSwitchTo(oldCxt);
return giststate;
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index a96ef5c3acc..156b9d699f7 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -164,7 +164,7 @@ gistindex_keytest(IndexScanDesc scan,
datum = index_getattr(tuple,
key->sk_attno,
- giststate->tupdesc,
+ giststate->leafTupdesc,
&isNull);
if (key->sk_flags & SK_ISNULL)
@@ -244,7 +244,7 @@ gistindex_keytest(IndexScanDesc scan,
datum = index_getattr(tuple,
key->sk_attno,
- giststate->tupdesc,
+ giststate->leafTupdesc,
&isNull);
if ((key->sk_flags & SK_ISNULL) || isNull)
@@ -769,11 +769,13 @@ gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
*
* Opclasses that implement a fetch function support index-only scans.
* Opclasses without compression functions also support index-only scans.
+ * Included attributes always can be fetched for index-only scans.
*/
bool
gistcanreturn(Relation index, int attno)
{
- if (OidIsValid(index_getprocid(index, attno, GIST_FETCH_PROC)) ||
+ if (attno > IndexRelationGetNumberOfKeyAttributes(index) ||
+ OidIsValid(index_getprocid(index, attno, GIST_FETCH_PROC)) ||
!OidIsValid(index_getprocid(index, attno, GIST_COMPRESS_PROC)))
return true;
else
diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c
index 78a8ede7949..893d7765b6c 100644
--- a/src/backend/access/gist/gistscan.c
+++ b/src/backend/access/gist/gistscan.c
@@ -158,6 +158,7 @@ gistrescan(IndexScanDesc scan, ScanKey key, int nkeys,
if (scan->xs_want_itup && !scan->xs_hitupdesc)
{
int natts;
+ int nkeyatts;
int attno;
/*
@@ -167,13 +168,23 @@ gistrescan(IndexScanDesc scan, ScanKey key, int nkeys,
* types.
*/
natts = RelationGetNumberOfAttributes(scan->indexRelation);
+ nkeyatts = IndexRelationGetNumberOfKeyAttributes(scan->indexRelation);
so->giststate->fetchTupdesc = CreateTemplateTupleDesc(natts);
- for (attno = 1; attno <= natts; attno++)
+ for (attno = 1; attno <= nkeyatts; attno++)
{
TupleDescInitEntry(so->giststate->fetchTupdesc, attno, NULL,
scan->indexRelation->rd_opcintype[attno - 1],
-1, 0);
}
+
+ for (; attno <= natts; attno++)
+ {
+ /* taking opcintype from giststate->tupdesc */
+ TupleDescInitEntry(so->giststate->fetchTupdesc, attno, NULL,
+ TupleDescAttr(so->giststate->leafTupdesc,
+ attno - 1)->atttypid,
+ -1, 0);
+ }
scan->xs_hitupdesc = so->giststate->fetchTupdesc;
/* Also create a memory context that will hold the returned tuples */
diff --git a/src/backend/access/gist/gistsplit.c b/src/backend/access/gist/gistsplit.c
index f210e0c39f4..6a9c54d86ce 100644
--- a/src/backend/access/gist/gistsplit.c
+++ b/src/backend/access/gist/gistsplit.c
@@ -207,7 +207,7 @@ placeOne(Relation r, GISTSTATE *giststate, GistSplitVector *v,
gistDeCompressAtt(giststate, r, itup, NULL, (OffsetNumber) 0,
identry, isnull);
- for (; attno < giststate->tupdesc->natts; attno++)
+ for (; attno < giststate->nonLeafTupdesc->natts; attno++)
{
float lpenalty,
rpenalty;
@@ -485,7 +485,7 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
*/
v->spl_dontcare = NULL;
- if (attno + 1 < giststate->tupdesc->natts)
+ if (attno + 1 < giststate->nonLeafTupdesc->natts)
{
int NumDontCare;
@@ -639,7 +639,7 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len,
Datum datum;
bool IsNull;
- datum = index_getattr(itup[i - 1], attno + 1, giststate->tupdesc,
+ datum = index_getattr(itup[i - 1], attno + 1, giststate->leafTupdesc,
&IsNull);
gistdentryinit(giststate, attno, &(entryvec->vector[i]),
datum, r, page, i,
@@ -657,7 +657,7 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len,
*/
v->spl_risnull[attno] = v->spl_lisnull[attno] = true;
- if (attno + 1 < giststate->tupdesc->natts)
+ if (attno + 1 < giststate->nonLeafTupdesc->natts)
gistSplitByKey(r, page, itup, len, giststate, v, attno + 1);
else
gistSplitHalf(&v->splitVector, len);
@@ -683,7 +683,7 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len,
v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
/* Compute union keys, unless outer recursion level will handle it */
- if (attno == 0 && giststate->tupdesc->natts == 1)
+ if (attno == 0 && giststate->nonLeafTupdesc->natts == 1)
{
v->spl_dontcare = NULL;
gistunionsubkey(giststate, itup, v);
@@ -700,7 +700,7 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len,
* Splitting on attno column is not optimal, so consider
* redistributing don't-care tuples according to the next column
*/
- Assert(attno + 1 < giststate->tupdesc->natts);
+ Assert(attno + 1 < giststate->nonLeafTupdesc->natts);
if (v->spl_dontcare == NULL)
{
@@ -771,7 +771,7 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len,
* that PickSplit (or the special cases above) produced correct union
* datums.
*/
- if (attno == 0 && giststate->tupdesc->natts > 1)
+ if (attno == 0 && giststate->nonLeafTupdesc->natts > 1)
{
v->spl_dontcare = NULL;
gistunionsubkey(giststate, itup, v);
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 8d3dfad27bd..f32e16eed58 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -160,7 +160,7 @@ gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len,
evec = (GistEntryVector *) palloc((len + 2) * sizeof(GISTENTRY) + GEVHDRSZ);
- for (i = 0; i < giststate->tupdesc->natts; i++)
+ for (i = 0; i < giststate->nonLeafTupdesc->natts; i++)
{
int j;
@@ -171,7 +171,8 @@ gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len,
Datum datum;
bool IsNull;
- datum = index_getattr(itvec[j], i + 1, giststate->tupdesc, &IsNull);
+ datum = index_getattr(itvec[j], i + 1, giststate->leafTupdesc,
+ &IsNull);
if (IsNull)
continue;
@@ -296,11 +297,11 @@ gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p,
{
int i;
- for (i = 0; i < r->rd_att->natts; i++)
+ for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
{
Datum datum;
- datum = index_getattr(tuple, i + 1, giststate->tupdesc, &isnull[i]);
+ datum = index_getattr(tuple, i + 1, giststate->leafTupdesc, &isnull[i]);
gistdentryinit(giststate, i, &attdata[i],
datum, r, p, o,
false, isnull[i]);
@@ -329,7 +330,7 @@ gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *gis
gistDeCompressAtt(giststate, r, addtup, NULL,
(OffsetNumber) 0, addentries, addisnull);
- for (i = 0; i < r->rd_att->natts; i++)
+ for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
{
gistMakeUnionKey(giststate, i,
oldentries + i, oldisnull[i],
@@ -442,14 +443,15 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
zero_penalty = true;
/* Loop over index attributes. */
- for (j = 0; j < r->rd_att->natts; j++)
+ for (j = 0; j < IndexRelationGetNumberOfKeyAttributes(r); j++)
{
Datum datum;
float usize;
bool IsNull;
/* Compute penalty for this column. */
- datum = index_getattr(itup, j + 1, giststate->tupdesc, &IsNull);
+ datum = index_getattr(itup, j + 1, giststate->leafTupdesc,
+ &IsNull);
gistdentryinit(giststate, j, &entry, datum, r, p, i,
false, IsNull);
usize = gistpenalty(giststate, j, &entry, IsNull,
@@ -470,7 +472,7 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
result = i;
best_penalty[j] = usize;
- if (j < r->rd_att->natts - 1)
+ if (j < IndexRelationGetNumberOfKeyAttributes(r) - 1)
best_penalty[j + 1] = -1;
/* we have new best, so reset keep-it decision */
@@ -500,7 +502,7 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
* If we looped past the last column, and did not update "result",
* then this tuple is exactly as good as the prior best tuple.
*/
- if (j == r->rd_att->natts && result != i)
+ if (j == IndexRelationGetNumberOfKeyAttributes(r) && result != i)
{
if (keep_current_best == -1)
{
@@ -579,7 +581,7 @@ gistFormTuple(GISTSTATE *giststate, Relation r,
/*
* Call the compress method on each attribute.
*/
- for (i = 0; i < r->rd_att->natts; i++)
+ for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
{
if (isnull[i])
compatt[i] = (Datum) 0;
@@ -602,7 +604,23 @@ gistFormTuple(GISTSTATE *giststate, Relation r,
}
}
- res = index_form_tuple(giststate->tupdesc, compatt, isnull);
+ if (isleaf)
+ {
+ /*
+ * Emplace each included attribute if any.
+ */
+ for (; i < r->rd_att->natts; i++)
+ {
+ if (isnull[i])
+ compatt[i] = (Datum) 0;
+ else
+ compatt[i] = attdata[i];
+ }
+ }
+
+ res = index_form_tuple(isleaf ? giststate->leafTupdesc :
+ giststate->nonLeafTupdesc,
+ compatt, isnull);
/*
* The offset number on tuples on internal pages is unused. For historical
@@ -644,11 +662,11 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
bool isnull[INDEX_MAX_KEYS];
int i;
- for (i = 0; i < r->rd_att->natts; i++)
+ for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
{
Datum datum;
- datum = index_getattr(tuple, i + 1, giststate->tupdesc, &isnull[i]);
+ datum = index_getattr(tuple, i + 1, giststate->leafTupdesc, &isnull[i]);
if (giststate->fetchFn[i].fn_oid != InvalidOid)
{
@@ -679,6 +697,15 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
fetchatt[i] = (Datum) 0;
}
}
+
+ /*
+ * Get each included attribute.
+ */
+ for (; i < r->rd_att->natts; i++)
+ {
+ fetchatt[i] = index_getattr(tuple, i + 1, giststate->leafTupdesc,
+ &isnull[i]);
+ }
MemoryContextSwitchTo(oldcxt);
return heap_form_tuple(giststate->fetchTupdesc, fetchatt, isnull);