PostgreSQL Source Code  git master
brin_tuple.c
Go to the documentation of this file.
1 /*
2  * brin_tuple.c
3  * Method implementations for tuples in BRIN indexes.
4  *
5  * Intended usage is that code outside this file only deals with
6  * BrinMemTuples, and convert to and from the on-disk representation through
7  * functions in this file.
8  *
9  * NOTES
10  *
11  * A BRIN tuple is similar to a heap tuple, with a few key differences. The
12  * first interesting difference is that the tuple header is much simpler, only
13  * containing its total length and a small area for flags. Also, the stored
14  * data does not match the relation tuple descriptor exactly: for each
15  * attribute in the descriptor, the index tuple carries an arbitrary number
16  * of values, depending on the opclass.
17  *
18  * Also, for each column of the index relation there are two null bits: one
19  * (hasnulls) stores whether any tuple within the page range has that column
20  * set to null; the other one (allnulls) stores whether the column values are
21  * all null. If allnulls is true, then the tuple data area does not contain
22  * values for that column at all; whereas it does if the hasnulls is set.
23  * Note the size of the null bitmask may not be the same as that of the
24  * datum array.
25  *
26  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
27  * Portions Copyright (c) 1994, Regents of the University of California
28  *
29  * IDENTIFICATION
30  * src/backend/access/brin/brin_tuple.c
31  */
32 #include "postgres.h"
33 
34 #include "access/brin_tuple.h"
35 #include "access/htup_details.h"
36 #include "access/tupdesc.h"
37 #include "access/tupmacs.h"
38 #include "utils/datum.h"
39 #include "utils/memutils.h"
40 
41 static inline void brin_deconstruct_tuple(BrinDesc *brdesc,
42  char *tp, bits8 *nullbits, bool nulls,
43  Datum *values, bool *allnulls, bool *hasnulls);
44 
45 
46 /*
47  * Return a tuple descriptor used for on-disk storage of BRIN tuples.
48  */
49 static TupleDesc
51 {
52  /* We cache these in the BrinDesc */
53  if (brdesc->bd_disktdesc == NULL)
54  {
55  int i;
56  int j;
57  AttrNumber attno = 1;
58  TupleDesc tupdesc;
59  MemoryContext oldcxt;
60 
61  /* make sure it's in the bdesc's context */
62  oldcxt = MemoryContextSwitchTo(brdesc->bd_context);
63 
64  tupdesc = CreateTemplateTupleDesc(brdesc->bd_totalstored);
65 
66  for (i = 0; i < brdesc->bd_tupdesc->natts; i++)
67  {
68  for (j = 0; j < brdesc->bd_info[i]->oi_nstored; j++)
69  TupleDescInitEntry(tupdesc, attno++, NULL,
70  brdesc->bd_info[i]->oi_typcache[j]->type_id,
71  -1, 0);
72  }
73 
74  MemoryContextSwitchTo(oldcxt);
75 
76  brdesc->bd_disktdesc = tupdesc;
77  }
78 
79  return brdesc->bd_disktdesc;
80 }
81 
82 /*
83  * Generate a new on-disk tuple to be inserted in a BRIN index.
84  *
85  * See brin_form_placeholder_tuple if you touch this.
86  */
87 BrinTuple *
89  Size *size)
90 {
91  Datum *values;
92  bool *nulls;
93  bool anynulls = false;
94  BrinTuple *rettuple;
95  int keyno;
96  int idxattno;
97  uint16 phony_infomask = 0;
98  bits8 *phony_nullbitmap;
99  Size len,
100  hoff,
101  data_len;
102 
103  Assert(brdesc->bd_totalstored > 0);
104 
105  values = (Datum *) palloc(sizeof(Datum) * brdesc->bd_totalstored);
106  nulls = (bool *) palloc0(sizeof(bool) * brdesc->bd_totalstored);
107  phony_nullbitmap = (bits8 *)
108  palloc(sizeof(bits8) * BITMAPLEN(brdesc->bd_totalstored));
109 
110  /*
111  * Set up the values/nulls arrays for heap_fill_tuple
112  */
113  idxattno = 0;
114  for (keyno = 0; keyno < brdesc->bd_tupdesc->natts; keyno++)
115  {
116  int datumno;
117 
118  /*
119  * "allnulls" is set when there's no nonnull value in any row in the
120  * column; when this happens, there is no data to store. Thus set the
121  * nullable bits for all data elements of this column and we're done.
122  */
123  if (tuple->bt_columns[keyno].bv_allnulls)
124  {
125  for (datumno = 0;
126  datumno < brdesc->bd_info[keyno]->oi_nstored;
127  datumno++)
128  nulls[idxattno++] = true;
129  anynulls = true;
130  continue;
131  }
132 
133  /*
134  * The "hasnulls" bit is set when there are some null values in the
135  * data. We still need to store a real value, but the presence of
136  * this means we need a null bitmap.
137  */
138  if (tuple->bt_columns[keyno].bv_hasnulls)
139  anynulls = true;
140 
141  for (datumno = 0;
142  datumno < brdesc->bd_info[keyno]->oi_nstored;
143  datumno++)
144  values[idxattno++] = tuple->bt_columns[keyno].bv_values[datumno];
145  }
146 
147  /* Assert we did not overrun temp arrays */
148  Assert(idxattno <= brdesc->bd_totalstored);
149 
150  /* compute total space needed */
151  len = SizeOfBrinTuple;
152  if (anynulls)
153  {
154  /*
155  * We need a double-length bitmap on an on-disk BRIN index tuple; the
156  * first half stores the "allnulls" bits, the second stores
157  * "hasnulls".
158  */
159  len += BITMAPLEN(brdesc->bd_tupdesc->natts * 2);
160  }
161 
162  len = hoff = MAXALIGN(len);
163 
164  data_len = heap_compute_data_size(brtuple_disk_tupdesc(brdesc),
165  values, nulls);
166  len += data_len;
167 
168  len = MAXALIGN(len);
169 
170  rettuple = palloc0(len);
171  rettuple->bt_blkno = blkno;
172  rettuple->bt_info = hoff;
173 
174  /* Assert that hoff fits in the space available */
175  Assert((rettuple->bt_info & BRIN_OFFSET_MASK) == hoff);
176 
177  /*
178  * The infomask and null bitmap as computed by heap_fill_tuple are useless
179  * to us. However, that function will not accept a null infomask; and we
180  * need to pass a valid null bitmap so that it will correctly skip
181  * outputting null attributes in the data area.
182  */
184  values,
185  nulls,
186  (char *) rettuple + hoff,
187  data_len,
188  &phony_infomask,
189  phony_nullbitmap);
190 
191  /* done with these */
192  pfree(values);
193  pfree(nulls);
194  pfree(phony_nullbitmap);
195 
196  /*
197  * Now fill in the real null bitmasks. allnulls first.
198  */
199  if (anynulls)
200  {
201  bits8 *bitP;
202  int bitmask;
203 
204  rettuple->bt_info |= BRIN_NULLS_MASK;
205 
206  /*
207  * Note that we reverse the sense of null bits in this module: we
208  * store a 1 for a null attribute rather than a 0. So we must reverse
209  * the sense of the att_isnull test in brin_deconstruct_tuple as well.
210  */
211  bitP = ((bits8 *) ((char *) rettuple + SizeOfBrinTuple)) - 1;
212  bitmask = HIGHBIT;
213  for (keyno = 0; keyno < brdesc->bd_tupdesc->natts; keyno++)
214  {
215  if (bitmask != HIGHBIT)
216  bitmask <<= 1;
217  else
218  {
219  bitP += 1;
220  *bitP = 0x0;
221  bitmask = 1;
222  }
223 
224  if (!tuple->bt_columns[keyno].bv_allnulls)
225  continue;
226 
227  *bitP |= bitmask;
228  }
229  /* hasnulls bits follow */
230  for (keyno = 0; keyno < brdesc->bd_tupdesc->natts; keyno++)
231  {
232  if (bitmask != HIGHBIT)
233  bitmask <<= 1;
234  else
235  {
236  bitP += 1;
237  *bitP = 0x0;
238  bitmask = 1;
239  }
240 
241  if (!tuple->bt_columns[keyno].bv_hasnulls)
242  continue;
243 
244  *bitP |= bitmask;
245  }
246  bitP = ((bits8 *) (rettuple + SizeOfBrinTuple)) - 1;
247  }
248 
249  if (tuple->bt_placeholder)
250  rettuple->bt_info |= BRIN_PLACEHOLDER_MASK;
251 
252  *size = len;
253  return rettuple;
254 }
255 
256 /*
257  * Generate a new on-disk tuple with no data values, marked as placeholder.
258  *
259  * This is a cut-down version of brin_form_tuple.
260  */
261 BrinTuple *
263 {
264  Size len;
265  Size hoff;
266  BrinTuple *rettuple;
267  int keyno;
268  bits8 *bitP;
269  int bitmask;
270 
271  /* compute total space needed: always add nulls */
272  len = SizeOfBrinTuple;
273  len += BITMAPLEN(brdesc->bd_tupdesc->natts * 2);
274  len = hoff = MAXALIGN(len);
275 
276  rettuple = palloc0(len);
277  rettuple->bt_blkno = blkno;
278  rettuple->bt_info = hoff;
280 
281  bitP = ((bits8 *) ((char *) rettuple + SizeOfBrinTuple)) - 1;
282  bitmask = HIGHBIT;
283  /* set allnulls true for all attributes */
284  for (keyno = 0; keyno < brdesc->bd_tupdesc->natts; keyno++)
285  {
286  if (bitmask != HIGHBIT)
287  bitmask <<= 1;
288  else
289  {
290  bitP += 1;
291  *bitP = 0x0;
292  bitmask = 1;
293  }
294 
295  *bitP |= bitmask;
296  }
297  /* no need to set hasnulls */
298 
299  *size = len;
300  return rettuple;
301 }
302 
303 /*
304  * Free a tuple created by brin_form_tuple
305  */
306 void
308 {
309  pfree(tuple);
310 }
311 
312 /*
313  * Given a brin tuple of size len, create a copy of it. If 'dest' is not
314  * NULL, its size is destsz, and can be used as output buffer; if the tuple
315  * to be copied does not fit, it is enlarged by repalloc, and the size is
316  * updated to match. This avoids palloc/free cycles when many brin tuples
317  * are being processed in loops.
318  */
319 BrinTuple *
321 {
322  if (!destsz || *destsz == 0)
323  dest = palloc(len);
324  else if (len > *destsz)
325  {
326  dest = repalloc(dest, len);
327  *destsz = len;
328  }
329 
330  memcpy(dest, tuple, len);
331 
332  return dest;
333 }
334 
335 /*
336  * Return whether two BrinTuples are bitwise identical.
337  */
338 bool
339 brin_tuples_equal(const BrinTuple *a, Size alen, const BrinTuple *b, Size blen)
340 {
341  if (alen != blen)
342  return false;
343  if (memcmp(a, b, alen) != 0)
344  return false;
345  return true;
346 }
347 
348 /*
349  * Create a new BrinMemTuple from scratch, and initialize it to an empty
350  * state.
351  *
352  * Note: we don't provide any means to free a deformed tuple, so make sure to
353  * use a temporary memory context.
354  */
355 BrinMemTuple *
357 {
358  BrinMemTuple *dtup;
359  long basesize;
360 
361  basesize = MAXALIGN(sizeof(BrinMemTuple) +
362  sizeof(BrinValues) * brdesc->bd_tupdesc->natts);
363  dtup = palloc0(basesize + sizeof(Datum) * brdesc->bd_totalstored);
364 
365  dtup->bt_values = palloc(sizeof(Datum) * brdesc->bd_totalstored);
366  dtup->bt_allnulls = palloc(sizeof(bool) * brdesc->bd_tupdesc->natts);
367  dtup->bt_hasnulls = palloc(sizeof(bool) * brdesc->bd_tupdesc->natts);
368 
370  "brin dtuple",
372 
373  brin_memtuple_initialize(dtup, brdesc);
374 
375  return dtup;
376 }
377 
378 /*
379  * Reset a BrinMemTuple to initial state. We return the same tuple, for
380  * notational convenience.
381  */
382 BrinMemTuple *
384 {
385  int i;
386  char *currdatum;
387 
389 
390  currdatum = (char *) dtuple +
391  MAXALIGN(sizeof(BrinMemTuple) +
392  sizeof(BrinValues) * brdesc->bd_tupdesc->natts);
393  for (i = 0; i < brdesc->bd_tupdesc->natts; i++)
394  {
395  dtuple->bt_columns[i].bv_allnulls = true;
396  dtuple->bt_columns[i].bv_hasnulls = false;
397 
398  dtuple->bt_columns[i].bv_attno = i + 1;
399  dtuple->bt_columns[i].bv_allnulls = true;
400  dtuple->bt_columns[i].bv_hasnulls = false;
401  dtuple->bt_columns[i].bv_values = (Datum *) currdatum;
402  currdatum += sizeof(Datum) * brdesc->bd_info[i]->oi_nstored;
403  }
404 
405  return dtuple;
406 }
407 
408 /*
409  * Convert a BrinTuple back to a BrinMemTuple. This is the reverse of
410  * brin_form_tuple.
411  *
412  * As an optimization, the caller can pass a previously allocated 'dMemtuple'.
413  * This avoids having to allocate it here, which can be useful when this
414  * function is called many times in a loop. It is caller's responsibility
415  * that the given BrinMemTuple matches what we need here.
416  *
417  * Note we don't need the "on disk tupdesc" here; we rely on our own routine to
418  * deconstruct the tuple from the on-disk format.
419  */
420 BrinMemTuple *
421 brin_deform_tuple(BrinDesc *brdesc, BrinTuple *tuple, BrinMemTuple *dMemtuple)
422 {
423  BrinMemTuple *dtup;
424  Datum *values;
425  bool *allnulls;
426  bool *hasnulls;
427  char *tp;
428  bits8 *nullbits;
429  int keyno;
430  int valueno;
431  MemoryContext oldcxt;
432 
433  dtup = dMemtuple ? brin_memtuple_initialize(dMemtuple, brdesc) :
434  brin_new_memtuple(brdesc);
435 
436  if (BrinTupleIsPlaceholder(tuple))
437  dtup->bt_placeholder = true;
438  dtup->bt_blkno = tuple->bt_blkno;
439 
440  values = dtup->bt_values;
441  allnulls = dtup->bt_allnulls;
442  hasnulls = dtup->bt_hasnulls;
443 
444  tp = (char *) tuple + BrinTupleDataOffset(tuple);
445 
446  if (BrinTupleHasNulls(tuple))
447  nullbits = (bits8 *) ((char *) tuple + SizeOfBrinTuple);
448  else
449  nullbits = NULL;
450  brin_deconstruct_tuple(brdesc,
451  tp, nullbits, BrinTupleHasNulls(tuple),
452  values, allnulls, hasnulls);
453 
454  /*
455  * Iterate to assign each of the values to the corresponding item in the
456  * values array of each column. The copies occur in the tuple's context.
457  */
458  oldcxt = MemoryContextSwitchTo(dtup->bt_context);
459  for (valueno = 0, keyno = 0; keyno < brdesc->bd_tupdesc->natts; keyno++)
460  {
461  int i;
462 
463  if (allnulls[keyno])
464  {
465  valueno += brdesc->bd_info[keyno]->oi_nstored;
466  continue;
467  }
468 
469  /*
470  * We would like to skip datumCopy'ing the values datum in some cases,
471  * caller permitting ...
472  */
473  for (i = 0; i < brdesc->bd_info[keyno]->oi_nstored; i++)
474  dtup->bt_columns[keyno].bv_values[i] =
475  datumCopy(values[valueno++],
476  brdesc->bd_info[keyno]->oi_typcache[i]->typbyval,
477  brdesc->bd_info[keyno]->oi_typcache[i]->typlen);
478 
479  dtup->bt_columns[keyno].bv_hasnulls = hasnulls[keyno];
480  dtup->bt_columns[keyno].bv_allnulls = false;
481  }
482 
483  MemoryContextSwitchTo(oldcxt);
484 
485  return dtup;
486 }
487 
488 /*
489  * brin_deconstruct_tuple
490  * Guts of attribute extraction from an on-disk BRIN tuple.
491  *
492  * Its arguments are:
493  * brdesc BRIN descriptor for the stored tuple
494  * tp pointer to the tuple data area
495  * nullbits pointer to the tuple nulls bitmask
496  * nulls "has nulls" bit in tuple infomask
497  * values output values, array of size brdesc->bd_totalstored
498  * allnulls output "allnulls", size brdesc->bd_tupdesc->natts
499  * hasnulls output "hasnulls", size brdesc->bd_tupdesc->natts
500  *
501  * Output arrays must have been allocated by caller.
502  */
503 static inline void
505  char *tp, bits8 *nullbits, bool nulls,
506  Datum *values, bool *allnulls, bool *hasnulls)
507 {
508  int attnum;
509  int stored;
510  TupleDesc diskdsc;
511  long off;
512 
513  /*
514  * First iterate to natts to obtain both null flags for each attribute.
515  * Note that we reverse the sense of the att_isnull test, because we store
516  * 1 for a null value (rather than a 1 for a not null value as is the
517  * att_isnull convention used elsewhere.) See brin_form_tuple.
518  */
519  for (attnum = 0; attnum < brdesc->bd_tupdesc->natts; attnum++)
520  {
521  /*
522  * the "all nulls" bit means that all values in the page range for
523  * this column are nulls. Therefore there are no values in the tuple
524  * data area.
525  */
526  allnulls[attnum] = nulls && !att_isnull(attnum, nullbits);
527 
528  /*
529  * the "has nulls" bit means that some tuples have nulls, but others
530  * have not-null values. Therefore we know the tuple contains data
531  * for this column.
532  *
533  * The hasnulls bits follow the allnulls bits in the same bitmask.
534  */
535  hasnulls[attnum] =
536  nulls && !att_isnull(brdesc->bd_tupdesc->natts + attnum, nullbits);
537  }
538 
539  /*
540  * Iterate to obtain each attribute's stored values. Note that since we
541  * may reuse attribute entries for more than one column, we cannot cache
542  * offsets here.
543  */
544  diskdsc = brtuple_disk_tupdesc(brdesc);
545  stored = 0;
546  off = 0;
547  for (attnum = 0; attnum < brdesc->bd_tupdesc->natts; attnum++)
548  {
549  int datumno;
550 
551  if (allnulls[attnum])
552  {
553  stored += brdesc->bd_info[attnum]->oi_nstored;
554  continue;
555  }
556 
557  for (datumno = 0;
558  datumno < brdesc->bd_info[attnum]->oi_nstored;
559  datumno++)
560  {
561  Form_pg_attribute thisatt = TupleDescAttr(diskdsc, stored);
562 
563  if (thisatt->attlen == -1)
564  {
565  off = att_align_pointer(off, thisatt->attalign, -1,
566  tp + off);
567  }
568  else
569  {
570  /* not varlena, so safe to use att_align_nominal */
571  off = att_align_nominal(off, thisatt->attalign);
572  }
573 
574  values[stored++] = fetchatt(thisatt, tp + off);
575 
576  off = att_addlength_pointer(off, thisatt->attlen, tp + off);
577  }
578  }
579 }
#define BRIN_OFFSET_MASK
Definition: brin_tuple.h:76
#define BrinTupleIsPlaceholder(tup)
Definition: brin_tuple.h:83
void heap_fill_tuple(TupleDesc tupleDesc, Datum *values, bool *isnull, char *data, Size data_size, uint16 *infomask, bits8 *bit)
Definition: heaptuple.c:304
struct BrinValues BrinValues
#define SizeOfBrinTuple
Definition: brin_tuple.h:71
#define AllocSetContextCreate
Definition: memutils.h:170
#define BrinTupleHasNulls(tup)
Definition: brin_tuple.h:82
#define att_align_nominal(cur_offset, attalign)
Definition: tupmacs.h:146
BrinTuple * brin_copy_tuple(BrinTuple *tuple, Size len, BrinTuple *dest, Size *destsz)
Definition: brin_tuple.c:320
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
#define att_isnull(ATT, BITS)
Definition: tupmacs.h:23
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
BlockNumber bt_blkno
Definition: brin_tuple.h:39
bool bv_allnulls
Definition: brin_tuple.h:28
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
uint32 BlockNumber
Definition: block.h:31
#define BITMAPLEN(NATTS)
Definition: htup_details.h:547
BrinMemTuple * brin_new_memtuple(BrinDesc *brdesc)
Definition: brin_tuple.c:356
int16 typlen
Definition: typcache.h:37
bool typbyval
Definition: typcache.h:38
#define fetchatt(A, T)
Definition: tupmacs.h:39
BrinMemTuple * brin_deform_tuple(BrinDesc *brdesc, BrinTuple *tuple, BrinMemTuple *dMemtuple)
Definition: brin_tuple.c:421
Datum * bt_values
Definition: brin_tuple.h:42
unsigned short uint16
Definition: c.h:358
void pfree(void *pointer)
Definition: mcxt.c:1056
static TupleDesc brtuple_disk_tupdesc(BrinDesc *brdesc)
Definition: brin_tuple.c:50
bool bt_placeholder
Definition: brin_tuple.h:38
bool bv_hasnulls
Definition: brin_tuple.h:27
TypeCacheEntry * oi_typcache[FLEXIBLE_ARRAY_MEMBER]
Definition: brin_internal.h:34
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
AttrNumber bv_attno
Definition: brin_tuple.h:26
uint16 oi_nstored
Definition: brin_internal.h:28
int bd_totalstored
Definition: brin_internal.h:56
static void brin_deconstruct_tuple(BrinDesc *brdesc, char *tp, bits8 *nullbits, bool nulls, Datum *values, bool *allnulls, bool *hasnulls)
Definition: brin_tuple.c:504
bool brin_tuples_equal(const BrinTuple *a, Size alen, const BrinTuple *b, Size blen)
Definition: brin_tuple.c:339
BrinValues bt_columns[FLEXIBLE_ARRAY_MEMBER]
Definition: brin_tuple.h:46
#define BRIN_NULLS_MASK
Definition: brin_tuple.h:79
TupleDesc bd_tupdesc
Definition: brin_internal.h:50
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
bool * bt_hasnulls
Definition: brin_tuple.h:44
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603
#define att_addlength_pointer(cur_offset, attlen, attptr)
Definition: tupmacs.h:174
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
#define HIGHBIT
Definition: c.h:1105
#define BRIN_PLACEHOLDER_MASK
Definition: brin_tuple.h:78
uint8 bits8
Definition: c.h:366
void * palloc0(Size size)
Definition: mcxt.c:980
uintptr_t Datum
Definition: postgres.h:367
#define att_align_pointer(cur_offset, attalign, attlen, attptr)
Definition: tupmacs.h:124
BrinOpcInfo * bd_info[FLEXIBLE_ARRAY_MEMBER]
Definition: brin_internal.h:59
int16 attnum
Definition: pg_attribute.h:79
BlockNumber bt_blkno
Definition: brin_tuple.h:57
void brin_free_tuple(BrinTuple *tuple)
Definition: brin_tuple.c:307
#define Assert(condition)
Definition: c.h:739
bool * bt_allnulls
Definition: brin_tuple.h:43
size_t Size
Definition: c.h:467
#define MAXALIGN(LEN)
Definition: c.h:692
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
Size heap_compute_data_size(TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:119
MemoryContext bd_context
Definition: brin_internal.h:44
static Datum values[MAXATTR]
Definition: bootstrap.c:167
uint8 bt_info
Definition: brin_tuple.h:68
void * palloc(Size size)
Definition: mcxt.c:949
TupleDesc bd_disktdesc
Definition: brin_internal.h:53
BrinTuple * brin_form_tuple(BrinDesc *brdesc, BlockNumber blkno, BrinMemTuple *tuple, Size *size)
Definition: brin_tuple.c:88
#define BrinTupleDataOffset(tup)
Definition: brin_tuple.h:81
int i
Datum * bv_values
Definition: brin_tuple.h:29
BrinTuple * brin_form_placeholder_tuple(BrinDesc *brdesc, BlockNumber blkno, Size *size)
Definition: brin_tuple.c:262
int16 AttrNumber
Definition: attnum.h:21
BrinMemTuple * brin_memtuple_initialize(BrinMemTuple *dtuple, BrinDesc *brdesc)
Definition: brin_tuple.c:383
MemoryContext bt_context
Definition: brin_tuple.h:40