Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 303a732

Browse files
committed
Ported toast support for include from 9.6 branch
1 parent adec831 commit 303a732

File tree

14 files changed

+189
-14
lines changed

14 files changed

+189
-14
lines changed

src/backend/access/common/indextuple.c

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,25 @@ IndexTuple
3838
index_form_tuple(TupleDesc tupleDescriptor,
3939
Datum *values,
4040
bool *isnull)
41+
{
42+
return index_form_tuple_extended(tupleDescriptor, values, isnull, tupleDescriptor->natts, NULL);
43+
}
44+
45+
/*
46+
* Workhorse for index_form_tuple().
47+
* This function is needed primarily to avoid de-toasting of the
48+
* included attributes for indexes with included columns.
49+
*
50+
* If sz_check_failed == NULL, then in case of tuple being too big we will print
51+
* an error. If it's a pointer to a bool, then we won't print an error but we will
52+
* make the bool TRUE if the tuple is too big and FALSE if it's all good.
53+
*/
54+
IndexTuple
55+
index_form_tuple_extended(TupleDesc tupleDescriptor,
56+
Datum *values,
57+
bool *isnull,
58+
int nkeyattrs,
59+
bool *sz_check_failed)
4160
{
4261
char *tp; /* tuple pointer */
4362
IndexTuple tuple; /* return tuple */
@@ -61,6 +80,8 @@ index_form_tuple(TupleDesc tupleDescriptor,
6180
errmsg("number of index columns (%d) exceeds limit (%d)",
6281
numberOfAttributes, INDEX_MAX_KEYS)));
6382

83+
Assert (nkeyattrs <= tupleDescriptor->natts);
84+
6485
#ifdef TOAST_INDEX_HACK
6586
for (i = 0; i < numberOfAttributes; i++)
6687
{
@@ -73,6 +94,10 @@ index_form_tuple(TupleDesc tupleDescriptor,
7394
if (isnull[i] || att->attlen != -1)
7495
continue;
7596

97+
/* Do not de-toast included attibutes. */
98+
if (i >= nkeyattrs)
99+
continue;
100+
76101
/*
77102
* If value is stored EXTERNAL, must fetch it so we are not depending
78103
* on outside storage. This should be improved someday.
@@ -133,6 +158,7 @@ index_form_tuple(TupleDesc tupleDescriptor,
133158
tp = (char *) palloc0(size);
134159
tuple = (IndexTuple) tp;
135160

161+
136162
heap_fill_tuple(tupleDescriptor,
137163
#ifdef TOAST_INDEX_HACK
138164
untoasted_values,
@@ -162,20 +188,23 @@ index_form_tuple(TupleDesc tupleDescriptor,
162188
if (tupmask & HEAP_HASVARWIDTH)
163189
infomask |= INDEX_VAR_MASK;
164190

165-
/* Also assert we got rid of external attributes */
166-
#ifdef TOAST_INDEX_HACK
167-
Assert((tupmask & HEAP_HASEXTERNAL) == 0);
168-
#endif
169-
170191
/*
171192
* Here we make sure that the size will fit in the field reserved for it
172193
* in t_info.
173194
*/
195+
if(sz_check_failed)
196+
*sz_check_failed = false;
197+
174198
if ((size & INDEX_SIZE_MASK) != size)
175-
ereport(ERROR,
176-
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
177-
errmsg("index row requires %zu bytes, maximum size is %zu",
178-
size, (Size) INDEX_SIZE_MASK)));
199+
{
200+
if(sz_check_failed)
201+
*sz_check_failed = true;
202+
else
203+
ereport(ERROR,
204+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
205+
errmsg("index row requires %zu bytes, maximum size is %zu",
206+
size, (Size) INDEX_SIZE_MASK)));
207+
}
179208

180209
infomask |= size;
181210

src/backend/access/nbtree/nbtinsert.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,48 @@ static bool _bt_isequal(TupleDesc itupdesc, Page page, OffsetNumber offnum,
8585
static void _bt_vacuum_one_page(Relation rel, Buffer buffer, Relation heapRel);
8686

8787

88+
/*
89+
* tuple_too_long_for_btree() -- returns TRUE if too long, FALSE if not
90+
*
91+
* Code for the check taken from _bt_findinsertloc() and _bt_doinsert()
92+
*/
93+
bool
94+
tuple_too_long_for_btree(Relation rel, IndexTuple itup)
95+
{
96+
Buffer buf;
97+
Page page;
98+
Size itemsz;
99+
int indnkeyatts;
100+
ScanKey itup_scankey;
101+
BTStack stack;
102+
103+
Assert(IndexRelationGetNumberOfAttributes(rel) != 0);
104+
indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
105+
Assert(indnkeyatts != 0);
106+
107+
itup_scankey = _bt_mkscankey(rel, itup);
108+
109+
stack = _bt_search(rel, indnkeyatts, itup_scankey, false, &buf, BT_WRITE, NULL);
110+
111+
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
112+
LockBuffer(buf, BT_WRITE);
113+
114+
buf = _bt_moveright(rel, buf, indnkeyatts, itup_scankey, false,
115+
true, stack, BT_WRITE, NULL);
116+
117+
itemsz = IndexTupleDSize(*itup);
118+
itemsz = MAXALIGN(itemsz);
119+
120+
page = BufferGetPage(buf);
121+
122+
_bt_relbuf(rel, buf);
123+
124+
if (itemsz > BTMaxItemSize(page))
125+
return true;
126+
127+
return false;
128+
}
129+
88130
/*
89131
* _bt_doinsert() -- Handle insertion of a single index tuple in the tree.
90132
*

src/backend/access/nbtree/nbtree.c

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "access/relscan.h"
2323
#include "access/xlog.h"
2424
#include "access/ptrack.h"
25+
#include "executor/executor.h" /* for using CreateExecutorState */
2526
#include "catalog/index.h"
2627
#include "commands/vacuum.h"
2728
#include "pgstat.h"
@@ -116,6 +117,8 @@ static void btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
116117
BTCycleId cycleid);
117118
static void btvacuumpage(BTVacState *vstate, BlockNumber blkno,
118119
BlockNumber orig_blkno);
120+
static void bt_get_data_from_heap(Relation rel, Datum *values, bool *isnull,
121+
ItemPointer ht_ctid, Relation heapRel);
119122

120123

121124
/*
@@ -328,9 +331,27 @@ btinsert(Relation rel, Datum *values, bool *isnull,
328331
{
329332
bool result;
330333
IndexTuple itup;
334+
int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
335+
int indnatts = IndexRelationGetNumberOfAttributes(rel);
336+
TupleDesc tupleDescIndex = RelationGetDescr(rel);
337+
bool data_too_long_for_making_a_tup = true;
338+
339+
340+
/* Forming an index tuple from the values[] and isnull[] arrays */
341+
itup = index_form_tuple_extended(tupleDescIndex, values, isnull, indnkeyatts, &data_too_long_for_making_a_tup);
342+
343+
/* If we discovered that there's an INCLUDED attribute, AND that the data is too big to fit
344+
* in the index, we will take the data for building right from the heap. We do it because this
345+
* way we can get actual TOAST links rather than detoasted data. We want TOAST links becacuse we
346+
* might want to let INCLUDED attributes stay toasted when being put into the index.
347+
*/
348+
if((indnatts != indnkeyatts) && (data_too_long_for_making_a_tup || tuple_too_long_for_btree(rel, itup)) )
349+
{
350+
pfree(itup);
351+
bt_get_data_from_heap(rel, values, isnull, ht_ctid, heapRel);
352+
itup = index_form_tuple_extended(tupleDescIndex, values, isnull, indnkeyatts, NULL);
353+
}
331354

332-
/* generate an index tuple */
333-
itup = index_form_tuple(RelationGetDescr(rel), values, isnull);
334355
itup->t_tid = *ht_ctid;
335356

336357
result = _bt_doinsert(rel, itup, checkUnique, heapRel);
@@ -472,6 +493,51 @@ btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
472493
return ntids;
473494
}
474495

496+
/*
497+
* Taking the data for building an index tuple right from the heap.
498+
* We do it in case if detoasted data turned out to be too long, because
499+
* this way we can get actual TOAST links rather than detoasted data.
500+
* We need it only becacuse we might want to let INCLUDED
501+
* attributes stay toasted when being put into the index.
502+
*
503+
* It will form data for btree tuple and put it into values[] and isnull[]
504+
*/
505+
void
506+
bt_get_data_from_heap(Relation rel, Datum *values, bool *isnull,
507+
ItemPointer ht_ctid, Relation heapRel)
508+
{
509+
TupleDesc tupleDescHeap = RelationGetDescr(heapRel);
510+
HeapTupleData htup;
511+
Buffer buffer;
512+
513+
htup.t_self = *ht_ctid;
514+
515+
/* Getting the tuple that we want to form an index tuple with from the heap */
516+
if (!heap_fetch(heapRel, SnapshotAny, &htup, &buffer, false, NULL))
517+
elog(ERROR, "failed to fetch tuple dy tid while tring to insert a tuple into btree");
518+
else
519+
{
520+
EState *estate = CreateExecutorState();
521+
IndexInfo *indexInfo = BuildIndexInfo(rel);
522+
TupleTableSlot *slot;
523+
/*
524+
* We put the tuple taken from the heap into a slot,
525+
* and then FormIndexDatum takes the data from that slot
526+
* and fills the values[] and isnull[] arrays with the
527+
* appropriate values for the column(s) of the index.
528+
* IndexInfo explains the structure of the index tuple.
529+
*/
530+
slot = MakeSingleTupleTableSlot(tupleDescHeap);
531+
ExecStoreTuple(&htup, slot, InvalidBuffer, false);
532+
533+
FormIndexDatum(indexInfo, slot, estate,
534+
values, isnull);
535+
536+
ExecDropSingleTupleTableSlot(slot);
537+
ReleaseBuffer(buffer);
538+
}
539+
}
540+
475541
/*
476542
* btbeginscan() -- start a scan on a btree index
477543
*/

src/backend/utils/sort/tuplesort.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1411,8 +1411,10 @@ tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel,
14111411
SortTuple stup;
14121412
Datum original;
14131413
IndexTuple tuple;
1414+
int indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
1415+
1416+
stup.tuple = index_form_tuple_extended(RelationGetDescr(rel), values, isnull, indnkeyatts, NULL);
14141417

1415-
stup.tuple = index_form_tuple(RelationGetDescr(rel), values, isnull);
14161418
tuple = ((IndexTuple) stup.tuple);
14171419
tuple->t_tid = *self;
14181420
USEMEM(state, GetMemoryChunkSpace(stup.tuple));

src/include/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
/pg_config_ext.h
55
/pg_config_os.h
66
/dynloader.h
7+
/commit_id.h

src/include/access/itup.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ typedef IndexAttributeBitMapData * IndexAttributeBitMap;
143143
/* routines in indextuple.c */
144144
extern IndexTuple index_form_tuple(TupleDesc tupleDescriptor,
145145
Datum *values, bool *isnull);
146+
extern IndexTuple index_form_tuple_extended(TupleDesc tupleDescriptor,
147+
Datum *values, bool *isnull, int nkeyattrs, bool *sz_check_failed);
146148
extern Datum nocache_index_getattr(IndexTuple tup, int attnum,
147149
TupleDesc tupleDesc);
148150
extern void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor,

src/include/access/nbtree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ extern Buffer _bt_getstackbuf(Relation rel, BTStack stack, int access);
473473
extern void _bt_finish_split(Relation rel, Buffer bbuf, BTStack stack);
474474
extern bool _bt_pgaddtup(Page page, Size itemsize, IndexTuple itup,
475475
OffsetNumber itup_off);
476-
476+
extern bool tuple_too_long_for_btree(Relation rel, IndexTuple itup);
477477
/*
478478
* prototypes for functions in nbtpage.c
479479
*/

src/test/regress/data/btree_long_included_atts.data

Lines changed: 2 additions & 0 deletions
Large diffs are not rendered by default.

src/test/regress/expected/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/btree_long_included_atts.out
12
/constraints.out
23
/copy.out
34
/create_function_1.out
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CREATE TABLE dt_news_tmp (
2+
"ID" bigint,
3+
"Preview" text,
4+
"Body" text,
5+
"IsLink" integer,
6+
"Link" character varying(255),
7+
"IsYandex" integer
8+
);
9+
10+
COPY dt_news_tmp ("ID", "Preview", "Body", "IsLink", "Link", "IsYandex") FROM '@abs_srcdir@/data/btree_long_included_atts.data';
11+
12+
CREATE INDEX "IX_DT_NEWS_DTA01" ON dt_news_tmp("ID" ) INCLUDE ("Preview","IsLink","Link");
13+
14+
COPY dt_news_tmp ("ID", "Preview", "Body", "IsLink", "Link", "IsYandex") FROM '@abs_srcdir@/data/btree_long_included_atts.data';
15+
16+
drop table dt_news_tmp;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CREATE TABLE dt_news_tmp (
2+
"ID" bigint,
3+
"Preview" text,
4+
"Body" text,
5+
"IsLink" integer,
6+
"Link" character varying(255),
7+
"IsYandex" integer
8+
);
9+
COPY dt_news_tmp ("ID", "Preview", "Body", "IsLink", "Link", "IsYandex") FROM '@abs_srcdir@/data/btree_long_included_atts.data';
10+
CREATE INDEX "IX_DT_NEWS_DTA01" ON dt_news_tmp("ID" ) INCLUDE ("Preview","IsLink","Link");
11+
COPY dt_news_tmp ("ID", "Preview", "Body", "IsLink", "Link", "IsYandex") FROM '@abs_srcdir@/data/btree_long_included_atts.data';
12+
drop table dt_news_tmp;

src/test/regress/parallel_schedule

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ ignore: random
7979
# ----------
8080
# Another group of parallel tests
8181
# ----------
82-
test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts delete
82+
test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index btree_long_included_atts hash_index update namespace prepared_xacts delete
8383

8484
# ----------
8585
# Another group of parallel tests

src/test/regress/serial_schedule

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ test: random
9999
test: portals
100100
test: arrays
101101
test: btree_index
102+
test: btree_long_included_atts
102103
test: hash_index
103104
test: update
104105
test: delete

src/test/regress/sql/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/btree_long_included_atts.sql
12
/constraints.sql
23
/copy.sql
34
/create_function_1.sql

0 commit comments

Comments
 (0)