PostgreSQL Source Code git master
Loading...
Searching...
No Matches
brin_minmax_multi.c File Reference
#include "postgres.h"
#include <sys/socket.h>
#include "access/brin.h"
#include "access/brin_internal.h"
#include "access/brin_tuple.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/stratnum.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_type.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/datum.h"
#include "utils/float.h"
#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/pg_lsn.h"
#include "utils/rel.h"
#include "utils/syscache.h"
#include "utils/timestamp.h"
#include "utils/uuid.h"
Include dependency graph for brin_minmax_multi.c:

Go to the source code of this file.

Data Structures

struct  MinmaxMultiOpaque
 
struct  MinMaxMultiOptions
 
struct  Ranges
 
struct  SerializedRanges
 
struct  ExpandedRange
 
struct  DistanceValue
 
struct  compare_context
 

Macros

#define MINMAX_MAX_PROCNUMS   1 /* maximum support procs we need */
 
#define PROCNUM_DISTANCE   11 /* required, distance between values */
 
#define PROCNUM_BASE   11
 
#define MINMAX_BUFFER_FACTOR   10
 
#define MINMAX_BUFFER_MIN   256
 
#define MINMAX_BUFFER_MAX   8192
 
#define MINMAX_BUFFER_LOAD_FACTOR   0.5
 
#define MINMAX_MULTI_DEFAULT_VALUES_PER_PAGE   32
 
#define MinMaxMultiGetValuesPerRange(opts)
 

Typedefs

typedef struct MinmaxMultiOpaque MinmaxMultiOpaque
 
typedef struct MinMaxMultiOptions MinMaxMultiOptions
 
typedef struct Ranges Ranges
 
typedef struct SerializedRanges SerializedRanges
 
typedef struct ExpandedRange ExpandedRange
 
typedef struct DistanceValue DistanceValue
 
typedef struct compare_context compare_context
 

Functions

static SerializedRangesbrin_range_serialize (Ranges *range)
 
static Rangesbrin_range_deserialize (int maxvalues, SerializedRanges *serialized)
 
static FmgrInfominmax_multi_get_procinfo (BrinDesc *bdesc, uint16 attno, uint16 procnum)
 
static FmgrInfominmax_multi_get_strategy_procinfo (BrinDesc *bdesc, uint16 attno, Oid subtype, uint16 strategynum)
 
static int compare_values (const void *a, const void *b, void *arg)
 
static void AssertCheckRanges (Ranges *ranges, FmgrInfo *cmpFn, Oid colloid)
 
static void AssertCheckExpandedRanges (BrinDesc *bdesc, Oid colloid, AttrNumber attno, Form_pg_attribute attr, ExpandedRange *ranges, int nranges)
 
static Rangesminmax_multi_init (int maxvalues)
 
static void range_deduplicate_values (Ranges *range)
 
static int compare_expanded_ranges (const void *a, const void *b, void *arg)
 
static bool has_matching_range (BrinDesc *bdesc, Oid colloid, Ranges *ranges, Datum newval, AttrNumber attno, Oid typid)
 
static bool range_contains_value (BrinDesc *bdesc, Oid colloid, AttrNumber attno, Form_pg_attribute attr, Ranges *ranges, Datum newval, bool full)
 
static void fill_expanded_ranges (ExpandedRange *eranges, int neranges, Ranges *ranges)
 
static int sort_expanded_ranges (FmgrInfo *cmp, Oid colloid, ExpandedRange *eranges, int neranges)
 
static int merge_overlapping_ranges (FmgrInfo *cmp, Oid colloid, ExpandedRange *eranges, int neranges)
 
static int compare_distances (const void *a, const void *b)
 
static DistanceValuebuild_distances (FmgrInfo *distanceFn, Oid colloid, ExpandedRange *eranges, int neranges)
 
static ExpandedRangebuild_expanded_ranges (FmgrInfo *cmp, Oid colloid, Ranges *ranges, int *nranges)
 
static int reduce_expanded_ranges (ExpandedRange *eranges, int neranges, DistanceValue *distances, int max_values, FmgrInfo *cmp, Oid colloid)
 
static void store_expanded_ranges (Ranges *ranges, ExpandedRange *eranges, int neranges)
 
static bool ensure_free_space_in_buffer (BrinDesc *bdesc, Oid colloid, AttrNumber attno, Form_pg_attribute attr, Ranges *range)
 
static bool range_add_value (BrinDesc *bdesc, Oid colloid, AttrNumber attno, Form_pg_attribute attr, Ranges *ranges, Datum newval)
 
static void compactify_ranges (BrinDesc *bdesc, Ranges *ranges, int max_values)
 
Datum brin_minmax_multi_opcinfo (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_float4 (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_float8 (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_int2 (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_int4 (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_int8 (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_tid (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_numeric (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_uuid (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_date (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_time (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_timetz (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_timestamp (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_interval (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_pg_lsn (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_macaddr (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_macaddr8 (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_distance_inet (PG_FUNCTION_ARGS)
 
static void brin_minmax_multi_serialize (BrinDesc *bdesc, Datum src, Datum *dst)
 
static int brin_minmax_multi_get_values (BrinDesc *bdesc, MinMaxMultiOptions *opts)
 
Datum brin_minmax_multi_add_value (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_consistent (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_union (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_options (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_summary_in (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_summary_out (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_summary_recv (PG_FUNCTION_ARGS)
 
Datum brin_minmax_multi_summary_send (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

◆ MINMAX_BUFFER_FACTOR

#define MINMAX_BUFFER_FACTOR   10

Definition at line 106 of file brin_minmax_multi.c.

◆ MINMAX_BUFFER_LOAD_FACTOR

#define MINMAX_BUFFER_LOAD_FACTOR   0.5

Definition at line 109 of file brin_minmax_multi.c.

◆ MINMAX_BUFFER_MAX

#define MINMAX_BUFFER_MAX   8192

Definition at line 108 of file brin_minmax_multi.c.

◆ MINMAX_BUFFER_MIN

#define MINMAX_BUFFER_MIN   256

Definition at line 107 of file brin_minmax_multi.c.

◆ MINMAX_MAX_PROCNUMS

#define MINMAX_MAX_PROCNUMS   1 /* maximum support procs we need */

Definition at line 92 of file brin_minmax_multi.c.

◆ MINMAX_MULTI_DEFAULT_VALUES_PER_PAGE

#define MINMAX_MULTI_DEFAULT_VALUES_PER_PAGE   32

Definition at line 127 of file brin_minmax_multi.c.

◆ MinMaxMultiGetValuesPerRange

#define MinMaxMultiGetValuesPerRange (   opts)
Value:
((opts) && (((MinMaxMultiOptions *) (opts))->valuesPerRange != 0) ? \
((MinMaxMultiOptions *) (opts))->valuesPerRange : \
#define MINMAX_MULTI_DEFAULT_VALUES_PER_PAGE
static AmcheckOptions opts
Definition pg_amcheck.c:112

Definition at line 129 of file brin_minmax_multi.c.

◆ PROCNUM_BASE

#define PROCNUM_BASE   11

Definition at line 99 of file brin_minmax_multi.c.

◆ PROCNUM_DISTANCE

#define PROCNUM_DISTANCE   11 /* required, distance between values */

Definition at line 93 of file brin_minmax_multi.c.

Typedef Documentation

◆ compare_context

◆ DistanceValue

◆ ExpandedRange

◆ MinmaxMultiOpaque

◆ MinMaxMultiOptions

◆ Ranges

◆ SerializedRanges

Function Documentation

◆ AssertCheckExpandedRanges()

static void AssertCheckExpandedRanges ( BrinDesc bdesc,
Oid  colloid,
AttrNumber  attno,
Form_pg_attribute  attr,
ExpandedRange ranges,
int  nranges 
)
static

Definition at line 424 of file brin_minmax_multi.c.

427{
428#ifdef USE_ASSERT_CHECKING
429 int i;
430 FmgrInfo *eq;
431 FmgrInfo *lt;
432
433 eq = minmax_multi_get_strategy_procinfo(bdesc, attno, attr->atttypid,
435
436 lt = minmax_multi_get_strategy_procinfo(bdesc, attno, attr->atttypid,
438
439 /*
440 * Each range independently should be valid, i.e. that for the boundary
441 * values (lower <= upper).
442 */
443 for (i = 0; i < nranges; i++)
444 {
445 Datum r;
446 Datum minval = ranges[i].minval;
447 Datum maxval = ranges[i].maxval;
448
449 if (ranges[i].collapsed) /* collapsed: minval == maxval */
450 r = FunctionCall2Coll(eq, colloid, minval, maxval);
451 else /* non-collapsed: minval < maxval */
452 r = FunctionCall2Coll(lt, colloid, minval, maxval);
453
455 }
456
457 /*
458 * And the ranges should be ordered and must not overlap, i.e. upper <
459 * lower for boundaries of consecutive ranges.
460 */
461 for (i = 0; i < nranges - 1; i++)
462 {
463 Datum r;
464 Datum maxval = ranges[i].maxval;
465 Datum minval = ranges[i + 1].minval;
466
467 r = FunctionCall2Coll(lt, colloid, maxval, minval);
468
470 }
471#endif
472}
static FmgrInfo * minmax_multi_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype, uint16 strategynum)
#define Assert(condition)
Definition c.h:945
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition fmgr.c:1151
int i
Definition isn.c:77
static bool DatumGetBool(Datum X)
Definition postgres.h:100
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
#define BTLessStrategyNumber
Definition stratnum.h:29
#define BTEqualStrategyNumber
Definition stratnum.h:31

References Assert, BTEqualStrategyNumber, BTLessStrategyNumber, DatumGetBool(), fb(), FunctionCall2Coll(), i, ExpandedRange::maxval, minmax_multi_get_strategy_procinfo(), and ExpandedRange::minval.

Referenced by brin_minmax_multi_union(), and ensure_free_space_in_buffer().

◆ AssertCheckRanges()

static void AssertCheckRanges ( Ranges ranges,
FmgrInfo cmpFn,
Oid  colloid 
)
static

Definition at line 294 of file brin_minmax_multi.c.

295{
296#ifdef USE_ASSERT_CHECKING
297 int i;
298
299 /* some basic sanity checks */
300 Assert(ranges->nranges >= 0);
301 Assert(ranges->nsorted >= 0);
302 Assert(ranges->nvalues >= ranges->nsorted);
303 Assert(ranges->maxvalues >= 2 * ranges->nranges + ranges->nvalues);
304 Assert(ranges->typid != InvalidOid);
305
306 /*
307 * First the ranges - there are 2*nranges boundary values, and the values
308 * have to be strictly ordered (equal values would mean the range is
309 * collapsed, and should be stored as a point). This also guarantees that
310 * the ranges do not overlap.
311 */
312 AssertArrayOrder(cmpFn, colloid, ranges->values, 2 * ranges->nranges);
313
314 /* then the single-point ranges (with nvalues boundary values ) */
315 AssertArrayOrder(cmpFn, colloid, &ranges->values[2 * ranges->nranges],
316 ranges->nsorted);
317
318 /*
319 * Check that none of the values are not covered by ranges (both sorted
320 * and unsorted)
321 */
322 if (ranges->nranges > 0)
323 {
324 for (i = 0; i < ranges->nvalues; i++)
325 {
327 int start,
328 end;
329 Datum minvalue = ranges->values[0];
330 Datum maxvalue = ranges->values[2 * ranges->nranges - 1];
331 Datum value = ranges->values[2 * ranges->nranges + i];
332
333 compar = FunctionCall2Coll(cmpFn, colloid, value, minvalue);
334
335 /*
336 * If the value is smaller than the lower bound in the first range
337 * then it cannot possibly be in any of the ranges.
338 */
339 if (DatumGetBool(compar))
340 continue;
341
342 compar = FunctionCall2Coll(cmpFn, colloid, maxvalue, value);
343
344 /*
345 * Likewise, if the value is larger than the upper bound of the
346 * final range, then it cannot possibly be inside any of the
347 * ranges.
348 */
349 if (DatumGetBool(compar))
350 continue;
351
352 /* bsearch the ranges to see if 'value' fits within any of them */
353 start = 0; /* first range */
354 end = ranges->nranges - 1; /* last range */
355 while (true)
356 {
357 int midpoint = (start + end) / 2;
358
359 /* this means we ran out of ranges in the last step */
360 if (start > end)
361 break;
362
363 /* copy the min/max values from the ranges */
364 minvalue = ranges->values[2 * midpoint];
365 maxvalue = ranges->values[2 * midpoint + 1];
366
367 /*
368 * Is the value smaller than the minval? If yes, we'll recurse
369 * to the left side of range array.
370 */
371 compar = FunctionCall2Coll(cmpFn, colloid, value, minvalue);
372
373 /* smaller than the smallest value in this range */
374 if (DatumGetBool(compar))
375 {
376 end = (midpoint - 1);
377 continue;
378 }
379
380 /*
381 * Is the value greater than the minval? If yes, we'll recurse
382 * to the right side of range array.
383 */
384 compar = FunctionCall2Coll(cmpFn, colloid, maxvalue, value);
385
386 /* larger than the largest value in this range */
387 if (DatumGetBool(compar))
388 {
389 start = (midpoint + 1);
390 continue;
391 }
392
393 /* hey, we found a matching range */
394 Assert(false);
395 }
396 }
397 }
398
399 /* and values in the unsorted part must not be in the sorted part */
400 if (ranges->nsorted > 0)
401 {
402 compare_context cxt;
403
404 cxt.colloid = ranges->colloid;
405 cxt.cmpFn = ranges->cmp;
406
407 for (i = ranges->nsorted; i < ranges->nvalues; i++)
408 {
409 Datum value = ranges->values[2 * ranges->nranges + i];
410
411 Assert(bsearch_arg(&value, &ranges->values[2 * ranges->nranges],
412 ranges->nsorted, sizeof(Datum),
413 compare_values, &cxt) == NULL);
414 }
415 }
416#endif
417}
static int compare_values(const void *a, const void *b, void *arg)
return str start
static struct @174 value
void * bsearch_arg(const void *key, const void *base0, size_t nmemb, size_t size, int(*compar)(const void *, const void *, void *), void *arg)
Definition bsearch_arg.c:55
#define InvalidOid
FmgrInfo * cmp
Datum values[FLEXIBLE_ARRAY_MEMBER]

References Assert, bsearch_arg(), Ranges::cmp, compare_context::cmpFn, Ranges::colloid, compare_context::colloid, compare_values(), DatumGetBool(), fb(), FunctionCall2Coll(), i, InvalidOid, Ranges::maxvalues, Ranges::nranges, Ranges::nsorted, Ranges::nvalues, start, Ranges::typid, value, and Ranges::values.

Referenced by compactify_ranges(), ensure_free_space_in_buffer(), range_add_value(), and range_deduplicate_values().

◆ brin_minmax_multi_add_value()

Datum brin_minmax_multi_add_value ( PG_FUNCTION_ARGS  )

Definition at line 2410 of file brin_minmax_multi.c.

2411{
2417 Oid colloid = PG_GET_COLLATION();
2418 bool modified = false;
2419 Form_pg_attribute attr;
2420 AttrNumber attno;
2421 Ranges *ranges;
2423
2424 Assert(!isnull);
2425
2426 attno = column->bv_attno;
2427 attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1);
2428
2429 /* use the already deserialized value, if possible */
2430 ranges = (Ranges *) DatumGetPointer(column->bv_mem_value);
2431
2432 /*
2433 * If this is the first non-null value, we need to initialize the range
2434 * list. Otherwise, just extract the existing range list from BrinValues.
2435 *
2436 * When starting with an empty range, we assume this is a batch mode and
2437 * we use a larger buffer. The buffer size is derived from the BRIN range
2438 * size, number of rows per page, with some sensible min/max values. A
2439 * small buffer would be bad for performance, but a large buffer might
2440 * require a lot of memory (because of keeping all the values).
2441 */
2442 if (column->bv_allnulls)
2443 {
2445
2446 int target_maxvalues;
2447 int maxvalues;
2448 BlockNumber pagesPerRange = BrinGetPagesPerRange(bdesc->bd_index);
2449
2450 /* what was specified as a reloption? */
2451 target_maxvalues = brin_minmax_multi_get_values(bdesc, opts);
2452
2453 /*
2454 * Determine the insert buffer size - we use 10x the target, capped to
2455 * the maximum number of values in the heap range. This is more than
2456 * enough, considering the actual number of rows per page is likely
2457 * much lower, but meh.
2458 */
2459 maxvalues = Min(target_maxvalues * MINMAX_BUFFER_FACTOR,
2460 MaxHeapTuplesPerPage * pagesPerRange);
2461
2462 /* but always at least the original value */
2463 maxvalues = Max(maxvalues, target_maxvalues);
2464
2465 /* always cap by MIN/MAX */
2466 maxvalues = Max(maxvalues, MINMAX_BUFFER_MIN);
2467 maxvalues = Min(maxvalues, MINMAX_BUFFER_MAX);
2468
2469 oldctx = MemoryContextSwitchTo(column->bv_context);
2470 ranges = minmax_multi_init(maxvalues);
2471 ranges->attno = attno;
2472 ranges->colloid = colloid;
2473 ranges->typid = attr->atttypid;
2474 ranges->target_maxvalues = target_maxvalues;
2475
2476 /* we'll certainly need the comparator, so just look it up now */
2477 ranges->cmp = minmax_multi_get_strategy_procinfo(bdesc, attno, attr->atttypid,
2479
2481
2482 column->bv_allnulls = false;
2483 modified = true;
2484
2485 column->bv_mem_value = PointerGetDatum(ranges);
2486 column->bv_serialize = brin_minmax_multi_serialize;
2487 }
2488 else if (!ranges)
2489 {
2491
2492 int maxvalues;
2493 BlockNumber pagesPerRange = BrinGetPagesPerRange(bdesc->bd_index);
2494
2495 oldctx = MemoryContextSwitchTo(column->bv_context);
2496
2498
2499 /*
2500 * Determine the insert buffer size - we use 10x the target, capped to
2501 * the maximum number of values in the heap range. This is more than
2502 * enough, considering the actual number of rows per page is likely
2503 * much lower, but meh.
2504 */
2505 maxvalues = Min(serialized->maxvalues * MINMAX_BUFFER_FACTOR,
2506 MaxHeapTuplesPerPage * pagesPerRange);
2507
2508 /* but always at least the original value */
2509 maxvalues = Max(maxvalues, serialized->maxvalues);
2510
2511 /* always cap by MIN/MAX */
2512 maxvalues = Max(maxvalues, MINMAX_BUFFER_MIN);
2513 maxvalues = Min(maxvalues, MINMAX_BUFFER_MAX);
2514
2515 ranges = brin_range_deserialize(maxvalues, serialized);
2516
2517 ranges->attno = attno;
2518 ranges->colloid = colloid;
2519 ranges->typid = attr->atttypid;
2520
2521 /* we'll certainly need the comparator, so just look it up now */
2522 ranges->cmp = minmax_multi_get_strategy_procinfo(bdesc, attno, attr->atttypid,
2524
2525 column->bv_mem_value = PointerGetDatum(ranges);
2526 column->bv_serialize = brin_minmax_multi_serialize;
2527
2529 }
2530
2531 /*
2532 * Try to add the new value to the range. We need to update the modified
2533 * flag, so that we serialize the updated summary later.
2534 */
2535 modified |= range_add_value(bdesc, colloid, attno, attr, ranges, newval);
2536
2537
2539}
int16 AttrNumber
Definition attnum.h:21
uint32 BlockNumber
Definition block.h:31
#define BrinGetPagesPerRange(relation)
Definition brin.h:41
static bool range_add_value(BrinDesc *bdesc, Oid colloid, AttrNumber attno, Form_pg_attribute attr, Ranges *ranges, Datum newval)
#define MINMAX_BUFFER_MAX
static int brin_minmax_multi_get_values(BrinDesc *bdesc, MinMaxMultiOptions *opts)
#define MINMAX_BUFFER_FACTOR
static void brin_minmax_multi_serialize(BrinDesc *bdesc, Datum src, Datum *dst)
static Ranges * brin_range_deserialize(int maxvalues, SerializedRanges *serialized)
static Ranges * minmax_multi_init(int maxvalues)
#define MINMAX_BUFFER_MIN
#define Min(x, y)
Definition c.h:1093
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:243
#define Max(x, y)
Definition c.h:1087
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_GETARG_DATUM(n)
Definition fmgr.h:268
#define PG_GET_OPCLASS_OPTIONS()
Definition fmgr.h:343
#define PG_DETOAST_DATUM(datum)
Definition fmgr.h:240
#define PG_GETARG_BOOL(n)
Definition fmgr.h:274
#define PG_GET_COLLATION()
Definition fmgr.h:198
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
#define newval
#define MaxHeapTuplesPerPage
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
FormData_pg_attribute * Form_pg_attribute
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
unsigned int Oid
AttrNumber attno
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178

References Assert, Ranges::attno, brin_minmax_multi_get_values(), brin_minmax_multi_serialize(), brin_range_deserialize(), BrinGetPagesPerRange, BTLessStrategyNumber, Ranges::cmp, Ranges::colloid, DatumGetPointer(), fb(), Max, MaxHeapTuplesPerPage, MemoryContextSwitchTo(), Min, MINMAX_BUFFER_FACTOR, MINMAX_BUFFER_MAX, MINMAX_BUFFER_MIN, minmax_multi_get_strategy_procinfo(), minmax_multi_init(), newval, opts, PG_DETOAST_DATUM, PG_GET_COLLATION, PG_GET_OPCLASS_OPTIONS, PG_GETARG_BOOL, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_RETURN_BOOL, PG_USED_FOR_ASSERTS_ONLY, PointerGetDatum(), range_add_value(), Ranges::target_maxvalues, TupleDescAttr(), and Ranges::typid.

◆ brin_minmax_multi_consistent()

Datum brin_minmax_multi_consistent ( PG_FUNCTION_ARGS  )

Definition at line 2547 of file brin_minmax_multi.c.

2548{
2551 ScanKey *keys = (ScanKey *) PG_GETARG_POINTER(2);
2552 int nkeys = PG_GETARG_INT32(3);
2553
2554 Oid colloid = PG_GET_COLLATION(),
2555 subtype;
2556 AttrNumber attno;
2557 Datum value;
2558 FmgrInfo *finfo;
2560 Ranges *ranges;
2561 int keyno;
2562 int rangeno;
2563 int i;
2564
2565 attno = column->bv_attno;
2566
2568 ranges = brin_range_deserialize(serialized->maxvalues, serialized);
2569
2570 /* inspect the ranges, and for each one evaluate the scan keys */
2571 for (rangeno = 0; rangeno < ranges->nranges; rangeno++)
2572 {
2573 Datum minval = ranges->values[2 * rangeno];
2574 Datum maxval = ranges->values[2 * rangeno + 1];
2575
2576 /* assume the range is matching, and we'll try to prove otherwise */
2577 bool matching = true;
2578
2579 for (keyno = 0; keyno < nkeys; keyno++)
2580 {
2581 bool matches;
2582 ScanKey key = keys[keyno];
2583
2584 /* NULL keys are handled and filtered-out in bringetbitmap */
2585 Assert(!(key->sk_flags & SK_ISNULL));
2586
2587 attno = key->sk_attno;
2588 subtype = key->sk_subtype;
2589 value = key->sk_argument;
2590 switch (key->sk_strategy)
2591 {
2594 finfo = minmax_multi_get_strategy_procinfo(bdesc, attno, subtype,
2595 key->sk_strategy);
2596 /* first value from the array */
2597 matches = DatumGetBool(FunctionCall2Coll(finfo, colloid, minval, value));
2598 break;
2599
2601 {
2602 Datum compar;
2603 FmgrInfo *cmpFn;
2604
2605 /* by default this range does not match */
2606 matches = false;
2607
2608 /*
2609 * Otherwise, need to compare the new value with
2610 * boundaries of all the ranges. First check if it's
2611 * less than the absolute minimum, which is the first
2612 * value in the array.
2613 */
2614 cmpFn = minmax_multi_get_strategy_procinfo(bdesc, attno, subtype,
2616 compar = FunctionCall2Coll(cmpFn, colloid, minval, value);
2617
2618 /* smaller than the smallest value in this range */
2619 if (DatumGetBool(compar))
2620 break;
2621
2622 cmpFn = minmax_multi_get_strategy_procinfo(bdesc, attno, subtype,
2624 compar = FunctionCall2Coll(cmpFn, colloid, maxval, value);
2625
2626 /* larger than the largest value in this range */
2627 if (DatumGetBool(compar))
2628 break;
2629
2630 /*
2631 * We haven't managed to eliminate this range, so
2632 * consider it matching.
2633 */
2634 matches = true;
2635
2636 break;
2637 }
2640 finfo = minmax_multi_get_strategy_procinfo(bdesc, attno, subtype,
2641 key->sk_strategy);
2642 /* last value from the array */
2643 matches = DatumGetBool(FunctionCall2Coll(finfo, colloid, maxval, value));
2644 break;
2645
2646 default:
2647 /* shouldn't happen */
2648 elog(ERROR, "invalid strategy number %d", key->sk_strategy);
2649 matches = false;
2650 break;
2651 }
2652
2653 /* the range has to match all the scan keys */
2654 matching &= matches;
2655
2656 /* once we find a non-matching key, we're done */
2657 if (!matching)
2658 break;
2659 }
2660
2661 /*
2662 * have we found a range matching all scan keys? if yes, we're done
2663 */
2664 if (matching)
2665 PG_RETURN_BOOL(true);
2666 }
2667
2668 /*
2669 * And now inspect the values. We don't bother with doing a binary search
2670 * here, because we're dealing with serialized / fully compacted ranges,
2671 * so there should be only very few values.
2672 */
2673 for (i = 0; i < ranges->nvalues; i++)
2674 {
2675 Datum val = ranges->values[2 * ranges->nranges + i];
2676
2677 /* assume the range is matching, and we'll try to prove otherwise */
2678 bool matching = true;
2679
2680 for (keyno = 0; keyno < nkeys; keyno++)
2681 {
2682 bool matches;
2683 ScanKey key = keys[keyno];
2684
2685 /* we've already dealt with NULL keys at the beginning */
2686 if (key->sk_flags & SK_ISNULL)
2687 continue;
2688
2689 attno = key->sk_attno;
2690 subtype = key->sk_subtype;
2691 value = key->sk_argument;
2692 switch (key->sk_strategy)
2693 {
2699
2700 finfo = minmax_multi_get_strategy_procinfo(bdesc, attno, subtype,
2701 key->sk_strategy);
2702 matches = DatumGetBool(FunctionCall2Coll(finfo, colloid, val, value));
2703 break;
2704
2705 default:
2706 /* shouldn't happen */
2707 elog(ERROR, "invalid strategy number %d", key->sk_strategy);
2708 matches = false;
2709 break;
2710 }
2711
2712 /* the range has to match all the scan keys */
2713 matching &= matches;
2714
2715 /* once we find a non-matching key, we're done */
2716 if (!matching)
2717 break;
2718 }
2719
2720 /* have we found a range matching all scan keys? if yes, we're done */
2721 if (matching)
2722 PG_RETURN_BOOL(true);
2723 }
2724
2725 PG_RETURN_BOOL(false);
2726}
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
long val
Definition informix.c:689
#define SK_ISNULL
Definition skey.h:115
#define BTGreaterStrategyNumber
Definition stratnum.h:33
#define BTLessEqualStrategyNumber
Definition stratnum.h:30
#define BTGreaterEqualStrategyNumber
Definition stratnum.h:32

References Assert, brin_range_deserialize(), BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, DatumGetBool(), elog, ERROR, fb(), FunctionCall2Coll(), i, minmax_multi_get_strategy_procinfo(), Ranges::nranges, Ranges::nvalues, PG_DETOAST_DATUM, PG_GET_COLLATION, PG_GETARG_INT32, PG_GETARG_POINTER, PG_RETURN_BOOL, SK_ISNULL, val, value, and Ranges::values.

◆ brin_minmax_multi_distance_date()

Datum brin_minmax_multi_distance_date ( PG_FUNCTION_ARGS  )

Definition at line 2078 of file brin_minmax_multi.c.

2079{
2080 float8 delta = 0;
2083
2084 delta = (float8) dateVal2 - (float8) dateVal1;
2085
2086 Assert(delta >= 0);
2087
2088 PG_RETURN_FLOAT8(delta);
2089}
double float8
Definition c.h:716
int32 DateADT
Definition date.h:21
#define PG_GETARG_DATEADT(n)
Definition date.h:95
#define PG_RETURN_FLOAT8(x)
Definition fmgr.h:369

References Assert, fb(), PG_GETARG_DATEADT, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_float4()

Datum brin_minmax_multi_distance_float4 ( PG_FUNCTION_ARGS  )

Definition at line 1881 of file brin_minmax_multi.c.

1882{
1883 float a1 = PG_GETARG_FLOAT4(0);
1884 float a2 = PG_GETARG_FLOAT4(1);
1885
1886 /* if both values are NaN, then we consider them the same */
1887 if (isnan(a1) && isnan(a2))
1888 PG_RETURN_FLOAT8(0.0);
1889
1890 /* if one value is NaN, use infinite distance */
1891 if (isnan(a1) || isnan(a2))
1893
1894 /*
1895 * We know the values are range boundaries, but the range may be collapsed
1896 * (i.e. single points), with equal values.
1897 */
1898 Assert(a1 <= a2);
1899
1900 PG_RETURN_FLOAT8((double) a2 - (double) a1);
1901}
static float8 get_float8_infinity(void)
Definition float.h:65
#define PG_GETARG_FLOAT4(n)
Definition fmgr.h:282
static const FormData_pg_attribute a1
Definition heap.c:144
static const FormData_pg_attribute a2
Definition heap.c:157

References a1, a2, Assert, fb(), get_float8_infinity(), PG_GETARG_FLOAT4, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_float8()

Datum brin_minmax_multi_distance_float8 ( PG_FUNCTION_ARGS  )

Definition at line 1907 of file brin_minmax_multi.c.

1908{
1909 double a1 = PG_GETARG_FLOAT8(0);
1910 double a2 = PG_GETARG_FLOAT8(1);
1911
1912 /* if both values are NaN, then we consider them the same */
1913 if (isnan(a1) && isnan(a2))
1914 PG_RETURN_FLOAT8(0.0);
1915
1916 /* if one value is NaN, use infinite distance */
1917 if (isnan(a1) || isnan(a2))
1919
1920 /*
1921 * We know the values are range boundaries, but the range may be collapsed
1922 * (i.e. single points), with equal values.
1923 */
1924 Assert(a1 <= a2);
1925
1927}
#define PG_GETARG_FLOAT8(n)
Definition fmgr.h:283

References a1, a2, Assert, fb(), get_float8_infinity(), PG_GETARG_FLOAT8, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_inet()

Datum brin_minmax_multi_distance_inet ( PG_FUNCTION_ARGS  )

Definition at line 2295 of file brin_minmax_multi.c.

2296{
2297 float8 delta;
2298 int i;
2299 int len;
2300 unsigned char *addra,
2301 *addrb;
2302
2305
2306 int lena,
2307 lenb;
2308
2309 /*
2310 * If the addresses are from different families, consider them to be in
2311 * maximal possible distance (which is 1.0).
2312 */
2313 if (ip_family(ipa) != ip_family(ipb))
2314 PG_RETURN_FLOAT8(1.0);
2315
2316 addra = (unsigned char *) palloc(ip_addrsize(ipa));
2318
2319 addrb = (unsigned char *) palloc(ip_addrsize(ipb));
2321
2322 /*
2323 * The length is calculated from the mask length, because we sort the
2324 * addresses by first address in the range, so A.B.C.D/24 < A.B.C.1 (the
2325 * first range starts at A.B.C.0, which is before A.B.C.1). We don't want
2326 * to produce a negative delta in this case, so we just cut the extra
2327 * bytes.
2328 *
2329 * XXX Maybe this should be a bit more careful and cut the bits, not just
2330 * whole bytes.
2331 */
2332 lena = ip_bits(ipa);
2333 lenb = ip_bits(ipb);
2334
2335 len = ip_addrsize(ipa);
2336
2337 /* apply the network mask to both addresses */
2338 for (i = 0; i < len; i++)
2339 {
2340 unsigned char mask;
2341 int nbits;
2342
2343 nbits = Max(0, lena - (i * 8));
2344 if (nbits < 8)
2345 {
2346 mask = (0xFF << (8 - nbits));
2347 addra[i] = (addra[i] & mask);
2348 }
2349
2350 nbits = Max(0, lenb - (i * 8));
2351 if (nbits < 8)
2352 {
2353 mask = (0xFF << (8 - nbits));
2354 addrb[i] = (addrb[i] & mask);
2355 }
2356 }
2357
2358 /* Calculate the difference between the addresses. */
2359 delta = 0;
2360 for (i = len - 1; i >= 0; i--)
2361 {
2362 unsigned char a = addra[i];
2363 unsigned char b = addrb[i];
2364
2365 delta += (float8) b - (float8) a;
2366 delta /= 256;
2367 }
2368
2369 Assert((delta >= 0) && (delta <= 1));
2370
2371 pfree(addra);
2372 pfree(addrb);
2373
2374 PG_RETURN_FLOAT8(delta);
2375}
int b
Definition isn.c:74
int a
Definition isn.c:73
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
const void size_t len
Definition inet.h:53
#define ip_addr(inetptr)
Definition inet.h:77
#define PG_GETARG_INET_PP(n)
Definition inet.h:134
#define ip_family(inetptr)
Definition inet.h:71
#define ip_addrsize(inetptr)
Definition inet.h:80
#define ip_bits(inetptr)
Definition inet.h:74

References a, Assert, b, fb(), i, ip_addr, ip_addrsize, ip_bits, ip_family, len, Max, palloc(), pfree(), PG_GETARG_INET_PP, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_int2()

Datum brin_minmax_multi_distance_int2 ( PG_FUNCTION_ARGS  )

Definition at line 1933 of file brin_minmax_multi.c.

1934{
1937
1938 /*
1939 * We know the values are range boundaries, but the range may be collapsed
1940 * (i.e. single points), with equal values.
1941 */
1942 Assert(a1 <= a2);
1943
1944 PG_RETURN_FLOAT8((double) a2 - (double) a1);
1945}
int16_t int16
Definition c.h:613
#define PG_GETARG_INT16(n)
Definition fmgr.h:271

References a1, a2, Assert, PG_GETARG_INT16, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_int4()

Datum brin_minmax_multi_distance_int4 ( PG_FUNCTION_ARGS  )

Definition at line 1951 of file brin_minmax_multi.c.

1952{
1955
1956 /*
1957 * We know the values are range boundaries, but the range may be collapsed
1958 * (i.e. single points), with equal values.
1959 */
1960 Assert(a1 <= a2);
1961
1962 PG_RETURN_FLOAT8((double) a2 - (double) a1);
1963}
int32_t int32
Definition c.h:614

References a1, a2, Assert, PG_GETARG_INT32, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_int8()

Datum brin_minmax_multi_distance_int8 ( PG_FUNCTION_ARGS  )

Definition at line 1969 of file brin_minmax_multi.c.

1970{
1973
1974 /*
1975 * We know the values are range boundaries, but the range may be collapsed
1976 * (i.e. single points), with equal values.
1977 */
1978 Assert(a1 <= a2);
1979
1980 PG_RETURN_FLOAT8((double) a2 - (double) a1);
1981}
int64_t int64
Definition c.h:615
#define PG_GETARG_INT64(n)
Definition fmgr.h:284

References a1, a2, Assert, PG_GETARG_INT64, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_interval()

Datum brin_minmax_multi_distance_interval ( PG_FUNCTION_ARGS  )

Definition at line 2153 of file brin_minmax_multi.c.

2154{
2155 float8 delta = 0;
2156
2159
2161 int64 days;
2162
2163 /*
2164 * Delta is (fractional) number of days between the intervals. Assume
2165 * months have 30 days for consistency with interval_cmp_internal. We
2166 * don't need to be exact, in the worst case we'll build a bit less
2167 * efficient ranges. But we should not contradict interval_cmp.
2168 */
2169 dayfraction = (ib->time % USECS_PER_DAY) - (ia->time % USECS_PER_DAY);
2170 days = (ib->time / USECS_PER_DAY) - (ia->time / USECS_PER_DAY);
2171 days += (int64) ib->day - (int64) ia->day;
2172 days += ((int64) ib->month - (int64) ia->month) * INT64CONST(30);
2173
2174 /* convert to double precision */
2175 delta = (double) days + dayfraction / (double) USECS_PER_DAY;
2176
2177 Assert(delta >= 0);
2178
2179 PG_RETURN_FLOAT8(delta);
2180}
const char *const days[]
Definition datetime.c:85
#define INT64CONST(x)
Definition c.h:632
#define USECS_PER_DAY
Definition timestamp.h:131
#define PG_GETARG_INTERVAL_P(n)
Definition timestamp.h:65

References Assert, days, fb(), INT64CONST, PG_GETARG_INTERVAL_P, PG_RETURN_FLOAT8, and USECS_PER_DAY.

◆ brin_minmax_multi_distance_macaddr()

Datum brin_minmax_multi_distance_macaddr ( PG_FUNCTION_ARGS  )

Definition at line 2210 of file brin_minmax_multi.c.

2211{
2212 float8 delta;
2213
2216
2217 delta = ((float8) b->f - (float8) a->f);
2218 delta /= 256;
2219
2220 delta += ((float8) b->e - (float8) a->e);
2221 delta /= 256;
2222
2223 delta += ((float8) b->d - (float8) a->d);
2224 delta /= 256;
2225
2226 delta += ((float8) b->c - (float8) a->c);
2227 delta /= 256;
2228
2229 delta += ((float8) b->b - (float8) a->b);
2230 delta /= 256;
2231
2232 delta += ((float8) b->a - (float8) a->a);
2233 delta /= 256;
2234
2235 Assert(delta >= 0);
2236
2237 PG_RETURN_FLOAT8(delta);
2238}
Definition inet.h:95
#define PG_GETARG_MACADDR_P(n)
Definition inet.h:158

References a, Assert, b, PG_GETARG_MACADDR_P, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_macaddr8()

Datum brin_minmax_multi_distance_macaddr8 ( PG_FUNCTION_ARGS  )

Definition at line 2247 of file brin_minmax_multi.c.

2248{
2249 float8 delta;
2250
2253
2254 delta = ((float8) b->h - (float8) a->h);
2255 delta /= 256;
2256
2257 delta += ((float8) b->g - (float8) a->g);
2258 delta /= 256;
2259
2260 delta += ((float8) b->f - (float8) a->f);
2261 delta /= 256;
2262
2263 delta += ((float8) b->e - (float8) a->e);
2264 delta /= 256;
2265
2266 delta += ((float8) b->d - (float8) a->d);
2267 delta /= 256;
2268
2269 delta += ((float8) b->c - (float8) a->c);
2270 delta /= 256;
2271
2272 delta += ((float8) b->b - (float8) a->b);
2273 delta /= 256;
2274
2275 delta += ((float8) b->a - (float8) a->a);
2276 delta /= 256;
2277
2278 Assert(delta >= 0);
2279
2280 PG_RETURN_FLOAT8(delta);
2281}
#define PG_GETARG_MACADDR8_P(n)
Definition inet.h:174

References a, Assert, b, PG_GETARG_MACADDR8_P, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_numeric()

Datum brin_minmax_multi_distance_numeric ( PG_FUNCTION_ARGS  )

Definition at line 2019 of file brin_minmax_multi.c.

2020{
2021 Datum d;
2024
2025 /*
2026 * We know the values are range boundaries, but the range may be collapsed
2027 * (i.e. single points), with equal values.
2028 */
2030
2031 d = DirectFunctionCall2(numeric_sub, a2, a1); /* a2 - a1 */
2032
2034}
Datum numeric_sub(PG_FUNCTION_ARGS)
Definition numeric.c:2941
Datum numeric_le(PG_FUNCTION_ARGS)
Definition numeric.c:2508
Datum numeric_float8(PG_FUNCTION_ARGS)
Definition numeric.c:4574
#define DirectFunctionCall2(func, arg1, arg2)
Definition fmgr.h:686
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:684
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354

References a1, a2, Assert, DatumGetBool(), DirectFunctionCall1, DirectFunctionCall2, numeric_float8(), numeric_le(), numeric_sub(), PG_GETARG_DATUM, and PG_RETURN_DATUM.

◆ brin_minmax_multi_distance_pg_lsn()

Datum brin_minmax_multi_distance_pg_lsn ( PG_FUNCTION_ARGS  )

Definition at line 2189 of file brin_minmax_multi.c.

2190{
2191 float8 delta = 0;
2192
2195
2196 delta = (lsnb - lsna);
2197
2198 Assert(delta >= 0);
2199
2200 PG_RETURN_FLOAT8(delta);
2201}
#define PG_GETARG_LSN(n)
Definition pg_lsn.h:36
uint64 XLogRecPtr
Definition xlogdefs.h:21

References Assert, fb(), PG_GETARG_LSN, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_tid()

Datum brin_minmax_multi_distance_tid ( PG_FUNCTION_ARGS  )

Definition at line 1988 of file brin_minmax_multi.c.

1989{
1990 double da1,
1991 da2;
1992
1995
1996 /*
1997 * We know the values are range boundaries, but the range may be collapsed
1998 * (i.e. single points), with equal values.
1999 */
2001
2002 /*
2003 * We use the no-check variants here, because user-supplied values may
2004 * have (ip_posid == 0). See ItemPointerCompare.
2005 */
2008
2011
2013}
int32 ItemPointerCompare(const ItemPointerData *arg1, const ItemPointerData *arg2)
Definition itemptr.c:51
static OffsetNumber ItemPointerGetOffsetNumberNoCheck(const ItemPointerData *pointer)
Definition itemptr.h:114
static BlockNumber ItemPointerGetBlockNumberNoCheck(const ItemPointerData *pointer)
Definition itemptr.h:93
ItemPointerData * ItemPointer
Definition itemptr.h:49

References Assert, fb(), ItemPointerCompare(), ItemPointerGetBlockNumberNoCheck(), ItemPointerGetOffsetNumberNoCheck(), MaxHeapTuplesPerPage, PG_GETARG_POINTER, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_time()

Datum brin_minmax_multi_distance_time ( PG_FUNCTION_ARGS  )

Definition at line 2097 of file brin_minmax_multi.c.

2098{
2099 float8 delta = 0;
2100
2103
2104 delta = (tb - ta);
2105
2106 Assert(delta >= 0);
2107
2108 PG_RETURN_FLOAT8(delta);
2109}
#define PG_GETARG_TIMEADT(n)
Definition date.h:96
int64 TimeADT
Definition date.h:23

References Assert, fb(), PG_GETARG_TIMEADT, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_timestamp()

Datum brin_minmax_multi_distance_timestamp ( PG_FUNCTION_ARGS  )

Definition at line 2135 of file brin_minmax_multi.c.

2136{
2137 float8 delta = 0;
2138
2141
2142 delta = (float8) dt2 - (float8) dt1;
2143
2144 Assert(delta >= 0);
2145
2146 PG_RETURN_FLOAT8(delta);
2147}
int64 Timestamp
Definition timestamp.h:38
#define PG_GETARG_TIMESTAMP(n)
Definition timestamp.h:63

References Assert, fb(), PG_GETARG_TIMESTAMP, and PG_RETURN_FLOAT8.

◆ brin_minmax_multi_distance_timetz()

Datum brin_minmax_multi_distance_timetz ( PG_FUNCTION_ARGS  )

Definition at line 2117 of file brin_minmax_multi.c.

2118{
2119 float8 delta = 0;
2120
2123
2124 delta = (tb->time - ta->time) + (tb->zone - ta->zone) * USECS_PER_SEC;
2125
2126 Assert(delta >= 0);
2127
2128 PG_RETURN_FLOAT8(delta);
2129}
#define USECS_PER_SEC
Definition timestamp.h:134
#define PG_GETARG_TIMETZADT_P(n)
Definition date.h:97

References Assert, fb(), PG_GETARG_TIMETZADT_P, PG_RETURN_FLOAT8, and USECS_PER_SEC.

◆ brin_minmax_multi_distance_uuid()

Datum brin_minmax_multi_distance_uuid ( PG_FUNCTION_ARGS  )

Definition at line 2045 of file brin_minmax_multi.c.

2046{
2047 int i;
2048 float8 delta = 0;
2049
2052
2055
2056 /*
2057 * We know the values are range boundaries, but the range may be collapsed
2058 * (i.e. single points), with equal values.
2059 */
2061
2062 /* compute approximate delta as a double precision value */
2063 for (i = UUID_LEN - 1; i >= 0; i--)
2064 {
2065 delta += (int) u2->data[i] - (int) u1->data[i];
2066 delta /= 256;
2067 }
2068
2069 Assert(delta >= 0);
2070
2071 PG_RETURN_FLOAT8(delta);
2072}
Datum uuid_le(PG_FUNCTION_ARGS)
Definition uuid.c:219
static pg_uuid_t * DatumGetUUIDP(Datum X)
Definition uuid.h:35
#define UUID_LEN
Definition uuid.h:18

References a1, a2, Assert, DatumGetBool(), DatumGetUUIDP(), DirectFunctionCall2, fb(), i, PG_GETARG_DATUM, PG_RETURN_FLOAT8, uuid_le(), and UUID_LEN.

◆ brin_minmax_multi_get_values()

static int brin_minmax_multi_get_values ( BrinDesc bdesc,
MinMaxMultiOptions opts 
)
static

Definition at line 2397 of file brin_minmax_multi.c.

2398{
2400}
#define MinMaxMultiGetValuesPerRange(opts)

References MinMaxMultiGetValuesPerRange, and opts.

Referenced by brin_minmax_multi_add_value().

◆ brin_minmax_multi_opcinfo()

Datum brin_minmax_multi_opcinfo ( PG_FUNCTION_ARGS  )

Definition at line 1857 of file brin_minmax_multi.c.

1858{
1859 BrinOpcInfo *result;
1860
1861 /*
1862 * opaque->strategy_procinfos is initialized lazily; here it is set to
1863 * all-uninitialized by palloc0 which sets fn_oid to InvalidOid.
1864 */
1865
1866 result = palloc0(MAXALIGN(SizeofBrinOpcInfo(1)) +
1867 sizeof(MinmaxMultiOpaque));
1868 result->oi_nstored = 1;
1869 result->oi_regular_nulls = true;
1870 result->oi_opaque = (MinmaxMultiOpaque *)
1871 MAXALIGN((char *) result + SizeofBrinOpcInfo(1));
1873
1874 PG_RETURN_POINTER(result);
1875}
#define SizeofBrinOpcInfo(ncols)
#define MAXALIGN(LEN)
Definition c.h:898
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
void * palloc0(Size size)
Definition mcxt.c:1417
TypeCacheEntry * oi_typcache[FLEXIBLE_ARRAY_MEMBER]
uint16 oi_nstored
bool oi_regular_nulls
void * oi_opaque
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389

References fb(), lookup_type_cache(), MAXALIGN, BrinOpcInfo::oi_nstored, BrinOpcInfo::oi_opaque, BrinOpcInfo::oi_regular_nulls, BrinOpcInfo::oi_typcache, palloc0(), PG_RETURN_POINTER, and SizeofBrinOpcInfo.

◆ brin_minmax_multi_options()

Datum brin_minmax_multi_options ( PG_FUNCTION_ARGS  )

Definition at line 2952 of file brin_minmax_multi.c.

2953{
2955
2957
2958 add_local_int_reloption(relopts, "values_per_range", "desc",
2960 offsetof(MinMaxMultiOptions, valuesPerRange));
2961
2963}
#define PG_RETURN_VOID()
Definition fmgr.h:350
void init_local_reloptions(local_relopts *relopts, Size relopt_struct_size)
Definition reloptions.c:783
void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset)

References add_local_int_reloption(), fb(), init_local_reloptions(), MINMAX_MULTI_DEFAULT_VALUES_PER_PAGE, PG_GETARG_POINTER, and PG_RETURN_VOID.

◆ brin_minmax_multi_serialize()

static void brin_minmax_multi_serialize ( BrinDesc bdesc,
Datum  src,
Datum dst 
)
static

Definition at line 2378 of file brin_minmax_multi.c.

2379{
2380 Ranges *ranges = (Ranges *) DatumGetPointer(src);
2382
2383 /*
2384 * In batch mode, we need to compress the accumulated values to the
2385 * actually requested number of values/ranges.
2386 */
2387 compactify_ranges(bdesc, ranges, ranges->target_maxvalues);
2388
2389 /* At this point everything has to be fully sorted. */
2390 Assert(ranges->nsorted == ranges->nvalues);
2391
2392 s = brin_range_serialize(ranges);
2393 dst[0] = PointerGetDatum(s);
2394}
static void compactify_ranges(BrinDesc *bdesc, Ranges *ranges, int max_values)
static SerializedRanges * brin_range_serialize(Ranges *range)

References Assert, brin_range_serialize(), compactify_ranges(), DatumGetPointer(), fb(), Ranges::nsorted, Ranges::nvalues, PointerGetDatum(), and Ranges::target_maxvalues.

Referenced by brin_minmax_multi_add_value().

◆ brin_minmax_multi_summary_in()

Datum brin_minmax_multi_summary_in ( PG_FUNCTION_ARGS  )

Definition at line 2974 of file brin_minmax_multi.c.

2975{
2976 /*
2977 * brin_minmax_multi_summary stores the data in binary form and parsing
2978 * text input is not needed, so disallow this.
2979 */
2980 ereport(ERROR,
2982 errmsg("cannot accept a value of type %s", "brin_minmax_multi_summary")));
2983
2984 PG_RETURN_VOID(); /* keep compiler quiet */
2985}
int errcode(int sqlerrcode)
Definition elog.c:874
#define ereport(elevel,...)
Definition elog.h:150
static char * errmsg

References ereport, errcode(), errmsg, ERROR, fb(), and PG_RETURN_VOID.

◆ brin_minmax_multi_summary_out()

Datum brin_minmax_multi_summary_out ( PG_FUNCTION_ARGS  )

Definition at line 2996 of file brin_minmax_multi.c.

2997{
2998 int i;
2999 int idx;
3000 SerializedRanges *ranges;
3003 bool isvarlena;
3004 Oid outfunc;
3007
3010
3011 /*
3012 * Detoast to get value with full 4B header (can't be stored in a toast
3013 * table, but can use 1B header).
3014 */
3016
3017 /* lookup output func for the type */
3020
3021 /* deserialize the range info easy-to-process pieces */
3023
3024 appendStringInfo(&str, "nranges: %d nvalues: %d maxvalues: %d",
3025 ranges_deserialized->nranges,
3026 ranges_deserialized->nvalues,
3027 ranges_deserialized->maxvalues);
3028
3029 /* serialize ranges */
3030 idx = 0;
3031 for (i = 0; i < ranges_deserialized->nranges; i++)
3032 {
3033 char *a,
3034 *b;
3035 text *c;
3037
3039
3042
3043 appendStringInfo(&buf, "%s ... %s", a, b);
3044
3045 c = cstring_to_text_with_len(buf.data, buf.len);
3046
3049 false,
3050 TEXTOID,
3052 }
3053
3054 if (ranges_deserialized->nranges > 0)
3055 {
3056 Oid typoutput;
3057 bool typIsVarlena;
3058 Datum val;
3059 char *extval;
3060
3062
3064
3065 extval = OidOutputFunctionCall(typoutput, val);
3066
3067 appendStringInfo(&str, " ranges: %s", extval);
3068 }
3069
3070 /* serialize individual values */
3072
3073 for (i = 0; i < ranges_deserialized->nvalues; i++)
3074 {
3075 Datum a;
3076 text *b;
3077
3080
3083 false,
3084 TEXTOID,
3086 }
3087
3088 if (ranges_deserialized->nvalues > 0)
3089 {
3090 Oid typoutput;
3091 bool typIsVarlena;
3092 Datum val;
3093 char *extval;
3094
3096
3098
3099 extval = OidOutputFunctionCall(typoutput, val);
3100
3101 appendStringInfo(&str, " values: %s", extval);
3102 }
3103
3104
3106
3107 PG_RETURN_CSTRING(str.data);
3108}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:262
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition fmgr.c:129
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition fmgr.c:1764
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition fmgr.c:1684
#define PG_RETURN_CSTRING(x)
Definition fmgr.h:364
#define FunctionCall1(flinfo, arg1)
Definition fmgr.h:702
const char * str
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition lsyscache.c:3129
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
static char buf[DEFAULT_XLOG_SEG_SIZE]
static char * DatumGetCString(Datum X)
Definition postgres.h:355
char * c
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
Definition c.h:778
text * cstring_to_text_with_len(const char *s, int len)
Definition varlena.c:196
text * cstring_to_text(const char *s)
Definition varlena.c:184

References a, accumArrayResult(), appendStringInfo(), appendStringInfoChar(), b, brin_range_deserialize(), buf, cstring_to_text(), cstring_to_text_with_len(), CurrentMemoryContext, DatumGetCString(), fb(), fmgr_info(), FunctionCall1, getTypeOutputInfo(), i, idx(), initStringInfo(), makeArrayResult(), SerializedRanges::maxvalues, OidOutputFunctionCall(), OutputFunctionCall(), PG_DETOAST_DATUM, PG_GETARG_DATUM, PG_RETURN_CSTRING, PointerGetDatum(), str, SerializedRanges::typid, and val.

◆ brin_minmax_multi_summary_recv()

Datum brin_minmax_multi_summary_recv ( PG_FUNCTION_ARGS  )

Definition at line 3115 of file brin_minmax_multi.c.

3116{
3117 ereport(ERROR,
3119 errmsg("cannot accept a value of type %s", "brin_minmax_multi_summary")));
3120
3121 PG_RETURN_VOID(); /* keep compiler quiet */
3122}

References ereport, errcode(), errmsg, ERROR, fb(), and PG_RETURN_VOID.

◆ brin_minmax_multi_summary_send()

Datum brin_minmax_multi_summary_send ( PG_FUNCTION_ARGS  )

Definition at line 3132 of file brin_minmax_multi.c.

3133{
3134 return byteasend(fcinfo);
3135}
Datum byteasend(PG_FUNCTION_ARGS)
Definition bytea.c:378

References byteasend().

◆ brin_minmax_multi_union()

Datum brin_minmax_multi_union ( PG_FUNCTION_ARGS  )

Definition at line 2733 of file brin_minmax_multi.c.

2734{
2738
2739 Oid colloid = PG_GET_COLLATION();
2744 AttrNumber attno;
2745 Form_pg_attribute attr;
2747 int neranges;
2748 FmgrInfo *cmpFn,
2749 *distanceFn;
2750 DistanceValue *distances;
2751 MemoryContext ctx;
2753
2754 Assert(col_a->bv_attno == col_b->bv_attno);
2755 Assert(!col_a->bv_allnulls && !col_b->bv_allnulls);
2756
2757 attno = col_a->bv_attno;
2758 attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1);
2759
2762
2765
2766 /* make sure neither of the ranges is NULL */
2768
2769 neranges = (ranges_a->nranges + ranges_a->nvalues) +
2770 (ranges_b->nranges + ranges_b->nvalues);
2771
2772 /*
2773 * The distanceFn calls (which may internally call e.g. numeric_le) may
2774 * allocate quite a bit of memory, and we must not leak it. Otherwise,
2775 * we'd have problems e.g. when building indexes. So we create a local
2776 * memory context and make sure we free the memory before leaving this
2777 * function (not after every call).
2778 */
2780 "minmax-multi context",
2782
2784
2785 /* allocate and fill */
2787
2788 /* fill the expanded ranges with entries for the first range */
2789 fill_expanded_ranges(eranges, ranges_a->nranges + ranges_a->nvalues,
2790 ranges_a);
2791
2792 /* and now add combine ranges for the second range */
2793 fill_expanded_ranges(&eranges[ranges_a->nranges + ranges_a->nvalues],
2794 ranges_b->nranges + ranges_b->nvalues,
2795 ranges_b);
2796
2797 cmpFn = minmax_multi_get_strategy_procinfo(bdesc, attno, attr->atttypid,
2799
2800 /* sort the expanded ranges */
2801 neranges = sort_expanded_ranges(cmpFn, colloid, eranges, neranges);
2802
2803 /*
2804 * We've loaded two different lists of expanded ranges, so some of them
2805 * may be overlapping. So walk through them and merge them.
2806 */
2808
2809 /* check that the combine ranges are correct (no overlaps, ordering) */
2810 AssertCheckExpandedRanges(bdesc, colloid, attno, attr, eranges, neranges);
2811
2812 /*
2813 * If needed, reduce some of the ranges.
2814 *
2815 * XXX This may be fairly expensive, so maybe we should do it only when
2816 * it's actually needed (when we have too many ranges).
2817 */
2818
2819 /* build array of gap distances and sort them in ascending order */
2820 distanceFn = minmax_multi_get_procinfo(bdesc, attno, PROCNUM_DISTANCE);
2821 distances = build_distances(distanceFn, colloid, eranges, neranges);
2822
2823 /*
2824 * See how many values would be needed to store the current ranges, and if
2825 * needed combine as many of them to get below the threshold. The
2826 * collapsed ranges will be stored as a single value.
2827 *
2828 * XXX This does not apply the load factor, as we don't expect to add more
2829 * values to the range, so we prefer to keep as many ranges as possible.
2830 *
2831 * XXX Can the maxvalues be different in the two ranges? Perhaps we should
2832 * use maximum of those?
2833 */
2835 ranges_a->maxvalues,
2836 cmpFn, colloid);
2837
2838 /* Is the result of reducing expanded ranges correct? */
2839 AssertCheckExpandedRanges(bdesc, colloid, attno, attr, eranges, neranges);
2840
2841 /* update the first range summary */
2843
2846
2847 /* cleanup and update the serialized value */
2850
2852}
static void AssertCheckExpandedRanges(BrinDesc *bdesc, Oid colloid, AttrNumber attno, Form_pg_attribute attr, ExpandedRange *ranges, int nranges)
static DistanceValue * build_distances(FmgrInfo *distanceFn, Oid colloid, ExpandedRange *eranges, int neranges)
static int reduce_expanded_ranges(ExpandedRange *eranges, int neranges, DistanceValue *distances, int max_values, FmgrInfo *cmp, Oid colloid)
static FmgrInfo * minmax_multi_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
static int sort_expanded_ranges(FmgrInfo *cmp, Oid colloid, ExpandedRange *eranges, int neranges)
static void fill_expanded_ranges(ExpandedRange *eranges, int neranges, Ranges *ranges)
static int merge_overlapping_ranges(FmgrInfo *cmp, Oid colloid, ExpandedRange *eranges, int neranges)
static void store_expanded_ranges(Ranges *ranges, ExpandedRange *eranges, int neranges)
#define PROCNUM_DISTANCE
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, AssertCheckExpandedRanges(), brin_range_deserialize(), brin_range_serialize(), BTLessStrategyNumber, build_distances(), CurrentMemoryContext, fb(), fill_expanded_ranges(), MemoryContextDelete(), MemoryContextSwitchTo(), merge_overlapping_ranges(), minmax_multi_get_procinfo(), minmax_multi_get_strategy_procinfo(), palloc0(), pfree(), PG_DETOAST_DATUM, PG_GET_COLLATION, PG_GETARG_POINTER, PG_RETURN_VOID, PointerGetDatum(), PROCNUM_DISTANCE, reduce_expanded_ranges(), sort_expanded_ranges(), store_expanded_ranges(), and TupleDescAttr().

◆ brin_range_deserialize()

static Ranges * brin_range_deserialize ( int  maxvalues,
SerializedRanges serialized 
)
static

Definition at line 719 of file brin_minmax_multi.c.

720{
721 int i,
722 nvalues;
723 char *ptr,
724 *dataptr;
725 bool typbyval;
726 int typlen;
727 Size datalen;
728
729 Ranges *range;
730
731 Assert(serialized->nranges >= 0);
732 Assert(serialized->nvalues >= 0);
733 Assert(serialized->maxvalues > 0);
734
735 nvalues = 2 * serialized->nranges + serialized->nvalues;
736
738 Assert(serialized->maxvalues <= maxvalues);
739
740 range = minmax_multi_init(maxvalues);
741
742 /* copy the header info */
743 range->nranges = serialized->nranges;
744 range->nvalues = serialized->nvalues;
745 range->nsorted = serialized->nvalues;
746 range->maxvalues = maxvalues;
747 range->target_maxvalues = serialized->maxvalues;
748
749 range->typid = serialized->typid;
750
751 typbyval = get_typbyval(serialized->typid);
752 typlen = get_typlen(serialized->typid);
753
754 /*
755 * And now deconstruct the values into Datum array. We have to copy the
756 * data because the serialized representation ignores alignment, and we
757 * don't want to rely on it being kept around anyway.
758 */
759 ptr = serialized->data;
760
761 /*
762 * We don't want to allocate many pieces, so we just allocate everything
763 * in one chunk. How much space will we need?
764 *
765 * XXX We don't need to copy simple by-value data types.
766 */
767 datalen = 0;
768 dataptr = NULL;
769 for (i = 0; (i < nvalues) && (!typbyval); i++)
770 {
771 if (typlen > 0) /* fixed-length by-ref types */
772 datalen += MAXALIGN(typlen);
773 else if (typlen == -1) /* varlena */
774 {
775 datalen += MAXALIGN(VARSIZE_ANY(ptr));
776 ptr += VARSIZE_ANY(ptr);
777 }
778 else if (typlen == -2) /* cstring */
779 {
780 Size slen = strlen(ptr) + 1;
781
782 datalen += MAXALIGN(slen);
783 ptr += slen;
784 }
785 }
786
787 if (datalen > 0)
788 dataptr = palloc(datalen);
789
790 /*
791 * Restore the source pointer (might have been modified when calculating
792 * the space we need to allocate).
793 */
794 ptr = serialized->data;
795
796 for (i = 0; i < nvalues; i++)
797 {
798 if (typbyval) /* simple by-value data types */
799 {
800 Datum v = 0;
801
802 memcpy(&v, ptr, typlen);
803
804 range->values[i] = fetch_att(&v, true, typlen);
805 ptr += typlen;
806 }
807 else if (typlen > 0) /* fixed-length by-ref types */
808 {
809 range->values[i] = PointerGetDatum(dataptr);
810
811 memcpy(dataptr, ptr, typlen);
812 dataptr += MAXALIGN(typlen);
813
814 ptr += typlen;
815 }
816 else if (typlen == -1) /* varlena */
817 {
818 range->values[i] = PointerGetDatum(dataptr);
819
820 memcpy(dataptr, ptr, VARSIZE_ANY(ptr));
821 dataptr += MAXALIGN(VARSIZE_ANY(ptr));
822 ptr += VARSIZE_ANY(ptr);
823 }
824 else if (typlen == -2) /* cstring */
825 {
826 Size slen = strlen(ptr) + 1;
827
828 range->values[i] = PointerGetDatum(dataptr);
829
830 memcpy(dataptr, ptr, slen);
831 dataptr += MAXALIGN(slen);
832 ptr += slen;
833 }
834
835 /* make sure we haven't overflown the buffer end */
836 Assert(ptr <= ((char *) serialized + VARSIZE_ANY(serialized)));
837 }
838
839 /* should have consumed the whole input value exactly */
840 Assert(ptr == ((char *) serialized + VARSIZE_ANY(serialized)));
841
842 /* return the deserialized value */
843 return range;
844}
size_t Size
Definition c.h:691
int16 get_typlen(Oid typid)
Definition lsyscache.c:2417
bool get_typbyval(Oid typid)
Definition lsyscache.c:2442
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
int nranges
Definition regguts.h:283
static Datum fetch_att(const void *T, bool attbyval, int attlen)
Definition tupmacs.h:108
static Size VARSIZE_ANY(const void *PTR)
Definition varatt.h:460

References Assert, fb(), fetch_att(), get_typbyval(), get_typlen(), i, MAXALIGN, minmax_multi_init(), cvec::nranges, palloc(), PointerGetDatum(), range(), and VARSIZE_ANY().

Referenced by brin_minmax_multi_add_value(), brin_minmax_multi_consistent(), brin_minmax_multi_summary_out(), and brin_minmax_multi_union().

◆ brin_range_serialize()

static SerializedRanges * brin_range_serialize ( Ranges range)
static

Definition at line 574 of file brin_minmax_multi.c.

575{
576 Size len;
577 int nvalues;
579 Oid typid;
580 int typlen;
581 bool typbyval;
582
583 char *ptr;
584
585 /* simple sanity checks */
586 Assert(range->nranges >= 0);
587 Assert(range->nsorted >= 0);
588 Assert(range->nvalues >= 0);
589 Assert(range->maxvalues > 0);
590 Assert(range->target_maxvalues > 0);
591
592 /* at this point the range should be compacted to the target size */
593 Assert(2 * range->nranges + range->nvalues <= range->target_maxvalues);
594
595 Assert(range->target_maxvalues <= range->maxvalues);
596
597 /* range boundaries are always sorted */
598 Assert(range->nvalues >= range->nsorted);
599
600 /* deduplicate values, if there's unsorted part */
602
603 /* see how many Datum values we actually have */
604 nvalues = 2 * range->nranges + range->nvalues;
605
606 typid = range->typid;
607 typbyval = get_typbyval(typid);
608 typlen = get_typlen(typid);
609
610 /* header is always needed */
612
613 /*
614 * The space needed depends on data type - for fixed-length data types
615 * (by-value and some by-reference) it's pretty simple, just multiply
616 * (attlen * nvalues) and we're done. For variable-length by-reference
617 * types we need to actually walk all the values and sum the lengths.
618 */
619 if (typlen == -1) /* varlena */
620 {
621 int i;
622
623 for (i = 0; i < nvalues; i++)
624 {
625 len += VARSIZE_ANY(DatumGetPointer(range->values[i]));
626 }
627 }
628 else if (typlen == -2) /* cstring */
629 {
630 int i;
631
632 for (i = 0; i < nvalues; i++)
633 {
634 /* don't forget to include the null terminator ;-) */
635 len += strlen(DatumGetCString(range->values[i])) + 1;
636 }
637 }
638 else /* fixed-length types (even by-reference) */
639 {
640 Assert(typlen > 0);
641 len += nvalues * typlen;
642 }
643
644 /*
645 * Allocate the serialized object, copy the basic information. The
646 * serialized object is a varlena, so update the header.
647 */
650
651 serialized->typid = typid;
652 serialized->nranges = range->nranges;
653 serialized->nvalues = range->nvalues;
654 serialized->maxvalues = range->target_maxvalues;
655
656 /*
657 * And now copy also the boundary values (like the length calculation this
658 * depends on the particular data type).
659 */
660 ptr = serialized->data; /* start of the serialized data */
661
662 for (int i = 0; i < nvalues; i++)
663 {
664 if (typbyval) /* simple by-value data types */
665 {
666 Datum tmp;
667
668 /*
669 * For byval types, we need to copy just the significant bytes -
670 * we can't use memcpy directly, as that assumes little-endian
671 * behavior. store_att_byval does almost what we need, but it
672 * requires a properly aligned buffer - the output buffer does not
673 * guarantee that. So we simply use a local Datum variable (which
674 * guarantees proper alignment), and then copy the value from it.
675 */
676 store_att_byval(&tmp, range->values[i], typlen);
677
678 memcpy(ptr, &tmp, typlen);
679 ptr += typlen;
680 }
681 else if (typlen > 0) /* fixed-length by-ref types */
682 {
683 memcpy(ptr, DatumGetPointer(range->values[i]), typlen);
684 ptr += typlen;
685 }
686 else if (typlen == -1) /* varlena */
687 {
688 int tmp = VARSIZE_ANY(DatumGetPointer(range->values[i]));
689
690 memcpy(ptr, DatumGetPointer(range->values[i]), tmp);
691 ptr += tmp;
692 }
693 else if (typlen == -2) /* cstring */
694 {
695 int tmp = strlen(DatumGetCString(range->values[i])) + 1;
696
697 memcpy(ptr, DatumGetCString(range->values[i]), tmp);
698 ptr += tmp;
699 }
700
701 /* make sure we haven't overflown the buffer end */
702 Assert(ptr <= ((char *) serialized + len));
703 }
704
705 /* exact size */
706 Assert(ptr == ((char *) serialized + len));
707
708 return serialized;
709}
static void range_deduplicate_values(Ranges *range)
const void * data
static void store_att_byval(void *T, Datum newdatum, int attlen)
Definition tupmacs.h:457
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432

References Assert, data, DatumGetCString(), DatumGetPointer(), fb(), get_typbyval(), get_typlen(), i, len, cvec::nranges, palloc0(), range(), range_deduplicate_values(), SET_VARSIZE(), store_att_byval(), and VARSIZE_ANY().

Referenced by brin_minmax_multi_serialize(), and brin_minmax_multi_union().

◆ build_distances()

static DistanceValue * build_distances ( FmgrInfo distanceFn,
Oid  colloid,
ExpandedRange eranges,
int  neranges 
)
static

Definition at line 1327 of file brin_minmax_multi.c.

1329{
1330 int i;
1331 int ndistances;
1332 DistanceValue *distances;
1333
1334 Assert(neranges > 0);
1335
1336 /* If there's only a single range, there's no distance to calculate. */
1337 if (neranges == 1)
1338 return NULL;
1339
1340 ndistances = (neranges - 1);
1342
1343 /*
1344 * Walk through the ranges once and compute the distance between the
1345 * ranges so that we can sort them once.
1346 */
1347 for (i = 0; i < ndistances; i++)
1348 {
1349 Datum a1,
1350 a2,
1351 r;
1352
1353 a1 = eranges[i].maxval;
1354 a2 = eranges[i + 1].minval;
1355
1356 /* compute length of the gap (between max/min) */
1357 r = FunctionCall2Coll(distanceFn, colloid, a1, a2);
1358
1359 /* remember the index of the gap the distance is for */
1360 distances[i].index = i;
1361 distances[i].value = DatumGetFloat8(r);
1362 }
1363
1364 /*
1365 * Sort the distances in descending order, so that the longest gaps are at
1366 * the front.
1367 */
1368 qsort(distances, ndistances, sizeof(DistanceValue), compare_distances);
1369
1370 return distances;
1371}
static int compare_distances(const void *a, const void *b)
#define palloc0_array(type, count)
Definition fe_memutils.h:77
#define qsort(a, b, c, d)
Definition port.h:495
static float8 DatumGetFloat8(Datum X)
Definition postgres.h:485

References a1, a2, Assert, compare_distances(), DatumGetFloat8(), fb(), FunctionCall2Coll(), i, DistanceValue::index, palloc0_array, qsort, and DistanceValue::value.

Referenced by brin_minmax_multi_union(), compactify_ranges(), and ensure_free_space_in_buffer().

◆ build_expanded_ranges()

static ExpandedRange * build_expanded_ranges ( FmgrInfo cmp,
Oid  colloid,
Ranges ranges,
int nranges 
)
static

Definition at line 1384 of file brin_minmax_multi.c.

1386{
1387 int neranges;
1389
1390 /* both ranges and points are expanded into a separate element */
1391 neranges = ranges->nranges + ranges->nvalues;
1392
1394
1395 /* fill the expanded ranges */
1397
1398 /* sort and deduplicate the expanded ranges */
1400
1401 /* remember how many ranges we built */
1402 *nranges = neranges;
1403
1404 return eranges;
1405}
static int cmp(const chr *x, const chr *y, size_t len)

References cmp(), fb(), fill_expanded_ranges(), Ranges::nranges, Ranges::nvalues, palloc0(), and sort_expanded_ranges().

Referenced by compactify_ranges(), and ensure_free_space_in_buffer().

◆ compactify_ranges()

static void compactify_ranges ( BrinDesc bdesc,
Ranges ranges,
int  max_values 
)
static

Definition at line 1786 of file brin_minmax_multi.c.

1787{
1788 FmgrInfo *cmpFn,
1789 *distanceFn;
1790
1791 /* expanded ranges */
1793 int neranges;
1794 DistanceValue *distances;
1795
1796 MemoryContext ctx;
1798
1799 /*
1800 * Do we need to actually compactify anything?
1801 *
1802 * There are two reasons why compaction may be needed - firstly, there may
1803 * be too many values, or some of the values may be unsorted.
1804 */
1805 if ((ranges->nranges * 2 + ranges->nvalues <= max_values) &&
1806 (ranges->nsorted == ranges->nvalues))
1807 return;
1808
1809 /* we'll certainly need the comparator, so just look it up now */
1810 cmpFn = minmax_multi_get_strategy_procinfo(bdesc, ranges->attno, ranges->typid,
1812
1813 /* and we'll also need the 'distance' procedure */
1814 distanceFn = minmax_multi_get_procinfo(bdesc, ranges->attno, PROCNUM_DISTANCE);
1815
1816 /*
1817 * The distanceFn calls (which may internally call e.g. numeric_le) may
1818 * allocate quite a bit of memory, and we must not leak it. Otherwise,
1819 * we'd have problems e.g. when building indexes. So we create a local
1820 * memory context and make sure we free the memory before leaving this
1821 * function (not after every call).
1822 */
1824 "minmax-multi context",
1826
1828
1829 /* build the expanded ranges */
1830 eranges = build_expanded_ranges(cmpFn, ranges->colloid, ranges, &neranges);
1831
1832 /* build array of gap distances and sort them in ascending order */
1833 distances = build_distances(distanceFn, ranges->colloid,
1834 eranges, neranges);
1835
1836 /*
1837 * Combine ranges until we get below max_values. We don't use any scale
1838 * factor, because this is used during serialization, and we don't expect
1839 * more tuples to be inserted anytime soon.
1840 */
1842 max_values, cmpFn, ranges->colloid);
1843
1845
1846 /* transform back into regular ranges and single values */
1848
1849 /* check all the range invariants */
1850 AssertCheckRanges(ranges, cmpFn, ranges->colloid);
1851
1854}
static ExpandedRange * build_expanded_ranges(FmgrInfo *cmp, Oid colloid, Ranges *ranges, int *nranges)
static void AssertCheckRanges(Ranges *ranges, FmgrInfo *cmpFn, Oid colloid)

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, AssertCheckRanges(), Ranges::attno, BTLessStrategyNumber, build_distances(), build_expanded_ranges(), Ranges::colloid, CurrentMemoryContext, fb(), MemoryContextDelete(), MemoryContextSwitchTo(), minmax_multi_get_procinfo(), minmax_multi_get_strategy_procinfo(), Ranges::nranges, Ranges::nsorted, Ranges::nvalues, PROCNUM_DISTANCE, reduce_expanded_ranges(), store_expanded_ranges(), and Ranges::typid.

Referenced by brin_minmax_multi_serialize().

◆ compare_distances()

static int compare_distances ( const void a,
const void b 
)
static

Definition at line 1303 of file brin_minmax_multi.c.

1304{
1305 const DistanceValue *da = a;
1306 const DistanceValue *db = b;
1307
1308 if (da->value < db->value)
1309 return 1;
1310 else if (da->value > db->value)
1311 return -1;
1312
1313 return 0;
1314}

References a, b, fb(), and DistanceValue::value.

Referenced by build_distances().

◆ compare_expanded_ranges()

static int compare_expanded_ranges ( const void a,
const void b,
void arg 
)
static

Definition at line 856 of file brin_minmax_multi.c.

857{
858 const ExpandedRange *ra = a;
859 const ExpandedRange *rb = b;
860 Datum r;
861
863
864 /* first compare minvals */
865 r = FunctionCall2Coll(cxt->cmpFn, cxt->colloid, ra->minval, rb->minval);
866
867 if (DatumGetBool(r))
868 return -1;
869
870 r = FunctionCall2Coll(cxt->cmpFn, cxt->colloid, rb->minval, ra->minval);
871
872 if (DatumGetBool(r))
873 return 1;
874
875 /* then compare maxvals */
876 r = FunctionCall2Coll(cxt->cmpFn, cxt->colloid, ra->maxval, rb->maxval);
877
878 if (DatumGetBool(r))
879 return -1;
880
881 r = FunctionCall2Coll(cxt->cmpFn, cxt->colloid, rb->maxval, ra->maxval);
882
883 if (DatumGetBool(r))
884 return 1;
885
886 return 0;
887}
Datum arg
Definition elog.c:1322

References a, arg, b, compare_context::cmpFn, compare_context::colloid, DatumGetBool(), fb(), and FunctionCall2Coll().

Referenced by sort_expanded_ranges().

◆ compare_values()

static int compare_values ( const void a,
const void b,
void arg 
)
static

Definition at line 894 of file brin_minmax_multi.c.

895{
896 const Datum *da = a;
897 const Datum *db = b;
898 Datum r;
899
901
902 r = FunctionCall2Coll(cxt->cmpFn, cxt->colloid, *da, *db);
903
904 if (DatumGetBool(r))
905 return -1;
906
907 r = FunctionCall2Coll(cxt->cmpFn, cxt->colloid, *db, *da);
908
909 if (DatumGetBool(r))
910 return 1;
911
912 return 0;
913}

References a, arg, b, compare_context::cmpFn, compare_context::colloid, DatumGetBool(), fb(), and FunctionCall2Coll().

Referenced by AssertCheckRanges(), range_contains_value(), range_deduplicate_values(), and reduce_expanded_ranges().

◆ ensure_free_space_in_buffer()

static bool ensure_free_space_in_buffer ( BrinDesc bdesc,
Oid  colloid,
AttrNumber  attno,
Form_pg_attribute  attr,
Ranges range 
)
static

Definition at line 1599 of file brin_minmax_multi.c.

1602{
1603 MemoryContext ctx;
1605
1606 FmgrInfo *cmpFn,
1607 *distanceFn;
1608
1609 /* expanded ranges */
1611 int neranges;
1612 DistanceValue *distances;
1613
1614 /*
1615 * If there is free space in the buffer, we're done without having to
1616 * modify anything.
1617 */
1618 if (2 * range->nranges + range->nvalues < range->maxvalues)
1619 return false;
1620
1621 /* we'll certainly need the comparator, so just look it up now */
1622 cmpFn = minmax_multi_get_strategy_procinfo(bdesc, attno, attr->atttypid,
1624
1625 /* deduplicate values, if there's an unsorted part */
1627
1628 /*
1629 * Did we reduce enough free space by just the deduplication?
1630 *
1631 * We don't simply check against range->maxvalues again. The deduplication
1632 * might have freed very little space (e.g. just one value), forcing us to
1633 * do deduplication very often. In that case, it's better to do the
1634 * compaction and reduce more space.
1635 */
1636 if (2 * range->nranges + range->nvalues <= range->maxvalues * MINMAX_BUFFER_LOAD_FACTOR)
1637 return true;
1638
1639 /*
1640 * We need to combine some of the existing ranges, to reduce the number of
1641 * values we have to store.
1642 *
1643 * The distanceFn calls (which may internally call e.g. numeric_le) may
1644 * allocate quite a bit of memory, and we must not leak it (we might have
1645 * to do this repeatedly, even for a single BRIN page range). Otherwise
1646 * we'd have problems e.g. when building new indexes. So we use a memory
1647 * context and make sure we free the memory at the end (so if we call the
1648 * distance function many times, it might be an issue, but meh).
1649 */
1651 "minmax-multi context",
1653
1655
1656 /* build the expanded ranges */
1657 eranges = build_expanded_ranges(cmpFn, colloid, range, &neranges);
1658
1659 /* Is the expanded representation of ranges correct? */
1660 AssertCheckExpandedRanges(bdesc, colloid, attno, attr, eranges, neranges);
1661
1662 /* and we'll also need the 'distance' procedure */
1663 distanceFn = minmax_multi_get_procinfo(bdesc, attno, PROCNUM_DISTANCE);
1664
1665 /* build array of gap distances and sort them in ascending order */
1666 distances = build_distances(distanceFn, colloid, eranges, neranges);
1667
1668 /*
1669 * Combine ranges until we release at least 50% of the space. This
1670 * threshold is somewhat arbitrary, perhaps needs tuning. We must not use
1671 * too low or high value.
1672 */
1674 range->maxvalues * MINMAX_BUFFER_LOAD_FACTOR,
1675 cmpFn, colloid);
1676
1677 /* Is the result of reducing expanded ranges correct? */
1678 AssertCheckExpandedRanges(bdesc, colloid, attno, attr, eranges, neranges);
1679
1680 /* Make sure we've sufficiently reduced the number of ranges. */
1682
1683 /* decompose the expanded ranges into regular ranges and single values */
1685
1688
1689 /* Did we break the ranges somehow? */
1690 AssertCheckRanges(range, cmpFn, colloid);
1691
1692 return true;
1693}
#define MINMAX_BUFFER_LOAD_FACTOR

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, AssertCheckExpandedRanges(), AssertCheckRanges(), BTLessStrategyNumber, build_distances(), build_expanded_ranges(), CurrentMemoryContext, fb(), MemoryContextDelete(), MemoryContextSwitchTo(), MINMAX_BUFFER_LOAD_FACTOR, minmax_multi_get_procinfo(), minmax_multi_get_strategy_procinfo(), cvec::nranges, PROCNUM_DISTANCE, range(), range_deduplicate_values(), reduce_expanded_ranges(), and store_expanded_ranges().

Referenced by range_add_value().

◆ fill_expanded_ranges()

static void fill_expanded_ranges ( ExpandedRange eranges,
int  neranges,
Ranges ranges 
)
static

Definition at line 1132 of file brin_minmax_multi.c.

1133{
1134 int idx;
1135 int i;
1136
1137 /* Check that the output array has the right size. */
1138 Assert(neranges == (ranges->nranges + ranges->nvalues));
1139
1140 idx = 0;
1141 for (i = 0; i < ranges->nranges; i++)
1142 {
1143 eranges[idx].minval = ranges->values[2 * i];
1144 eranges[idx].maxval = ranges->values[2 * i + 1];
1145 eranges[idx].collapsed = false;
1146 idx++;
1147
1148 Assert(idx <= neranges);
1149 }
1150
1151 for (i = 0; i < ranges->nvalues; i++)
1152 {
1153 eranges[idx].minval = ranges->values[2 * ranges->nranges + i];
1154 eranges[idx].maxval = ranges->values[2 * ranges->nranges + i];
1155 eranges[idx].collapsed = true;
1156 idx++;
1157
1158 Assert(idx <= neranges);
1159 }
1160
1161 /* Did we produce the expected number of elements? */
1162 Assert(idx == neranges);
1163
1164 return;
1165}

References Assert, fb(), i, idx(), Ranges::nranges, Ranges::nvalues, and Ranges::values.

Referenced by brin_minmax_multi_union(), and build_expanded_ranges().

◆ has_matching_range()

static bool has_matching_range ( BrinDesc bdesc,
Oid  colloid,
Ranges ranges,
Datum  newval,
AttrNumber  attno,
Oid  typid 
)
static

Definition at line 919 of file brin_minmax_multi.c.

921{
923
926
929
930 /* binary search on ranges */
931 int start,
932 end;
933
934 if (ranges->nranges == 0)
935 return false;
936
937 minvalue = ranges->values[0];
938 maxvalue = ranges->values[2 * ranges->nranges - 1];
939
940 /*
941 * Otherwise, need to compare the new value with boundaries of all the
942 * ranges. First check if it's less than the absolute minimum, which is
943 * the first value in the array.
944 */
948
949 /* smaller than the smallest value in the range list */
950 if (DatumGetBool(compar))
951 return false;
952
953 /*
954 * And now compare it to the existing maximum (last value in the data
955 * array). But only if we haven't already ruled out a possible match in
956 * the minvalue check.
957 */
961
962 if (DatumGetBool(compar))
963 return false;
964
965 /*
966 * So we know it's in the general min/max, the question is whether it
967 * falls in one of the ranges or gaps. We'll do a binary search on
968 * individual ranges - for each range we check equality (value falls into
969 * the range), and then check ranges either above or below the current
970 * range.
971 */
972 start = 0; /* first range */
973 end = (ranges->nranges - 1); /* last range */
974 while (true)
975 {
976 int midpoint = (start + end) / 2;
977
978 /* this means we ran out of ranges in the last step */
979 if (start > end)
980 return false;
981
982 /* copy the min/max values from the ranges */
983 minvalue = ranges->values[2 * midpoint];
984 maxvalue = ranges->values[2 * midpoint + 1];
985
986 /*
987 * Is the value smaller than the minval? If yes, we'll recurse to the
988 * left side of range array.
989 */
991
992 /* smaller than the smallest value in this range */
993 if (DatumGetBool(compar))
994 {
995 end = (midpoint - 1);
996 continue;
997 }
998
999 /*
1000 * Is the value greater than the minval? If yes, we'll recurse to the
1001 * right side of range array.
1002 */
1004
1005 /* larger than the largest value in this range */
1006 if (DatumGetBool(compar))
1007 {
1008 start = (midpoint + 1);
1009 continue;
1010 }
1011
1012 /* hey, we found a matching range */
1013 return true;
1014 }
1015
1016 return false;
1017}

References BTGreaterStrategyNumber, BTLessStrategyNumber, DatumGetBool(), fb(), FunctionCall2Coll(), minmax_multi_get_strategy_procinfo(), newval, Ranges::nranges, start, and Ranges::values.

Referenced by range_contains_value().

◆ merge_overlapping_ranges()

static int merge_overlapping_ranges ( FmgrInfo cmp,
Oid  colloid,
ExpandedRange eranges,
int  neranges 
)
static

Definition at line 1229 of file brin_minmax_multi.c.

1231{
1232 int idx;
1233
1234 /* Merge ranges (idx) and (idx+1) if they overlap. */
1235 idx = 0;
1236 while (idx < (neranges - 1))
1237 {
1238 Datum r;
1239
1240 /*
1241 * comparing [?,maxval] vs. [minval,?] - the ranges overlap if (minval
1242 * < maxval)
1243 */
1244 r = FunctionCall2Coll(cmp, colloid,
1245 eranges[idx].maxval,
1246 eranges[idx + 1].minval);
1247
1248 /*
1249 * Nope, maxval < minval, so no overlap. And we know the ranges are
1250 * ordered, so there are no more overlaps, because all the remaining
1251 * ranges have greater or equal minval.
1252 */
1253 if (DatumGetBool(r))
1254 {
1255 /* proceed to the next range */
1256 idx += 1;
1257 continue;
1258 }
1259
1260 /*
1261 * So ranges 'idx' and 'idx+1' do overlap, but we don't know if
1262 * 'idx+1' is contained in 'idx', or if they overlap only partially.
1263 * So compare the upper bounds and keep the larger one.
1264 */
1265 r = FunctionCall2Coll(cmp, colloid,
1266 eranges[idx].maxval,
1267 eranges[idx + 1].maxval);
1268
1269 if (DatumGetBool(r))
1270 eranges[idx].maxval = eranges[idx + 1].maxval;
1271
1272 /*
1273 * The range certainly is no longer collapsed (irrespectively of the
1274 * previous state).
1275 */
1276 eranges[idx].collapsed = false;
1277
1278 /*
1279 * Now get rid of the (idx+1) range entirely by shifting the remaining
1280 * ranges by 1. There are neranges elements, and we need to move
1281 * elements from (idx+2). That means the number of elements to move is
1282 * [ncranges - (idx+2)].
1283 */
1284 memmove(&eranges[idx + 1], &eranges[idx + 2],
1285 (neranges - (idx + 2)) * sizeof(ExpandedRange));
1286
1287 /*
1288 * Decrease the number of ranges, and repeat (with the same range, as
1289 * it might overlap with additional ranges thanks to the merge).
1290 */
1291 neranges--;
1292 }
1293
1294 return neranges;
1295}

References cmp(), DatumGetBool(), fb(), FunctionCall2Coll(), and idx().

Referenced by brin_minmax_multi_union().

◆ minmax_multi_get_procinfo()

static FmgrInfo * minmax_multi_get_procinfo ( BrinDesc bdesc,
uint16  attno,
uint16  procnum 
)
static

Definition at line 2861 of file brin_minmax_multi.c.

2862{
2863 MinmaxMultiOpaque *opaque;
2865
2866 /*
2867 * We cache these in the opaque struct, to avoid repetitive syscache
2868 * lookups.
2869 */
2870 opaque = (MinmaxMultiOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
2871
2872 if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
2873 {
2874 if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
2875 procnum)))
2876 fmgr_info_copy(&opaque->extra_procinfos[basenum],
2877 index_getprocinfo(bdesc->bd_index, attno, procnum),
2878 bdesc->bd_context);
2879 else
2880 ereport(ERROR,
2882 errmsg_internal("invalid opclass definition"),
2883 errdetail_internal("The operator class is missing support function %d for column %d.",
2884 procnum, attno));
2885 }
2886
2887 return &opaque->extra_procinfos[basenum];
2888}
#define PROCNUM_BASE
#define RegProcedureIsValid(p)
Definition c.h:864
uint16_t uint16
Definition c.h:617
int int errdetail_internal(const char *fmt,...) pg_attribute_printf(1
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition fmgr.c:582
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition indexam.c:918
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition indexam.c:884

References ereport, errcode(), errdetail_internal(), errmsg_internal(), ERROR, MinmaxMultiOpaque::extra_procinfos, fb(), fmgr_info_copy(), FmgrInfo::fn_oid, index_getprocid(), index_getprocinfo(), InvalidOid, PROCNUM_BASE, and RegProcedureIsValid.

Referenced by brin_minmax_multi_union(), compactify_ranges(), and ensure_free_space_in_buffer().

◆ minmax_multi_get_strategy_procinfo()

static FmgrInfo * minmax_multi_get_strategy_procinfo ( BrinDesc bdesc,
uint16  attno,
Oid  subtype,
uint16  strategynum 
)
static

Definition at line 2897 of file brin_minmax_multi.c.

2899{
2900 MinmaxMultiOpaque *opaque;
2901
2902 Assert(strategynum >= 1 &&
2904
2905 opaque = (MinmaxMultiOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
2906
2907 /*
2908 * We cache the procedures for the previous subtype in the opaque struct,
2909 * to avoid repetitive syscache lookups. If the subtype changed,
2910 * invalidate all the cached entries.
2911 */
2912 if (opaque->cached_subtype != subtype)
2913 {
2914 uint16 i;
2915
2916 for (i = 1; i <= BTMaxStrategyNumber; i++)
2917 opaque->strategy_procinfos[i - 1].fn_oid = InvalidOid;
2918 opaque->cached_subtype = subtype;
2919 }
2920
2921 if (opaque->strategy_procinfos[strategynum - 1].fn_oid == InvalidOid)
2922 {
2923 Form_pg_attribute attr;
2924 HeapTuple tuple;
2925 Oid opfamily,
2926 oprid;
2927
2928 opfamily = bdesc->bd_index->rd_opfamily[attno - 1];
2929 attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1);
2931 ObjectIdGetDatum(attr->atttypid),
2932 ObjectIdGetDatum(subtype),
2934 if (!HeapTupleIsValid(tuple))
2935 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2936 strategynum, attr->atttypid, subtype, opfamily);
2937
2940 ReleaseSysCache(tuple);
2942
2944 &opaque->strategy_procinfos[strategynum - 1],
2945 bdesc->bd_context);
2946 }
2947
2948 return &opaque->strategy_procinfos[strategynum - 1];
2949}
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition fmgr.c:139
#define HeapTupleIsValid(tuple)
Definition htup.h:78
RegProcedure get_opcode(Oid opno)
Definition lsyscache.c:1505
Oid oprid(Operator op)
Definition parse_oper.c:241
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
static Datum UInt16GetDatum(uint16 X)
Definition postgres.h:192
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
#define BTMaxStrategyNumber
Definition stratnum.h:35
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626
HeapTuple SearchSysCache4(SysCacheIdentifier cacheId, Datum key1, Datum key2, Datum key3, Datum key4)
Definition syscache.c:251

References Assert, BTMaxStrategyNumber, MinmaxMultiOpaque::cached_subtype, DatumGetObjectId(), elog, ERROR, fb(), fmgr_info_cxt(), FmgrInfo::fn_oid, get_opcode(), HeapTupleIsValid, i, InvalidOid, ObjectIdGetDatum(), oprid(), RegProcedureIsValid, ReleaseSysCache(), SearchSysCache4(), MinmaxMultiOpaque::strategy_procinfos, SysCacheGetAttrNotNull(), TupleDescAttr(), and UInt16GetDatum().

Referenced by AssertCheckExpandedRanges(), brin_minmax_multi_add_value(), brin_minmax_multi_consistent(), brin_minmax_multi_union(), compactify_ranges(), ensure_free_space_in_buffer(), has_matching_range(), range_add_value(), and range_contains_value().

◆ minmax_multi_init()

static Ranges * minmax_multi_init ( int  maxvalues)
static

Definition at line 484 of file brin_minmax_multi.c.

485{
486 Size len;
487 Ranges *ranges;
488
489 Assert(maxvalues > 0);
490
491 len = offsetof(Ranges, values); /* fixed header */
492 len += maxvalues * sizeof(Datum); /* Datum values */
493
494 ranges = (Ranges *) palloc0(len);
495
496 ranges->maxvalues = maxvalues;
497
498 return ranges;
499}
static Datum values[MAXATTR]
Definition bootstrap.c:188

References Assert, fb(), len, Ranges::maxvalues, palloc0(), and values.

Referenced by brin_minmax_multi_add_value(), and brin_range_deserialize().

◆ range_add_value()

static bool range_add_value ( BrinDesc bdesc,
Oid  colloid,
AttrNumber  attno,
Form_pg_attribute  attr,
Ranges ranges,
Datum  newval 
)
static

Definition at line 1700 of file brin_minmax_multi.c.

1703{
1704 FmgrInfo *cmpFn;
1705 bool modified = false;
1706
1707 /* we'll certainly need the comparator, so just look it up now */
1708 cmpFn = minmax_multi_get_strategy_procinfo(bdesc, attno, attr->atttypid,
1710
1711 /* comprehensive checks of the input ranges */
1712 AssertCheckRanges(ranges, cmpFn, colloid);
1713
1714 /*
1715 * Make sure there's enough free space in the buffer. We only trigger this
1716 * when the buffer is full, which means it had to be modified as we size
1717 * it to be larger than what is stored on disk.
1718 *
1719 * This needs to happen before we check if the value is contained in the
1720 * range, because the value might be in the unsorted part, and we don't
1721 * check that in range_contains_value. The deduplication would then move
1722 * it to the sorted part, and we'd add the value too, which violates the
1723 * rule that we never have duplicates with the ranges or sorted values.
1724 *
1725 * We might also deduplicate and recheck if the value is contained, but
1726 * that seems like overkill. We'd need to deduplicate anyway, so why not
1727 * do it now.
1728 */
1730 attno, attr, ranges);
1731
1732 /*
1733 * Bail out if the value already is covered by the range.
1734 *
1735 * We could also add values until we hit values_per_range, and then do the
1736 * deduplication in a batch, hoping for better efficiency. But that would
1737 * mean we actually modify the range every time, which means having to
1738 * serialize the value, which does palloc, walks the values, copies them,
1739 * etc. Not exactly cheap.
1740 *
1741 * So instead we do the check, which should be fairly cheap - assuming the
1742 * comparator function is not very expensive.
1743 *
1744 * This also implies the values array can't contain duplicate values.
1745 */
1746 if (range_contains_value(bdesc, colloid, attno, attr, ranges, newval, false))
1747 return modified;
1748
1749 /* Make a copy of the value, if needed. */
1750 newval = datumCopy(newval, attr->attbyval, attr->attlen);
1751
1752 /*
1753 * If there's space in the values array, copy it in and we're done.
1754 *
1755 * We do want to keep the values sorted (to speed up searches), so we do a
1756 * simple insertion sort. We could do something more elaborate, e.g. by
1757 * sorting the values only now and then, but for small counts (e.g. when
1758 * maxvalues is 64) this should be fine.
1759 */
1760 ranges->values[2 * ranges->nranges + ranges->nvalues] = newval;
1761 ranges->nvalues++;
1762
1763 /* If we added the first value, we can consider it as sorted. */
1764 if (ranges->nvalues == 1)
1765 ranges->nsorted = 1;
1766
1767 /*
1768 * Check we haven't broken the ordering of boundary values (checks both
1769 * parts, but that doesn't hurt).
1770 */
1771 AssertCheckRanges(ranges, cmpFn, colloid);
1772
1773 /* Check the range contains the value we just added. */
1774 Assert(range_contains_value(bdesc, colloid, attno, attr, ranges, newval, true));
1775
1776 /* yep, we've modified the range */
1777 return true;
1778}
static bool ensure_free_space_in_buffer(BrinDesc *bdesc, Oid colloid, AttrNumber attno, Form_pg_attribute attr, Ranges *range)
static bool range_contains_value(BrinDesc *bdesc, Oid colloid, AttrNumber attno, Form_pg_attribute attr, Ranges *ranges, Datum newval, bool full)
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition datum.c:132

References Assert, AssertCheckRanges(), BTLessStrategyNumber, datumCopy(), ensure_free_space_in_buffer(), fb(), minmax_multi_get_strategy_procinfo(), newval, Ranges::nranges, Ranges::nsorted, Ranges::nvalues, range_contains_value(), and Ranges::values.

Referenced by brin_minmax_multi_add_value().

◆ range_contains_value()

static bool range_contains_value ( BrinDesc bdesc,
Oid  colloid,
AttrNumber  attno,
Form_pg_attribute  attr,
Ranges ranges,
Datum  newval,
bool  full 
)
static

Definition at line 1043 of file brin_minmax_multi.c.

1046{
1047 int i;
1049 Oid typid = attr->atttypid;
1050
1051 /*
1052 * First inspect the ranges, if there are any. We first check the whole
1053 * range, and only when there's still a chance of getting a match we
1054 * inspect the individual ranges.
1055 */
1056 if (has_matching_range(bdesc, colloid, ranges, newval, attno, typid))
1057 return true;
1058
1061
1062 /*
1063 * There is no matching range, so let's inspect the sorted values.
1064 *
1065 * We do a sequential search for small numbers of values, and binary
1066 * search once we have more than 16 values. This threshold is somewhat
1067 * arbitrary, as it depends on how expensive the comparison function is.
1068 *
1069 * XXX If we use the threshold here, maybe we should do the same thing in
1070 * has_matching_range? Or maybe we should do the bin search all the time?
1071 *
1072 * XXX We could use the same optimization as for ranges, to check if the
1073 * value is between min/max, to maybe rule out all sorted values without
1074 * having to inspect all of them.
1075 */
1076 if (ranges->nsorted >= 16)
1077 {
1078 compare_context cxt;
1079
1080 cxt.colloid = ranges->colloid;
1081 cxt.cmpFn = ranges->cmp;
1082
1083 if (bsearch_arg(&newval, &ranges->values[2 * ranges->nranges],
1084 ranges->nsorted, sizeof(Datum),
1085 compare_values, &cxt) != NULL)
1086 return true;
1087 }
1088 else
1089 {
1090 for (i = 2 * ranges->nranges; i < 2 * ranges->nranges + ranges->nsorted; i++)
1091 {
1092 Datum compar;
1093
1094 compar = FunctionCall2Coll(cmpEqualFn, colloid, newval, ranges->values[i]);
1095
1096 /* found an exact match */
1097 if (DatumGetBool(compar))
1098 return true;
1099 }
1100 }
1101
1102 /* If not asked to inspect the unsorted part, we're done. */
1103 if (!full)
1104 return false;
1105
1106 /* Inspect the unsorted part. */
1107 for (i = 2 * ranges->nranges + ranges->nsorted; i < 2 * ranges->nranges + ranges->nvalues; i++)
1108 {
1109 Datum compar;
1110
1111 compar = FunctionCall2Coll(cmpEqualFn, colloid, newval, ranges->values[i]);
1112
1113 /* found an exact match */
1114 if (DatumGetBool(compar))
1115 return true;
1116 }
1117
1118 /* the value is not covered by this BRIN tuple */
1119 return false;
1120}
static bool has_matching_range(BrinDesc *bdesc, Oid colloid, Ranges *ranges, Datum newval, AttrNumber attno, Oid typid)

References bsearch_arg(), BTEqualStrategyNumber, Ranges::cmp, compare_context::cmpFn, Ranges::colloid, compare_context::colloid, compare_values(), DatumGetBool(), fb(), FunctionCall2Coll(), has_matching_range(), i, minmax_multi_get_strategy_procinfo(), newval, Ranges::nranges, Ranges::nsorted, Ranges::nvalues, and Ranges::values.

Referenced by range_add_value().

◆ range_deduplicate_values()

static void range_deduplicate_values ( Ranges range)
static

Definition at line 514 of file brin_minmax_multi.c.

515{
516 int i,
517 n;
518 int start;
519 compare_context cxt;
520
521 /*
522 * If there are no unsorted values, we're done (this probably can't
523 * happen, as we're adding values to unsorted part).
524 */
525 if (range->nsorted == range->nvalues)
526 return;
527
528 /* sort the values */
529 cxt.colloid = range->colloid;
530 cxt.cmpFn = range->cmp;
531
532 /* the values start right after the ranges (which are always sorted) */
533 start = 2 * range->nranges;
534
535 /*
536 * XXX This might do a merge sort, to leverage that the first part of the
537 * array is already sorted. If the sorted part is large, it might be quite
538 * a bit faster.
539 */
540 qsort_arg(&range->values[start],
541 range->nvalues, sizeof(Datum),
542 compare_values, &cxt);
543
544 n = 1;
545 for (i = 1; i < range->nvalues; i++)
546 {
547 /* same as preceding value, so store it */
548 if (compare_values(&range->values[start + i - 1],
549 &range->values[start + i],
550 &cxt) == 0)
551 continue;
552
553 range->values[start + n] = range->values[start + i];
554
555 n++;
556 }
557
558 /* now all the values are sorted */
559 range->nvalues = n;
560 range->nsorted = n;
561
562 AssertCheckRanges(range, range->cmp, range->colloid);
563}
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)

References AssertCheckRanges(), compare_context::cmpFn, compare_context::colloid, compare_values(), i, cvec::nranges, qsort_arg(), range(), and start.

Referenced by brin_range_serialize(), and ensure_free_space_in_buffer().

◆ reduce_expanded_ranges()

static int reduce_expanded_ranges ( ExpandedRange eranges,
int  neranges,
DistanceValue distances,
int  max_values,
FmgrInfo cmp,
Oid  colloid 
)
static

Definition at line 1474 of file brin_minmax_multi.c.

1477{
1478 int i;
1479 int nvalues;
1480 Datum *values;
1481
1482 compare_context cxt;
1483
1484 /* total number of gaps between ranges */
1485 int ndistances = (neranges - 1);
1486
1487 /* number of gaps to keep */
1488 int keep = (max_values / 2 - 1);
1489
1490 /*
1491 * Maybe we have a sufficiently low number of ranges already?
1492 *
1493 * XXX This should happen before we actually do the expensive stuff like
1494 * sorting, so maybe this should be just an assert.
1495 */
1496 if (keep >= ndistances)
1497 return neranges;
1498
1499 /* sort the values */
1500 cxt.colloid = colloid;
1501 cxt.cmpFn = cmp;
1502
1503 /* allocate space for the boundary values */
1504 nvalues = 0;
1506
1507 /* add the global min/max values, from the first/last range */
1508 values[nvalues++] = eranges[0].minval;
1509 values[nvalues++] = eranges[neranges - 1].maxval;
1510
1511 /* add boundary values for enough gaps */
1512 for (i = 0; i < keep; i++)
1513 {
1514 /* index of the gap between (index) and (index+1) ranges */
1515 int index = distances[i].index;
1516
1517 Assert((index >= 0) && ((index + 1) < neranges));
1518
1519 /* add max from the preceding range, minval from the next one */
1520 values[nvalues++] = eranges[index].maxval;
1521 values[nvalues++] = eranges[index + 1].minval;
1522
1523 Assert(nvalues <= max_values);
1524 }
1525
1526 /* We should have an even number of range values. */
1527 Assert(nvalues % 2 == 0);
1528
1529 /*
1530 * Sort the values using the comparator function, and form ranges from the
1531 * sorted result.
1532 */
1533 qsort_arg(values, nvalues, sizeof(Datum),
1534 compare_values, &cxt);
1535
1536 /* We have nvalues boundary values, which means nvalues/2 ranges. */
1537 for (i = 0; i < (nvalues / 2); i++)
1538 {
1539 eranges[i].minval = values[2 * i];
1540 eranges[i].maxval = values[2 * i + 1];
1541
1542 /* if the boundary values are the same, it's a collapsed range */
1543 eranges[i].collapsed = (compare_values(&values[2 * i],
1544 &values[2 * i + 1],
1545 &cxt) == 0);
1546 }
1547
1548 return (nvalues / 2);
1549}
#define palloc_array(type, count)
Definition fe_memutils.h:76
Definition type.h:96

References Assert, cmp(), compare_context::cmpFn, compare_context::colloid, compare_values(), fb(), i, DistanceValue::index, palloc_array, qsort_arg(), and values.

Referenced by brin_minmax_multi_union(), compactify_ranges(), and ensure_free_space_in_buffer().

◆ sort_expanded_ranges()

static int sort_expanded_ranges ( FmgrInfo cmp,
Oid  colloid,
ExpandedRange eranges,
int  neranges 
)
static

Definition at line 1177 of file brin_minmax_multi.c.

1179{
1180 int n;
1181 int i;
1182 compare_context cxt;
1183
1184 Assert(neranges > 0);
1185
1186 /* sort the values */
1187 cxt.colloid = colloid;
1188 cxt.cmpFn = cmp;
1189
1190 /*
1191 * XXX We do qsort on all the values, but we could also leverage the fact
1192 * that some of the input data is already sorted (all the ranges and maybe
1193 * some of the points) and do merge sort.
1194 */
1197
1198 /*
1199 * Deduplicate the ranges - simply compare each range to the preceding
1200 * one, and skip the duplicate ones.
1201 */
1202 n = 1;
1203 for (i = 1; i < neranges; i++)
1204 {
1205 /* if the current range is equal to the preceding one, do nothing */
1206 if (!compare_expanded_ranges(&eranges[i - 1], &eranges[i], &cxt))
1207 continue;
1208
1209 /* otherwise, copy it to n-th place (if not already there) */
1210 if (i != n)
1211 memcpy(&eranges[n], &eranges[i], sizeof(ExpandedRange));
1212
1213 n++;
1214 }
1215
1216 Assert((n > 0) && (n <= neranges));
1217
1218 return n;
1219}
static int compare_expanded_ranges(const void *a, const void *b, void *arg)

References Assert, cmp(), compare_context::cmpFn, compare_context::colloid, compare_expanded_ranges(), fb(), i, and qsort_arg().

Referenced by brin_minmax_multi_union(), and build_expanded_ranges().

◆ store_expanded_ranges()

static void store_expanded_ranges ( Ranges ranges,
ExpandedRange eranges,
int  neranges 
)
static

Definition at line 1556 of file brin_minmax_multi.c.

1557{
1558 int i;
1559 int idx = 0;
1560
1561 /* first copy in the regular ranges */
1562 ranges->nranges = 0;
1563 for (i = 0; i < neranges; i++)
1564 {
1565 if (!eranges[i].collapsed)
1566 {
1567 ranges->values[idx++] = eranges[i].minval;
1568 ranges->values[idx++] = eranges[i].maxval;
1569 ranges->nranges++;
1570 }
1571 }
1572
1573 /* now copy in the collapsed ones */
1574 ranges->nvalues = 0;
1575 for (i = 0; i < neranges; i++)
1576 {
1577 if (eranges[i].collapsed)
1578 {
1579 ranges->values[idx++] = eranges[i].minval;
1580 ranges->nvalues++;
1581 }
1582 }
1583
1584 /* all the values are sorted */
1585 ranges->nsorted = ranges->nvalues;
1586
1587 Assert(count_values(eranges, neranges) == 2 * ranges->nranges + ranges->nvalues);
1588 Assert(2 * ranges->nranges + ranges->nvalues <= ranges->maxvalues);
1589}

References Assert, fb(), i, idx(), Ranges::maxvalues, Ranges::nranges, Ranges::nsorted, Ranges::nvalues, and Ranges::values.

Referenced by brin_minmax_multi_union(), compactify_ranges(), and ensure_free_space_in_buffer().