BRIN bloom indexes

Adds a BRIN opclass using a Bloom filter to summarize the range. Indexes
using the new opclasses allow only equality queries (similar to hash
indexes), but that works fine for data like UUID, MAC addresses etc. for
which range queries are not very common. This also means the indexes
work for data that is not well correlated to physical location within
the table, or perhaps even entirely random (which is a common issue with
existing BRIN minmax opclasses).

It's possible to specify opclass parameters with the usual Bloom filter
parameters, i.e. the desired false-positive rate and the expected number
of distinct values per page range.

  CREATE TABLE t (a int);
  CREATE INDEX ON t
   USING brin (a int4_bloom_ops(false_positive_rate = 0.05,
                                n_distinct_per_range = 100));

The opclasses do not operate on the indexed values directly, but compute
a 32-bit hash first, and the Bloom filter is built on the hash value.
Collisions should not be a huge issue though, as the number of distinct
values in a page ranges is usually fairly small.

Bump catversion, due to various catalog changes.

Author: Tomas Vondra <tomas.vondra@postgresql.org>
Reviewed-by: Alvaro Herrera <alvherre@alvh.no-ip.org>
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Reviewed-by: Sokolov Yura <y.sokolov@postgrespro.ru>
Reviewed-by: Nico Williams <nico@cryptonector.com>
Reviewed-by: John Naylor <john.naylor@enterprisedb.com>
Discussion: https://postgr.es/m/c1138ead-7668-f0e1-0638-c3be3237e812@2ndquadrant.com
Discussion: https://postgr.es/m/5d78b774-7e9c-c94e-12cf-fef51cc89b1a%402ndquadrant.com
This commit is contained in:
Tomas Vondra 2021-03-26 13:35:29 +01:00
parent a681e3c107
commit 77b88cd1bb
17 changed files with 2567 additions and 8 deletions

View File

@ -115,7 +115,8 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
operator classes store the minimum and the maximum values appearing
in the indexed column within the range. The <firstterm>inclusion</firstterm>
operator classes store a value which includes the values in the indexed
column within the range.
column within the range. The <firstterm>bloom</firstterm> operator
classes build a Bloom filter for all values in the range.
</para>
<table id="brin-builtin-opclasses-table">
@ -154,6 +155,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>|&amp;&gt; (box,box)</literal></entry></row>
<row><entry><literal>|&gt;&gt; (box,box)</literal></entry></row>
<row>
<entry valign="middle"><literal>bpchar_bloom_ops</literal></entry>
<entry><literal>= (character,character)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>bpchar_minmax_ops</literal></entry>
<entry><literal>= (character,character)</literal></entry>
@ -163,6 +169,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (character,character)</literal></entry></row>
<row><entry><literal>&gt;= (character,character)</literal></entry></row>
<row>
<entry valign="middle"><literal>bytea_bloom_ops</literal></entry>
<entry><literal>= (bytea,bytea)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>bytea_minmax_ops</literal></entry>
<entry><literal>= (bytea,bytea)</literal></entry>
@ -172,6 +183,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (bytea,bytea)</literal></entry></row>
<row><entry><literal>&gt;= (bytea,bytea)</literal></entry></row>
<row>
<entry valign="middle"><literal>char_bloom_ops</literal></entry>
<entry><literal>= ("char","char")</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>char_minmax_ops</literal></entry>
<entry><literal>= ("char","char")</literal></entry>
@ -181,6 +197,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; ("char","char")</literal></entry></row>
<row><entry><literal>&gt;= ("char","char")</literal></entry></row>
<row>
<entry valign="middle"><literal>date_bloom_ops</literal></entry>
<entry><literal>= (date,date)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>date_minmax_ops</literal></entry>
<entry><literal>= (date,date)</literal></entry>
@ -190,6 +211,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (date,date)</literal></entry></row>
<row><entry><literal>&gt;= (date,date)</literal></entry></row>
<row>
<entry valign="middle"><literal>float4_bloom_ops</literal></entry>
<entry><literal>= (float4,float4)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>float4_minmax_ops</literal></entry>
<entry><literal>= (float4,float4)</literal></entry>
@ -199,6 +225,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&lt;= (float4,float4)</literal></entry></row>
<row><entry><literal>&gt;= (float4,float4)</literal></entry></row>
<row>
<entry valign="middle"><literal>float8_bloom_ops</literal></entry>
<entry><literal>= (float8,float8)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>float8_minmax_ops</literal></entry>
<entry><literal>= (float8,float8)</literal></entry>
@ -218,6 +249,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>= (inet,inet)</literal></entry></row>
<row><entry><literal>&amp;&amp; (inet,inet)</literal></entry></row>
<row>
<entry valign="middle"><literal>inet_bloom_ops</literal></entry>
<entry><literal>= (inet,inet)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>inet_minmax_ops</literal></entry>
<entry><literal>= (inet,inet)</literal></entry>
@ -227,6 +263,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (inet,inet)</literal></entry></row>
<row><entry><literal>&gt;= (inet,inet)</literal></entry></row>
<row>
<entry valign="middle"><literal>int2_bloom_ops</literal></entry>
<entry><literal>= (int2,int2)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>int2_minmax_ops</literal></entry>
<entry><literal>= (int2,int2)</literal></entry>
@ -236,6 +277,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&lt;= (int2,int2)</literal></entry></row>
<row><entry><literal>&gt;= (int2,int2)</literal></entry></row>
<row>
<entry valign="middle"><literal>int4_bloom_ops</literal></entry>
<entry><literal>= (int4,int4)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>int4_minmax_ops</literal></entry>
<entry><literal>= (int4,int4)</literal></entry>
@ -245,6 +291,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&lt;= (int4,int4)</literal></entry></row>
<row><entry><literal>&gt;= (int4,int4)</literal></entry></row>
<row>
<entry valign="middle"><literal>int8_bloom_ops</literal></entry>
<entry><literal>= (bigint,bigint)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>int8_minmax_ops</literal></entry>
<entry><literal>= (bigint,bigint)</literal></entry>
@ -254,6 +305,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&lt;= (bigint,bigint)</literal></entry></row>
<row><entry><literal>&gt;= (bigint,bigint)</literal></entry></row>
<row>
<entry valign="middle"><literal>interval_bloom_ops</literal></entry>
<entry><literal>= (interval,interval)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>interval_minmax_ops</literal></entry>
<entry><literal>= (interval,interval)</literal></entry>
@ -263,6 +319,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (interval,interval)</literal></entry></row>
<row><entry><literal>&gt;= (interval,interval)</literal></entry></row>
<row>
<entry valign="middle"><literal>macaddr_bloom_ops</literal></entry>
<entry><literal>= (macaddr,macaddr)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>macaddr_minmax_ops</literal></entry>
<entry><literal>= (macaddr,macaddr)</literal></entry>
@ -272,6 +333,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (macaddr,macaddr)</literal></entry></row>
<row><entry><literal>&gt;= (macaddr,macaddr)</literal></entry></row>
<row>
<entry valign="middle"><literal>macaddr8_bloom_ops</literal></entry>
<entry><literal>= (macaddr8,macaddr8)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>macaddr8_minmax_ops</literal></entry>
<entry><literal>= (macaddr8,macaddr8)</literal></entry>
@ -281,6 +347,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (macaddr8,macaddr8)</literal></entry></row>
<row><entry><literal>&gt;= (macaddr8,macaddr8)</literal></entry></row>
<row>
<entry valign="middle"><literal>name_bloom_ops</literal></entry>
<entry><literal>= (name,name)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>name_minmax_ops</literal></entry>
<entry><literal>= (name,name)</literal></entry>
@ -290,6 +361,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (name,name)</literal></entry></row>
<row><entry><literal>&gt;= (name,name)</literal></entry></row>
<row>
<entry valign="middle"><literal>numeric_bloom_ops</literal></entry>
<entry><literal>= (numeric,numeric)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>numeric_minmax_ops</literal></entry>
<entry><literal>= (numeric,numeric)</literal></entry>
@ -299,6 +375,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (numeric,numeric)</literal></entry></row>
<row><entry><literal>&gt;= (numeric,numeric)</literal></entry></row>
<row>
<entry valign="middle"><literal>oid_bloom_ops</literal></entry>
<entry><literal>= (oid,oid)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>oid_minmax_ops</literal></entry>
<entry><literal>= (oid,oid)</literal></entry>
@ -308,6 +389,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&lt;= (oid,oid)</literal></entry></row>
<row><entry><literal>&gt;= (oid,oid)</literal></entry></row>
<row>
<entry valign="middle"><literal>pg_lsn_bloom_ops</literal></entry>
<entry><literal>= (pg_lsn,pg_lsn)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>pg_lsn_minmax_ops</literal></entry>
<entry><literal>= (pg_lsn,pg_lsn)</literal></entry>
@ -335,6 +421,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&amp;&gt; (anyrange,anyrange)</literal></entry></row>
<row><entry><literal>-|- (anyrange,anyrange)</literal></entry></row>
<row>
<entry valign="middle"><literal>text_bloom_ops</literal></entry>
<entry><literal>= (text,text)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>text_minmax_ops</literal></entry>
<entry><literal>= (text,text)</literal></entry>
@ -344,6 +435,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (text,text)</literal></entry></row>
<row><entry><literal>&gt;= (text,text)</literal></entry></row>
<row>
<entry valign="middle"><literal>tid_bloom_ops</literal></entry>
<entry><literal>= (tid,tid)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>tid_minmax_ops</literal></entry>
<entry><literal>= (tid,tid)</literal></entry>
@ -353,6 +449,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&lt;= (tid,tid)</literal></entry></row>
<row><entry><literal>&gt;= (tid,tid)</literal></entry></row>
<row>
<entry valign="middle"><literal>timestamp_bloom_ops</literal></entry>
<entry><literal>= (timestamp,timestamp)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>timestamp_minmax_ops</literal></entry>
<entry><literal>= (timestamp,timestamp)</literal></entry>
@ -362,6 +463,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (timestamp,timestamp)</literal></entry></row>
<row><entry><literal>&gt;= (timestamp,timestamp)</literal></entry></row>
<row>
<entry valign="middle"><literal>timestamptz_bloom_ops</literal></entry>
<entry><literal>= (timestamptz,timestamptz)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>timestamptz_minmax_ops</literal></entry>
<entry><literal>= (timestamptz,timestamptz)</literal></entry>
@ -371,6 +477,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (timestamptz,timestamptz)</literal></entry></row>
<row><entry><literal>&gt;= (timestamptz,timestamptz)</literal></entry></row>
<row>
<entry valign="middle"><literal>time_bloom_ops</literal></entry>
<entry><literal>= (time,time)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>time_minmax_ops</literal></entry>
<entry><literal>= (time,time)</literal></entry>
@ -380,6 +491,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (time,time)</literal></entry></row>
<row><entry><literal>&gt;= (time,time)</literal></entry></row>
<row>
<entry valign="middle"><literal>timetz_bloom_ops</literal></entry>
<entry><literal>= (timetz,timetz)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>timetz_minmax_ops</literal></entry>
<entry><literal>= (timetz,timetz)</literal></entry>
@ -389,6 +505,11 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
<row><entry><literal>&gt; (timetz,timetz)</literal></entry></row>
<row><entry><literal>&gt;= (timetz,timetz)</literal></entry></row>
<row>
<entry valign="middle"><literal>uuid_bloom_ops</literal></entry>
<entry><literal>= (uuid,uuid)</literal></entry>
</row>
<row>
<entry valign="middle" morerows="4"><literal>uuid_minmax_ops</literal></entry>
<entry><literal>= (uuid,uuid)</literal></entry>
@ -409,6 +530,55 @@ LOG: request for BRIN range summarization for index "brin_wi_idx" page 128 was
</tbody>
</tgroup>
</table>
<sect2 id="brin-builtin-opclasses--parameters">
<title>Operator Class Parameters</title>
<para>
Some of the built-in operator classes allow specifying parameters affecting
behavior of the operator class. Each operator class has its own set of
allowed parameters. Only the <literal>bloom</literal> operator class
allows specifying parameters:
</para>
<para>
<acronym>bloom</acronym> operator classes accept these parameters:
</para>
<variablelist>
<varlistentry>
<term><literal>n_distinct_per_range</literal></term>
<listitem>
<para>
Defines the estimated number of distinct non-null values in the block
range, used by <acronym>BRIN</acronym> bloom indexes for sizing of the
Bloom filter. It behaves similarly to <literal>n_distinct</literal> option
for <xref linkend="sql-altertable"/>. When set to a positive value,
each block range is assumed to contain this number of distinct non-null
values. When set to a negative value, which must be greater than or
equal to -1, the number of distinct non-null is assumed linear with
the maximum possible number of tuples in the block range (about 290
rows per block). The default value is <literal>-0.1</literal>, and
the minimum number of distinct non-null values is <literal>16</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>false_positive_rate</literal></term>
<listitem>
<para>
Defines the desired false positive rate used by <acronym>BRIN</acronym>
bloom indexes for sizing of the Bloom filter. The values must be
between 0.0001 and 0.25. The default value is 0.01, which is 1% false
positive rate.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
</sect1>
<sect1 id="brin-extensibility">
@ -794,6 +964,60 @@ typedef struct BrinOpcInfo
function can improve index performance.
</para>
<para>
To write an operator class for a data type that implements only an equality
operator and supports hashing, it is possible to use the bloom support procedures
alongside the corresponding operators, as shown in
<xref linkend="brin-extensibility-bloom-table"/>.
All operator class members (procedures and operators) are mandatory.
</para>
<table id="brin-extensibility-bloom-table">
<title>Procedure and Support Numbers for Bloom Operator Classes</title>
<tgroup cols="2">
<thead>
<row>
<entry>Operator class member</entry>
<entry>Object</entry>
</row>
</thead>
<tbody>
<row>
<entry>Support Procedure 1</entry>
<entry>internal function <function>brin_bloom_opcinfo()</function></entry>
</row>
<row>
<entry>Support Procedure 2</entry>
<entry>internal function <function>brin_bloom_add_value()</function></entry>
</row>
<row>
<entry>Support Procedure 3</entry>
<entry>internal function <function>brin_bloom_consistent()</function></entry>
</row>
<row>
<entry>Support Procedure 4</entry>
<entry>internal function <function>brin_bloom_union()</function></entry>
</row>
<row>
<entry>Support Procedure 11</entry>
<entry>function to compute hash of an element</entry>
</row>
<row>
<entry>Operator Strategy 1</entry>
<entry>operator equal-to</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Support procedure numbers 1-10 are reserved for the BRIN internal
functions, so the SQL level functions start with number 11. Support
function number 11 is the main function required to build the index.
It should accept one argument with the same data type as the operator class,
and return a hash of the value.
</para>
<para>
Both minmax and inclusion operator classes support cross-data-type
operators, though with these the dependencies become more complicated.

View File

@ -14,6 +14,7 @@ include $(top_builddir)/src/Makefile.global
OBJS = \
brin.o \
brin_bloom.o \
brin_inclusion.o \
brin_minmax.o \
brin_pageops.o \

View File

@ -0,0 +1,809 @@
/*
* brin_bloom.c
* Implementation of Bloom opclass for BRIN
*
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* A BRIN opclass summarizing page range into a bloom filter.
*
* Bloom filters allow efficient testing whether a given page range contains
* a particular value. Therefore, if we summarize each page range into a small
* bloom filter, we can easily (and cheaply) test whether it contains values
* we get later.
*
* The index only supports equality operators, similarly to hash indexes.
* Bloom indexes are however much smaller, and support only bitmap scans.
*
* Note: Don't confuse this with bloom indexes, implemented in a contrib
* module. That extension implements an entirely new AM, building a bloom
* filter on multiple columns in a single row. This opclass works with an
* existing AM (BRIN) and builds bloom filter on a column.
*
*
* values vs. hashes
* -----------------
*
* The original column values are not used directly, but are first hashed
* using the regular type-specific hash function, producing a uint32 hash.
* And this hash value is then added to the summary - i.e. it's hashed
* again and added to the bloom filter.
*
* This allows the code to treat all data types (byval/byref/...) the same
* way, with only minimal space requirements, because we're working with
* hashes and not the original values. Everything is uint32.
*
* Of course, this assumes the built-in hash function is reasonably good,
* without too many collisions etc. But that does seem to be the case, at
* least based on past experience. After all, the same hash functions are
* used for hash indexes, hash partitioning and so on.
*
*
* hashing scheme
* --------------
*
* Bloom filters require a number of independent hash functions. There are
* different schemes how to construct them - for example we might use
* hash_uint32_extended with random seeds, but that seems fairly expensive.
* We use a scheme requiring only two functions described in this paper:
*
* Less Hashing, Same Performance:Building a Better Bloom Filter
* Adam Kirsch, Michael Mitzenmacher, Harvard School of Engineering and
* Applied Sciences, Cambridge, Massachusetts [DOI 10.1002/rsa.20208]
*
* The two hash functions h1 and h2 are calculated using hard-coded seeds,
* and then combined using (h1 + i * h2) to generate the hash functions.
*
*
* sizing the bloom filter
* -----------------------
*
* Size of a bloom filter depends on the number of distinct values we will
* store in it, and the desired false positive rate. The higher the number
* of distinct values and/or the lower the false positive rate, the larger
* the bloom filter. On the other hand, we want to keep the index as small
* as possible - that's one of the basic advantages of BRIN indexes.
*
* Although the number of distinct elements (in a page range) depends on
* the data, we can consider it fixed. This simplifies the trade-off to
* just false positive rate vs. size.
*
* At the page range level, false positive rate is a probability the bloom
* filter matches a random value. For the whole index (with sufficiently
* many page ranges) it represents the fraction of the index ranges (and
* thus fraction of the table to be scanned) matching the random value.
*
* Furthermore, the size of the bloom filter is subject to implementation
* limits - it has to fit onto a single index page (8kB by default). As
* the bitmap is inherently random (when "full" about half the bits is set
* to 1, randomly), compression can't help very much.
*
* To reduce the size of a filter (to fit to a page), we have to either
* accept higher false positive rate (undesirable), or reduce the number
* of distinct items to be stored in the filter. We can't alter the input
* data, of course, but we may make the BRIN page ranges smaller - instead
* of the default 128 pages (1MB) we may build index with 16-page ranges,
* or something like that. This should reduce the number of distinct values
* in the page range, making the filter smaller (with fixed false positive
* rate). Even for random data sets this should help, as the number of rows
* per heap page is limited (to ~290 with very narrow tables, likely ~20
* in practice).
*
* Of course, good sizing decisions depend on having the necessary data,
* i.e. number of distinct values in a page range (of a given size) and
* table size (to estimate cost change due to change in false positive
* rate due to having larger index vs. scanning larger indexes). We may
* not have that data - for example when building an index on empty table
* it's not really possible. And for some data we only have estimates for
* the whole table and we can only estimate per-range values (ndistinct).
*
* Another challenge is that while the bloom filter is per-column, it's
* the whole index tuple that has to fit into a page. And for multi-column
* indexes that may include pieces we have no control over (not necessarily
* bloom filters, the other columns may use other BRIN opclasses). So it's
* not entirely clear how to distribute the space between those columns.
*
* The current logic, implemented in brin_bloom_get_ndistinct, attempts to
* make some basic sizing decisions, based on the size of BRIN ranges, and
* the maximum number of rows per range.
*
*
* IDENTIFICATION
* src/backend/access/brin/brin_bloom.c
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/brin.h"
#include "access/brin_internal.h"
#include "access/brin_page.h"
#include "access/brin_tuple.h"
#include "access/hash.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/stratnum.h"
#include "catalog/pg_type.h"
#include "catalog/pg_amop.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
#include <math.h>
#define BloomEqualStrategyNumber 1
/*
* Additional SQL level support functions. We only have one, which is
* used to calculate hash of the input value.
*
* Procedure numbers must not use values reserved for BRIN itself; see
* brin_internal.h.
*/
#define BLOOM_MAX_PROCNUMS 1 /* maximum support procs we need */
#define PROCNUM_HASH 11 /* required */
/*
* Subtract this from procnum to obtain index in BloomOpaque arrays
* (Must be equal to minimum of private procnums).
*/
#define PROCNUM_BASE 11
/*
* Storage type for BRIN's reloptions.
*/
typedef struct BloomOptions
{
int32 vl_len_; /* varlena header (do not touch directly!) */
double nDistinctPerRange; /* number of distinct values per range */
double falsePositiveRate; /* false positive for bloom filter */
} BloomOptions;
/*
* The current min value (16) is somewhat arbitrary, but it's based
* on the fact that the filter header is ~20B alone, which is about
* the same as the filter bitmap for 16 distinct items with 1% false
* positive rate. So by allowing lower values we'd not gain much. In
* any case, the min should not be larger than MaxHeapTuplesPerPage
* (~290), which is the theoretical maximum for single-page ranges.
*/
#define BLOOM_MIN_NDISTINCT_PER_RANGE 16
/*
* Used to determine number of distinct items, based on the number of rows
* in a page range. The 10% is somewhat similar to what estimate_num_groups
* does, so we use the same factor here.
*/
#define BLOOM_DEFAULT_NDISTINCT_PER_RANGE -0.1 /* 10% of values */
/*
* Allowed range and default value for the false positive range. The exact
* values are somewhat arbitrary, but were chosen considering the various
* parameters (size of filter vs. page size, etc.).
*
* The lower the false-positive rate, the more accurate the filter is, but
* it also gets larger - at some point this eliminates the main advantage
* of BRIN indexes, which is the tiny size. At 0.01% the index is about
* 10% of the table (assuming 290 distinct values per 8kB page).
*
* On the other hand, as the false-positive rate increases, larger part of
* the table has to be scanned due to mismatches - at 25% we're probably
* close to sequential scan being cheaper.
*/
#define BLOOM_MIN_FALSE_POSITIVE_RATE 0.0001 /* 0.01% fp rate */
#define BLOOM_MAX_FALSE_POSITIVE_RATE 0.25 /* 25% fp rate */
#define BLOOM_DEFAULT_FALSE_POSITIVE_RATE 0.01 /* 1% fp rate */
#define BloomGetNDistinctPerRange(opts) \
((opts) && (((BloomOptions *) (opts))->nDistinctPerRange != 0) ? \
(((BloomOptions *) (opts))->nDistinctPerRange) : \
BLOOM_DEFAULT_NDISTINCT_PER_RANGE)
#define BloomGetFalsePositiveRate(opts) \
((opts) && (((BloomOptions *) (opts))->falsePositiveRate != 0.0) ? \
(((BloomOptions *) (opts))->falsePositiveRate) : \
BLOOM_DEFAULT_FALSE_POSITIVE_RATE)
/*
* And estimate of the largest bloom we can fit onto a page. This is not
* a perfect guarantee, for a couple of reasons. For example, the row may
* be larger because the index has multiple columns.
*/
#define BloomMaxFilterSize \
MAXALIGN_DOWN(BLCKSZ - \
(MAXALIGN(SizeOfPageHeaderData + \
sizeof(ItemIdData)) + \
MAXALIGN(sizeof(BrinSpecialSpace)) + \
SizeOfBrinTuple))
/*
* Seeds used to calculate two hash functions h1 and h2, which are then used
* to generate k hashes using the (h1 + i * h2) scheme.
*/
#define BLOOM_SEED_1 0x71d924af
#define BLOOM_SEED_2 0xba48b314
/*
* Bloom Filter
*
* Represents a bloom filter, built on hashes of the indexed values. That is,
* we compute a uint32 hash of the value, and then store this hash into the
* bloom filter (and compute additional hashes on it).
*
* XXX We could implement "sparse" bloom filters, keeping only the bytes that
* are not entirely 0. But while indexes don't support TOAST, the varlena can
* still be compressed. So this seems unnecessary, because the compression
* should do the same job.
*
* XXX We can also watch the number of bits set in the bloom filter, and then
* stop using it (and not store the bitmap, to save space) when the false
* positive rate gets too high. But even if the false positive rate exceeds the
* desired value, it still can eliminate some page ranges.
*/
typedef struct BloomFilter
{
/* varlena header (do not touch directly!) */
int32 vl_len_;
/* space for various flags (unused for now) */
uint16 flags;
/* fields for the HASHED phase */
uint8 nhashes; /* number of hash functions */
uint32 nbits; /* number of bits in the bitmap (size) */
uint32 nbits_set; /* number of bits set to 1 */
/* data of the bloom filter */
char data[FLEXIBLE_ARRAY_MEMBER];
} BloomFilter;
/*
* bloom_init
* Initialize the Bloom Filter, allocate all the memory.
*
* The filter is initialized with optimal size for ndistinct expected values
* and the requested false positive rate. The filter is stored as varlena.
*/
static BloomFilter *
bloom_init(int ndistinct, double false_positive_rate)
{
Size len;
BloomFilter *filter;
int nbits; /* size of filter / number of bits */
int nbytes; /* size of filter / number of bytes */
double k; /* number of hash functions */
Assert(ndistinct > 0);
Assert((false_positive_rate >= BLOOM_MIN_FALSE_POSITIVE_RATE) &&
(false_positive_rate < BLOOM_MAX_FALSE_POSITIVE_RATE));
/* sizing bloom filter: -(n * ln(p)) / (ln(2))^2 */
nbits = ceil(-(ndistinct * log(false_positive_rate)) / pow(log(2.0), 2));
/* round m to whole bytes */
nbytes = ((nbits + 7) / 8);
nbits = nbytes * 8;
/*
* Reject filters that are obviously too large to store on a page.
*
* Initially the bloom filter is just zeroes and so very compressible, but
* as we add values it gets more and more random, and so less and less
* compressible. So initially everything fits on the page, but we might
* get surprising failures later - we want to prevent that, so we reject
* bloom filter that are obviously too large.
*
* XXX It's not uncommon to oversize the bloom filter a bit, to defend
* against unexpected data anomalies (parts of table with more distinct
* values per range etc.). But we still need to make sure even the
* oversized filter fits on page, if such need arises.
*
* XXX This check is not perfect, because the index may have multiple
* filters that are small individually, but too large when combined.
*/
if (nbytes > BloomMaxFilterSize)
elog(ERROR, "the bloom filter is too large (%d > %zu)", nbytes,
BloomMaxFilterSize);
/*
* round(log(2.0) * m / ndistinct), but assume round() may not be
* available on Windows
*/
k = log(2.0) * nbits / ndistinct;
k = (k - floor(k) >= 0.5) ? ceil(k) : floor(k);
/*
* We allocate the whole filter. Most of it is going to be 0 bits, so the
* varlena is easy to compress.
*/
len = offsetof(BloomFilter, data) + nbytes;
filter = (BloomFilter *) palloc0(len);
filter->flags = 0;
filter->nhashes = (int) k;
filter->nbits = nbits;
SET_VARSIZE(filter, len);
return filter;
}
/*
* bloom_add_value
* Add value to the bloom filter.
*/
static BloomFilter *
bloom_add_value(BloomFilter * filter, uint32 value, bool *updated)
{
int i;
uint64 h1,
h2;
/* compute the hashes, used for the bloom filter */
h1 = hash_bytes_uint32_extended(value, BLOOM_SEED_1) % filter->nbits;
h2 = hash_bytes_uint32_extended(value, BLOOM_SEED_2) % filter->nbits;
/* compute the requested number of hashes */
for (i = 0; i < filter->nhashes; i++)
{
/* h1 + h2 + f(i) */
uint32 h = (h1 + i * h2) % filter->nbits;
uint32 byte = (h / 8);
uint32 bit = (h % 8);
/* if the bit is not set, set it and remember we did that */
if (!(filter->data[byte] & (0x01 << bit)))
{
filter->data[byte] |= (0x01 << bit);
filter->nbits_set++;
if (updated)
*updated = true;
}
}
return filter;
}
/*
* bloom_contains_value
* Check if the bloom filter contains a particular value.
*/
static bool
bloom_contains_value(BloomFilter * filter, uint32 value)
{
int i;
uint64 h1,
h2;
/* calculate the two hashes */
h1 = hash_bytes_uint32_extended(value, BLOOM_SEED_1) % filter->nbits;
h2 = hash_bytes_uint32_extended(value, BLOOM_SEED_2) % filter->nbits;
/* compute the requested number of hashes */
for (i = 0; i < filter->nhashes; i++)
{
/* h1 + h2 + f(i) */
uint32 h = (h1 + i * h2) % filter->nbits;
uint32 byte = (h / 8);
uint32 bit = (h % 8);
/* if the bit is not set, the value is not there */
if (!(filter->data[byte] & (0x01 << bit)))
return false;
}
/* all hashes found in bloom filter */
return true;
}
typedef struct BloomOpaque
{
/*
* XXX At this point we only need a single proc (to compute the hash), but
* let's keep the array just like inclusion and minman opclasses, for
* consistency. We may need additional procs in the future.
*/
FmgrInfo extra_procinfos[BLOOM_MAX_PROCNUMS];
bool extra_proc_missing[BLOOM_MAX_PROCNUMS];
} BloomOpaque;
static FmgrInfo *bloom_get_procinfo(BrinDesc *bdesc, uint16 attno,
uint16 procnum);
Datum
brin_bloom_opcinfo(PG_FUNCTION_ARGS)
{
BrinOpcInfo *result;
/*
* opaque->strategy_procinfos is initialized lazily; here it is set to
* all-uninitialized by palloc0 which sets fn_oid to InvalidOid.
*
* bloom indexes only store the filter as a single BYTEA column
*/
result = palloc0(MAXALIGN(SizeofBrinOpcInfo(1)) +
sizeof(BloomOpaque));
result->oi_nstored = 1;
result->oi_regular_nulls = true;
result->oi_opaque = (BloomOpaque *)
MAXALIGN((char *) result + SizeofBrinOpcInfo(1));
result->oi_typcache[0] = lookup_type_cache(PG_BRIN_BLOOM_SUMMARYOID, 0);
PG_RETURN_POINTER(result);
}
/*
* brin_bloom_get_ndistinct
* Determine the ndistinct value used to size bloom filter.
*
* Adjust the ndistinct value based on the pagesPerRange value. First,
* if it's negative, it's assumed to be relative to maximum number of
* tuples in the range (assuming each page gets MaxHeapTuplesPerPage
* tuples, which is likely a significant over-estimate). We also clamp
* the value, not to over-size the bloom filter unnecessarily.
*
* XXX We can only do this when the pagesPerRange value was supplied.
* If it wasn't, it has to be a read-only access to the index, in which
* case we don't really care. But perhaps we should fall-back to the
* default pagesPerRange value?
*
* XXX We might also fetch info about ndistinct estimate for the column,
* and compute the expected number of distinct values in a range. But
* that may be tricky due to data being sorted in various ways, so it
* seems better to rely on the upper estimate.
*
* XXX We might also calculate a better estimate of rows per BRIN range,
* instead of using MaxHeapTuplesPerPage (which probably produces values
* much higher than reality).
*/
static int
brin_bloom_get_ndistinct(BrinDesc *bdesc, BloomOptions *opts)
{
double ndistinct;
double maxtuples;
BlockNumber pagesPerRange;
pagesPerRange = BrinGetPagesPerRange(bdesc->bd_index);
ndistinct = BloomGetNDistinctPerRange(opts);
Assert(BlockNumberIsValid(pagesPerRange));
maxtuples = MaxHeapTuplesPerPage * pagesPerRange;
/*
* Similarly to n_distinct, negative values are relative - in this case to
* maximum number of tuples in the page range (maxtuples).
*/
if (ndistinct < 0)
ndistinct = (-ndistinct) * maxtuples;
/*
* Positive values are to be used directly, but we still apply a couple of
* safeties to avoid using unreasonably small bloom filters.
*/
ndistinct = Max(ndistinct, BLOOM_MIN_NDISTINCT_PER_RANGE);
/*
* And don't use more than the maximum possible number of tuples, in the
* range, which would be entirely wasteful.
*/
ndistinct = Min(ndistinct, maxtuples);
return (int) ndistinct;
}
/*
* Examine the given index tuple (which contains partial status of a certain
* page range) by comparing it to the given value that comes from another heap
* tuple. If the new value is outside the bloom filter specified by the
* existing tuple values, update the index tuple and return true. Otherwise,
* return false and do not modify in this case.
*/
Datum
brin_bloom_add_value(PG_FUNCTION_ARGS)
{
BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
Datum newval = PG_GETARG_DATUM(2);
bool isnull PG_USED_FOR_ASSERTS_ONLY = PG_GETARG_DATUM(3);
BloomOptions *opts = (BloomOptions *) PG_GET_OPCLASS_OPTIONS();
Oid colloid = PG_GET_COLLATION();
FmgrInfo *hashFn;
uint32 hashValue;
bool updated = false;
AttrNumber attno;
BloomFilter *filter;
Assert(!isnull);
attno = column->bv_attno;
/*
* If this is the first non-null value, we need to initialize the bloom
* filter. Otherwise just extract the existing bloom filter from
* BrinValues.
*/
if (column->bv_allnulls)
{
filter = bloom_init(brin_bloom_get_ndistinct(bdesc, opts),
BloomGetFalsePositiveRate(opts));
column->bv_values[0] = PointerGetDatum(filter);
column->bv_allnulls = false;
updated = true;
}
else
filter = (BloomFilter *) PG_DETOAST_DATUM(column->bv_values[0]);
/*
* Compute the hash of the new value, using the supplied hash function,
* and then add the hash value to the bloom filter.
*/
hashFn = bloom_get_procinfo(bdesc, attno, PROCNUM_HASH);
hashValue = DatumGetUInt32(FunctionCall1Coll(hashFn, colloid, newval));
filter = bloom_add_value(filter, hashValue, &updated);
column->bv_values[0] = PointerGetDatum(filter);
PG_RETURN_BOOL(updated);
}
/*
* Given an index tuple corresponding to a certain page range and a scan key,
* return whether the scan key is consistent with the index tuple's bloom
* filter. Return true if so, false otherwise.
*/
Datum
brin_bloom_consistent(PG_FUNCTION_ARGS)
{
BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
ScanKey *keys = (ScanKey *) PG_GETARG_POINTER(2);
int nkeys = PG_GETARG_INT32(3);
Oid colloid = PG_GET_COLLATION();
AttrNumber attno;
Datum value;
Datum matches;
FmgrInfo *finfo;
uint32 hashValue;
BloomFilter *filter;
int keyno;
filter = (BloomFilter *) PG_DETOAST_DATUM(column->bv_values[0]);
Assert(filter);
matches = true;
for (keyno = 0; keyno < nkeys; keyno++)
{
ScanKey key = keys[keyno];
/* NULL keys are handled and filtered-out in bringetbitmap */
Assert(!(key->sk_flags & SK_ISNULL));
attno = key->sk_attno;
value = key->sk_argument;
switch (key->sk_strategy)
{
case BloomEqualStrategyNumber:
/*
* In the equality case (WHERE col = someval), we want to
* return the current page range if the minimum value in the
* range <= scan key, and the maximum value >= scan key.
*/
finfo = bloom_get_procinfo(bdesc, attno, PROCNUM_HASH);
hashValue = DatumGetUInt32(FunctionCall1Coll(finfo, colloid, value));
matches &= bloom_contains_value(filter, hashValue);
break;
default:
/* shouldn't happen */
elog(ERROR, "invalid strategy number %d", key->sk_strategy);
matches = 0;
break;
}
if (!matches)
break;
}
PG_RETURN_DATUM(matches);
}
/*
* Given two BrinValues, update the first of them as a union of the summary
* values contained in both. The second one is untouched.
*
* XXX We assume the bloom filters have the same parameters for now. In the
* future we should have 'can union' function, to decide if we can combine
* two particular bloom filters.
*/
Datum
brin_bloom_union(PG_FUNCTION_ARGS)
{
int i;
int nbytes;
BrinValues *col_a = (BrinValues *) PG_GETARG_POINTER(1);
BrinValues *col_b = (BrinValues *) PG_GETARG_POINTER(2);
BloomFilter *filter_a;
BloomFilter *filter_b;
Assert(col_a->bv_attno == col_b->bv_attno);
Assert(!col_a->bv_allnulls && !col_b->bv_allnulls);
filter_a = (BloomFilter *) PG_DETOAST_DATUM(col_a->bv_values[0]);
filter_b = (BloomFilter *) PG_DETOAST_DATUM(col_b->bv_values[0]);
/* make sure the filters use the same parameters */
Assert(filter_a && filter_b);
Assert(filter_a->nbits == filter_b->nbits);
Assert(filter_a->nhashes == filter_b->nhashes);
Assert((filter_a->nbits > 0) && (filter_a->nbits % 8 == 0));
nbytes = (filter_a->nbits) / 8;
/* simply OR the bitmaps */
for (i = 0; i < nbytes; i++)
filter_a->data[i] |= filter_b->data[i];
PG_RETURN_VOID();
}
/*
* Cache and return inclusion opclass support procedure
*
* Return the procedure corresponding to the given function support number
* or null if it does not exist.
*/
static FmgrInfo *
bloom_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
{
BloomOpaque *opaque;
uint16 basenum = procnum - PROCNUM_BASE;
/*
* We cache these in the opaque struct, to avoid repetitive syscache
* lookups.
*/
opaque = (BloomOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
/*
* If we already searched for this proc and didn't find it, don't bother
* searching again.
*/
if (opaque->extra_proc_missing[basenum])
return NULL;
if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
{
if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
procnum)))
{
fmgr_info_copy(&opaque->extra_procinfos[basenum],
index_getprocinfo(bdesc->bd_index, attno, procnum),
bdesc->bd_context);
}
else
{
opaque->extra_proc_missing[basenum] = true;
return NULL;
}
}
return &opaque->extra_procinfos[basenum];
}
Datum
brin_bloom_options(PG_FUNCTION_ARGS)
{
local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
init_local_reloptions(relopts, sizeof(BloomOptions));
add_local_real_reloption(relopts, "n_distinct_per_range",
"number of distinct items expected in a BRIN page range",
BLOOM_DEFAULT_NDISTINCT_PER_RANGE,
-1.0, INT_MAX, offsetof(BloomOptions, nDistinctPerRange));
add_local_real_reloption(relopts, "false_positive_rate",
"desired false-positive rate for the bloom filters",
BLOOM_DEFAULT_FALSE_POSITIVE_RATE,
BLOOM_MIN_FALSE_POSITIVE_RATE,
BLOOM_MAX_FALSE_POSITIVE_RATE,
offsetof(BloomOptions, falsePositiveRate));
PG_RETURN_VOID();
}
/*
* brin_bloom_summary_in
* - input routine for type brin_bloom_summary.
*
* brin_bloom_summary is only used internally to represent summaries
* in BRIN bloom indexes, so it has no operations of its own, and we
* disallow input too.
*/
Datum
brin_bloom_summary_in(PG_FUNCTION_ARGS)
{
/*
* brin_bloom_summary stores the data in binary form and parsing text
* input is not needed, so disallow this.
*/
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type %s", "pg_brin_bloom_summary")));
PG_RETURN_VOID(); /* keep compiler quiet */
}
/*
* brin_bloom_summary_out
* - output routine for type brin_bloom_summary.
*
* BRIN bloom summaries are serialized into a bytea value, but we want
* to output something nicer humans can understand.
*/
Datum
brin_bloom_summary_out(PG_FUNCTION_ARGS)
{
BloomFilter *filter;
StringInfoData str;
/* detoast the data to get value with a full 4B header */
filter = (BloomFilter *) PG_DETOAST_DATUM(PG_GETARG_BYTEA_PP(0));
initStringInfo(&str);
appendStringInfoChar(&str, '{');
appendStringInfo(&str, "mode: hashed nhashes: %u nbits: %u nbits_set: %u",
filter->nhashes, filter->nbits, filter->nbits_set);
appendStringInfoChar(&str, '}');
PG_RETURN_CSTRING(str.data);
}
/*
* brin_bloom_summary_recv
* - binary input routine for type brin_bloom_summary.
*/
Datum
brin_bloom_summary_recv(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type %s", "pg_brin_bloom_summary")));
PG_RETURN_VOID(); /* keep compiler quiet */
}
/*
* brin_bloom_summary_send
* - binary output routine for type brin_bloom_summary.
*
* BRIN bloom summaries are serialized in a bytea value (although the
* type is named differently), so let's just send that.
*/
Datum
brin_bloom_summary_send(PG_FUNCTION_ARGS)
{
return byteasend(fcinfo);
}

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 202103262
#define CATALOG_VERSION_NO 202103263
#endif

View File

@ -1814,6 +1814,11 @@
amoprighttype => 'bytea', amopstrategy => '5', amopopr => '>(bytea,bytea)',
amopmethod => 'brin' },
# bloom bytea
{ amopfamily => 'brin/bytea_bloom_ops', amoplefttype => 'bytea',
amoprighttype => 'bytea', amopstrategy => '1', amopopr => '=(bytea,bytea)',
amopmethod => 'brin' },
# minmax "char"
{ amopfamily => 'brin/char_minmax_ops', amoplefttype => 'char',
amoprighttype => 'char', amopstrategy => '1', amopopr => '<(char,char)',
@ -1831,6 +1836,11 @@
amoprighttype => 'char', amopstrategy => '5', amopopr => '>(char,char)',
amopmethod => 'brin' },
# bloom "char"
{ amopfamily => 'brin/char_bloom_ops', amoplefttype => 'char',
amoprighttype => 'char', amopstrategy => '1', amopopr => '=(char,char)',
amopmethod => 'brin' },
# minmax name
{ amopfamily => 'brin/name_minmax_ops', amoplefttype => 'name',
amoprighttype => 'name', amopstrategy => '1', amopopr => '<(name,name)',
@ -1848,6 +1858,11 @@
amoprighttype => 'name', amopstrategy => '5', amopopr => '>(name,name)',
amopmethod => 'brin' },
# bloom name
{ amopfamily => 'brin/name_bloom_ops', amoplefttype => 'name',
amoprighttype => 'name', amopstrategy => '1', amopopr => '=(name,name)',
amopmethod => 'brin' },
# minmax integer
{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8',
@ -1994,6 +2009,20 @@
amoprighttype => 'int8', amopstrategy => '5', amopopr => '>(int4,int8)',
amopmethod => 'brin' },
# bloom integer
{ amopfamily => 'brin/integer_bloom_ops', amoplefttype => 'int8',
amoprighttype => 'int8', amopstrategy => '1', amopopr => '=(int8,int8)',
amopmethod => 'brin' },
{ amopfamily => 'brin/integer_bloom_ops', amoplefttype => 'int2',
amoprighttype => 'int2', amopstrategy => '1', amopopr => '=(int2,int2)',
amopmethod => 'brin' },
{ amopfamily => 'brin/integer_bloom_ops', amoplefttype => 'int4',
amoprighttype => 'int4', amopstrategy => '1', amopopr => '=(int4,int4)',
amopmethod => 'brin' },
# minmax text
{ amopfamily => 'brin/text_minmax_ops', amoplefttype => 'text',
amoprighttype => 'text', amopstrategy => '1', amopopr => '<(text,text)',
@ -2011,6 +2040,11 @@
amoprighttype => 'text', amopstrategy => '5', amopopr => '>(text,text)',
amopmethod => 'brin' },
# bloom text
{ amopfamily => 'brin/text_bloom_ops', amoplefttype => 'text',
amoprighttype => 'text', amopstrategy => '1', amopopr => '=(text,text)',
amopmethod => 'brin' },
# minmax oid
{ amopfamily => 'brin/oid_minmax_ops', amoplefttype => 'oid',
amoprighttype => 'oid', amopstrategy => '1', amopopr => '<(oid,oid)',
@ -2028,6 +2062,11 @@
amoprighttype => 'oid', amopstrategy => '5', amopopr => '>(oid,oid)',
amopmethod => 'brin' },
# bloom oid
{ amopfamily => 'brin/oid_bloom_ops', amoplefttype => 'oid',
amoprighttype => 'oid', amopstrategy => '1', amopopr => '=(oid,oid)',
amopmethod => 'brin' },
# minmax tid
{ amopfamily => 'brin/tid_minmax_ops', amoplefttype => 'tid',
amoprighttype => 'tid', amopstrategy => '1', amopopr => '<(tid,tid)',
@ -2045,6 +2084,11 @@
amoprighttype => 'tid', amopstrategy => '5', amopopr => '>(tid,tid)',
amopmethod => 'brin' },
# tid oid
{ amopfamily => 'brin/tid_bloom_ops', amoplefttype => 'tid',
amoprighttype => 'tid', amopstrategy => '1', amopopr => '=(tid,tid)',
amopmethod => 'brin' },
# minmax float (float4, float8)
{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float4',
@ -2111,6 +2155,14 @@
amoprighttype => 'float8', amopstrategy => '5', amopopr => '>(float8,float8)',
amopmethod => 'brin' },
# bloom float
{ amopfamily => 'brin/float_bloom_ops', amoplefttype => 'float4',
amoprighttype => 'float4', amopstrategy => '1', amopopr => '=(float4,float4)',
amopmethod => 'brin' },
{ amopfamily => 'brin/float_bloom_ops', amoplefttype => 'float8',
amoprighttype => 'float8', amopstrategy => '1', amopopr => '=(float8,float8)',
amopmethod => 'brin' },
# minmax macaddr
{ amopfamily => 'brin/macaddr_minmax_ops', amoplefttype => 'macaddr',
amoprighttype => 'macaddr', amopstrategy => '1',
@ -2128,6 +2180,11 @@
amoprighttype => 'macaddr', amopstrategy => '5',
amopopr => '>(macaddr,macaddr)', amopmethod => 'brin' },
# bloom macaddr
{ amopfamily => 'brin/macaddr_bloom_ops', amoplefttype => 'macaddr',
amoprighttype => 'macaddr', amopstrategy => '1',
amopopr => '=(macaddr,macaddr)', amopmethod => 'brin' },
# minmax macaddr8
{ amopfamily => 'brin/macaddr8_minmax_ops', amoplefttype => 'macaddr8',
amoprighttype => 'macaddr8', amopstrategy => '1',
@ -2145,6 +2202,11 @@
amoprighttype => 'macaddr8', amopstrategy => '5',
amopopr => '>(macaddr8,macaddr8)', amopmethod => 'brin' },
# bloom macaddr8
{ amopfamily => 'brin/macaddr8_bloom_ops', amoplefttype => 'macaddr8',
amoprighttype => 'macaddr8', amopstrategy => '1',
amopopr => '=(macaddr8,macaddr8)', amopmethod => 'brin' },
# minmax inet
{ amopfamily => 'brin/network_minmax_ops', amoplefttype => 'inet',
amoprighttype => 'inet', amopstrategy => '1', amopopr => '<(inet,inet)',
@ -2162,6 +2224,11 @@
amoprighttype => 'inet', amopstrategy => '5', amopopr => '>(inet,inet)',
amopmethod => 'brin' },
# bloom inet
{ amopfamily => 'brin/network_bloom_ops', amoplefttype => 'inet',
amoprighttype => 'inet', amopstrategy => '1', amopopr => '=(inet,inet)',
amopmethod => 'brin' },
# inclusion inet
{ amopfamily => 'brin/network_inclusion_ops', amoplefttype => 'inet',
amoprighttype => 'inet', amopstrategy => '3', amopopr => '&&(inet,inet)',
@ -2199,6 +2266,11 @@
amoprighttype => 'bpchar', amopstrategy => '5', amopopr => '>(bpchar,bpchar)',
amopmethod => 'brin' },
# bloom character
{ amopfamily => 'brin/bpchar_bloom_ops', amoplefttype => 'bpchar',
amoprighttype => 'bpchar', amopstrategy => '1', amopopr => '=(bpchar,bpchar)',
amopmethod => 'brin' },
# minmax time without time zone
{ amopfamily => 'brin/time_minmax_ops', amoplefttype => 'time',
amoprighttype => 'time', amopstrategy => '1', amopopr => '<(time,time)',
@ -2216,6 +2288,11 @@
amoprighttype => 'time', amopstrategy => '5', amopopr => '>(time,time)',
amopmethod => 'brin' },
# bloom time without time zone
{ amopfamily => 'brin/time_bloom_ops', amoplefttype => 'time',
amoprighttype => 'time', amopstrategy => '1', amopopr => '=(time,time)',
amopmethod => 'brin' },
# minmax datetime (date, timestamp, timestamptz)
{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp',
@ -2362,6 +2439,20 @@
amoprighttype => 'timestamptz', amopstrategy => '5',
amopopr => '>(timestamptz,timestamptz)', amopmethod => 'brin' },
# bloom datetime (date, timestamp, timestamptz)
{ amopfamily => 'brin/datetime_bloom_ops', amoplefttype => 'timestamp',
amoprighttype => 'timestamp', amopstrategy => '1',
amopopr => '=(timestamp,timestamp)', amopmethod => 'brin' },
{ amopfamily => 'brin/datetime_bloom_ops', amoplefttype => 'date',
amoprighttype => 'date', amopstrategy => '1', amopopr => '=(date,date)',
amopmethod => 'brin' },
{ amopfamily => 'brin/datetime_bloom_ops', amoplefttype => 'timestamptz',
amoprighttype => 'timestamptz', amopstrategy => '1',
amopopr => '=(timestamptz,timestamptz)', amopmethod => 'brin' },
# minmax interval
{ amopfamily => 'brin/interval_minmax_ops', amoplefttype => 'interval',
amoprighttype => 'interval', amopstrategy => '1',
@ -2379,6 +2470,11 @@
amoprighttype => 'interval', amopstrategy => '5',
amopopr => '>(interval,interval)', amopmethod => 'brin' },
# bloom interval
{ amopfamily => 'brin/interval_bloom_ops', amoplefttype => 'interval',
amoprighttype => 'interval', amopstrategy => '1',
amopopr => '=(interval,interval)', amopmethod => 'brin' },
# minmax time with time zone
{ amopfamily => 'brin/timetz_minmax_ops', amoplefttype => 'timetz',
amoprighttype => 'timetz', amopstrategy => '1', amopopr => '<(timetz,timetz)',
@ -2396,6 +2492,11 @@
amoprighttype => 'timetz', amopstrategy => '5', amopopr => '>(timetz,timetz)',
amopmethod => 'brin' },
# bloom time with time zone
{ amopfamily => 'brin/timetz_bloom_ops', amoplefttype => 'timetz',
amoprighttype => 'timetz', amopstrategy => '1', amopopr => '=(timetz,timetz)',
amopmethod => 'brin' },
# minmax bit
{ amopfamily => 'brin/bit_minmax_ops', amoplefttype => 'bit',
amoprighttype => 'bit', amopstrategy => '1', amopopr => '<(bit,bit)',
@ -2447,6 +2548,11 @@
amoprighttype => 'numeric', amopstrategy => '5',
amopopr => '>(numeric,numeric)', amopmethod => 'brin' },
# bloom numeric
{ amopfamily => 'brin/numeric_bloom_ops', amoplefttype => 'numeric',
amoprighttype => 'numeric', amopstrategy => '1',
amopopr => '=(numeric,numeric)', amopmethod => 'brin' },
# minmax uuid
{ amopfamily => 'brin/uuid_minmax_ops', amoplefttype => 'uuid',
amoprighttype => 'uuid', amopstrategy => '1', amopopr => '<(uuid,uuid)',
@ -2464,6 +2570,11 @@
amoprighttype => 'uuid', amopstrategy => '5', amopopr => '>(uuid,uuid)',
amopmethod => 'brin' },
# bloom uuid
{ amopfamily => 'brin/uuid_bloom_ops', amoplefttype => 'uuid',
amoprighttype => 'uuid', amopstrategy => '1', amopopr => '=(uuid,uuid)',
amopmethod => 'brin' },
# inclusion range types
{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange',
amoprighttype => 'anyrange', amopstrategy => '1',
@ -2525,6 +2636,11 @@
amoprighttype => 'pg_lsn', amopstrategy => '5', amopopr => '>(pg_lsn,pg_lsn)',
amopmethod => 'brin' },
# bloom pg_lsn
{ amopfamily => 'brin/pg_lsn_bloom_ops', amoplefttype => 'pg_lsn',
amoprighttype => 'pg_lsn', amopstrategy => '1', amopopr => '=(pg_lsn,pg_lsn)',
amopmethod => 'brin' },
# inclusion box
{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box',
amoprighttype => 'box', amopstrategy => '1', amopopr => '<<(box,box)',

View File

@ -805,6 +805,24 @@
{ amprocfamily => 'brin/bytea_minmax_ops', amproclefttype => 'bytea',
amprocrighttype => 'bytea', amprocnum => '4', amproc => 'brin_minmax_union' },
# bloom bytea
{ amprocfamily => 'brin/bytea_bloom_ops', amproclefttype => 'bytea',
amprocrighttype => 'bytea', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/bytea_bloom_ops', amproclefttype => 'bytea',
amprocrighttype => 'bytea', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/bytea_bloom_ops', amproclefttype => 'bytea',
amprocrighttype => 'bytea', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/bytea_bloom_ops', amproclefttype => 'bytea',
amprocrighttype => 'bytea', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/bytea_bloom_ops', amproclefttype => 'bytea',
amprocrighttype => 'bytea', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/bytea_bloom_ops', amproclefttype => 'bytea',
amprocrighttype => 'bytea', amprocnum => '11', amproc => 'hashvarlena' },
# minmax "char"
{ amprocfamily => 'brin/char_minmax_ops', amproclefttype => 'char',
amprocrighttype => 'char', amprocnum => '1',
@ -818,6 +836,24 @@
{ amprocfamily => 'brin/char_minmax_ops', amproclefttype => 'char',
amprocrighttype => 'char', amprocnum => '4', amproc => 'brin_minmax_union' },
# bloom "char"
{ amprocfamily => 'brin/char_bloom_ops', amproclefttype => 'char',
amprocrighttype => 'char', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/char_bloom_ops', amproclefttype => 'char',
amprocrighttype => 'char', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/char_bloom_ops', amproclefttype => 'char',
amprocrighttype => 'char', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/char_bloom_ops', amproclefttype => 'char',
amprocrighttype => 'char', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/char_bloom_ops', amproclefttype => 'char',
amprocrighttype => 'char', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/char_bloom_ops', amproclefttype => 'char',
amprocrighttype => 'char', amprocnum => '11', amproc => 'hashchar' },
# minmax name
{ amprocfamily => 'brin/name_minmax_ops', amproclefttype => 'name',
amprocrighttype => 'name', amprocnum => '1',
@ -831,6 +867,24 @@
{ amprocfamily => 'brin/name_minmax_ops', amproclefttype => 'name',
amprocrighttype => 'name', amprocnum => '4', amproc => 'brin_minmax_union' },
# bloom name
{ amprocfamily => 'brin/name_bloom_ops', amproclefttype => 'name',
amprocrighttype => 'name', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/name_bloom_ops', amproclefttype => 'name',
amprocrighttype => 'name', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/name_bloom_ops', amproclefttype => 'name',
amprocrighttype => 'name', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/name_bloom_ops', amproclefttype => 'name',
amprocrighttype => 'name', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/name_bloom_ops', amproclefttype => 'name',
amprocrighttype => 'name', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/name_bloom_ops', amproclefttype => 'name',
amprocrighttype => 'name', amprocnum => '11', amproc => 'hashname' },
# minmax integer: int2, int4, int8
{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int8',
amprocrighttype => 'int8', amprocnum => '1',
@ -868,6 +922,58 @@
{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int4',
amprocrighttype => 'int4', amprocnum => '4', amproc => 'brin_minmax_union' },
# bloom integer: int2, int4, int8
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int8',
amprocrighttype => 'int8', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int8',
amprocrighttype => 'int8', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int8',
amprocrighttype => 'int8', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int8',
amprocrighttype => 'int8', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int8',
amprocrighttype => 'int8', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int8',
amprocrighttype => 'int8', amprocnum => '11', amproc => 'hashint8' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int2',
amprocrighttype => 'int2', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int2',
amprocrighttype => 'int2', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int2',
amprocrighttype => 'int2', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int2',
amprocrighttype => 'int2', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int2',
amprocrighttype => 'int2', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int2',
amprocrighttype => 'int2', amprocnum => '11', amproc => 'hashint2' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int4',
amprocrighttype => 'int4', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int4',
amprocrighttype => 'int4', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int4',
amprocrighttype => 'int4', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int4',
amprocrighttype => 'int4', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int4',
amprocrighttype => 'int4', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int4',
amprocrighttype => 'int4', amprocnum => '11', amproc => 'hashint4' },
# minmax text
{ amprocfamily => 'brin/text_minmax_ops', amproclefttype => 'text',
amprocrighttype => 'text', amprocnum => '1',
@ -881,6 +987,24 @@
{ amprocfamily => 'brin/text_minmax_ops', amproclefttype => 'text',
amprocrighttype => 'text', amprocnum => '4', amproc => 'brin_minmax_union' },
# bloom text
{ amprocfamily => 'brin/text_bloom_ops', amproclefttype => 'text',
amprocrighttype => 'text', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/text_bloom_ops', amproclefttype => 'text',
amprocrighttype => 'text', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/text_bloom_ops', amproclefttype => 'text',
amprocrighttype => 'text', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/text_bloom_ops', amproclefttype => 'text',
amprocrighttype => 'text', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/text_bloom_ops', amproclefttype => 'text',
amprocrighttype => 'text', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/text_bloom_ops', amproclefttype => 'text',
amprocrighttype => 'text', amprocnum => '11', amproc => 'hashtext' },
# minmax oid
{ amprocfamily => 'brin/oid_minmax_ops', amproclefttype => 'oid',
amprocrighttype => 'oid', amprocnum => '1', amproc => 'brin_minmax_opcinfo' },
@ -893,6 +1017,23 @@
{ amprocfamily => 'brin/oid_minmax_ops', amproclefttype => 'oid',
amprocrighttype => 'oid', amprocnum => '4', amproc => 'brin_minmax_union' },
# bloom oid
{ amprocfamily => 'brin/oid_bloom_ops', amproclefttype => 'oid',
amprocrighttype => 'oid', amprocnum => '1', amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/oid_bloom_ops', amproclefttype => 'oid',
amprocrighttype => 'oid', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/oid_bloom_ops', amproclefttype => 'oid',
amprocrighttype => 'oid', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/oid_bloom_ops', amproclefttype => 'oid',
amprocrighttype => 'oid', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/oid_bloom_ops', amproclefttype => 'oid',
amprocrighttype => 'oid', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/oid_bloom_ops', amproclefttype => 'oid',
amprocrighttype => 'oid', amprocnum => '11', amproc => 'hashoid' },
# minmax tid
{ amprocfamily => 'brin/tid_minmax_ops', amproclefttype => 'tid',
amprocrighttype => 'tid', amprocnum => '1', amproc => 'brin_minmax_opcinfo' },
@ -905,6 +1046,23 @@
{ amprocfamily => 'brin/tid_minmax_ops', amproclefttype => 'tid',
amprocrighttype => 'tid', amprocnum => '4', amproc => 'brin_minmax_union' },
# bloom tid
{ amprocfamily => 'brin/tid_bloom_ops', amproclefttype => 'tid',
amprocrighttype => 'tid', amprocnum => '1', amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/tid_bloom_ops', amproclefttype => 'tid',
amprocrighttype => 'tid', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/tid_bloom_ops', amproclefttype => 'tid',
amprocrighttype => 'tid', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/tid_bloom_ops', amproclefttype => 'tid',
amprocrighttype => 'tid', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/tid_bloom_ops', amproclefttype => 'tid',
amprocrighttype => 'tid', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/tid_bloom_ops', amproclefttype => 'tid',
amprocrighttype => 'tid', amprocnum => '11', amproc => 'hashtid' },
# minmax float
{ amprocfamily => 'brin/float_minmax_ops', amproclefttype => 'float4',
amprocrighttype => 'float4', amprocnum => '1',
@ -932,6 +1090,45 @@
amprocrighttype => 'float8', amprocnum => '4',
amproc => 'brin_minmax_union' },
# bloom float
{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float4',
amprocrighttype => 'float4', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float4',
amprocrighttype => 'float4', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float4',
amprocrighttype => 'float4', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float4',
amprocrighttype => 'float4', amprocnum => '4',
amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float4',
amprocrighttype => 'float4', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float4',
amprocrighttype => 'float4', amprocnum => '11',
amproc => 'hashfloat4' },
{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float8',
amprocrighttype => 'float8', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float8',
amprocrighttype => 'float8', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float8',
amprocrighttype => 'float8', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float8',
amprocrighttype => 'float8', amprocnum => '4',
amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float8',
amprocrighttype => 'float8', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float8',
amprocrighttype => 'float8', amprocnum => '11',
amproc => 'hashfloat8' },
# minmax macaddr
{ amprocfamily => 'brin/macaddr_minmax_ops', amproclefttype => 'macaddr',
amprocrighttype => 'macaddr', amprocnum => '1',
@ -946,6 +1143,26 @@
amprocrighttype => 'macaddr', amprocnum => '4',
amproc => 'brin_minmax_union' },
# bloom macaddr
{ amprocfamily => 'brin/macaddr_bloom_ops', amproclefttype => 'macaddr',
amprocrighttype => 'macaddr', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/macaddr_bloom_ops', amproclefttype => 'macaddr',
amprocrighttype => 'macaddr', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/macaddr_bloom_ops', amproclefttype => 'macaddr',
amprocrighttype => 'macaddr', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/macaddr_bloom_ops', amproclefttype => 'macaddr',
amprocrighttype => 'macaddr', amprocnum => '4',
amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/macaddr_bloom_ops', amproclefttype => 'macaddr',
amprocrighttype => 'macaddr', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/macaddr_bloom_ops', amproclefttype => 'macaddr',
amprocrighttype => 'macaddr', amprocnum => '11',
amproc => 'hashmacaddr' },
# minmax macaddr8
{ amprocfamily => 'brin/macaddr8_minmax_ops', amproclefttype => 'macaddr8',
amprocrighttype => 'macaddr8', amprocnum => '1',
@ -960,6 +1177,26 @@
amprocrighttype => 'macaddr8', amprocnum => '4',
amproc => 'brin_minmax_union' },
# bloom macaddr8
{ amprocfamily => 'brin/macaddr8_bloom_ops', amproclefttype => 'macaddr8',
amprocrighttype => 'macaddr8', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/macaddr8_bloom_ops', amproclefttype => 'macaddr8',
amprocrighttype => 'macaddr8', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/macaddr8_bloom_ops', amproclefttype => 'macaddr8',
amprocrighttype => 'macaddr8', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/macaddr8_bloom_ops', amproclefttype => 'macaddr8',
amprocrighttype => 'macaddr8', amprocnum => '4',
amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/macaddr8_bloom_ops', amproclefttype => 'macaddr8',
amprocrighttype => 'macaddr8', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/macaddr8_bloom_ops', amproclefttype => 'macaddr8',
amprocrighttype => 'macaddr8', amprocnum => '11',
amproc => 'hashmacaddr8' },
# minmax inet
{ amprocfamily => 'brin/network_minmax_ops', amproclefttype => 'inet',
amprocrighttype => 'inet', amprocnum => '1',
@ -973,6 +1210,24 @@
{ amprocfamily => 'brin/network_minmax_ops', amproclefttype => 'inet',
amprocrighttype => 'inet', amprocnum => '4', amproc => 'brin_minmax_union' },
# bloom inet
{ amprocfamily => 'brin/network_bloom_ops', amproclefttype => 'inet',
amprocrighttype => 'inet', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/network_bloom_ops', amproclefttype => 'inet',
amprocrighttype => 'inet', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/network_bloom_ops', amproclefttype => 'inet',
amprocrighttype => 'inet', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/network_bloom_ops', amproclefttype => 'inet',
amprocrighttype => 'inet', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/network_bloom_ops', amproclefttype => 'inet',
amprocrighttype => 'inet', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/network_bloom_ops', amproclefttype => 'inet',
amprocrighttype => 'inet', amprocnum => '11', amproc => 'hashinet' },
# inclusion inet
{ amprocfamily => 'brin/network_inclusion_ops', amproclefttype => 'inet',
amprocrighttype => 'inet', amprocnum => '1',
@ -1007,6 +1262,26 @@
amprocrighttype => 'bpchar', amprocnum => '4',
amproc => 'brin_minmax_union' },
# bloom character
{ amprocfamily => 'brin/bpchar_bloom_ops', amproclefttype => 'bpchar',
amprocrighttype => 'bpchar', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/bpchar_bloom_ops', amproclefttype => 'bpchar',
amprocrighttype => 'bpchar', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/bpchar_bloom_ops', amproclefttype => 'bpchar',
amprocrighttype => 'bpchar', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/bpchar_bloom_ops', amproclefttype => 'bpchar',
amprocrighttype => 'bpchar', amprocnum => '4',
amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/bpchar_bloom_ops', amproclefttype => 'bpchar',
amprocrighttype => 'bpchar', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/bpchar_bloom_ops', amproclefttype => 'bpchar',
amprocrighttype => 'bpchar', amprocnum => '11',
amproc => 'hashbpchar' },
# minmax time without time zone
{ amprocfamily => 'brin/time_minmax_ops', amproclefttype => 'time',
amprocrighttype => 'time', amprocnum => '1',
@ -1020,6 +1295,24 @@
{ amprocfamily => 'brin/time_minmax_ops', amproclefttype => 'time',
amprocrighttype => 'time', amprocnum => '4', amproc => 'brin_minmax_union' },
# bloom time without time zone
{ amprocfamily => 'brin/time_bloom_ops', amproclefttype => 'time',
amprocrighttype => 'time', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/time_bloom_ops', amproclefttype => 'time',
amprocrighttype => 'time', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/time_bloom_ops', amproclefttype => 'time',
amprocrighttype => 'time', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/time_bloom_ops', amproclefttype => 'time',
amprocrighttype => 'time', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/time_bloom_ops', amproclefttype => 'time',
amprocrighttype => 'time', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/time_bloom_ops', amproclefttype => 'time',
amprocrighttype => 'time', amprocnum => '11', amproc => 'time_hash' },
# minmax datetime (date, timestamp, timestamptz)
{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'timestamp',
amprocrighttype => 'timestamp', amprocnum => '1',
@ -1059,6 +1352,62 @@
{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'date',
amprocrighttype => 'date', amprocnum => '4', amproc => 'brin_minmax_union' },
# bloom datetime (date, timestamp, timestamptz)
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamp',
amprocrighttype => 'timestamp', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamp',
amprocrighttype => 'timestamp', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamp',
amprocrighttype => 'timestamp', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamp',
amprocrighttype => 'timestamp', amprocnum => '4',
amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamp',
amprocrighttype => 'timestamp', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamp',
amprocrighttype => 'timestamp', amprocnum => '11',
amproc => 'timestamp_hash' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamptz',
amprocrighttype => 'timestamptz', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamptz',
amprocrighttype => 'timestamptz', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamptz',
amprocrighttype => 'timestamptz', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamptz',
amprocrighttype => 'timestamptz', amprocnum => '4',
amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamptz',
amprocrighttype => 'timestamptz', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamptz',
amprocrighttype => 'timestamptz', amprocnum => '11',
amproc => 'timestamp_hash' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'date',
amprocrighttype => 'date', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'date',
amprocrighttype => 'date', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'date',
amprocrighttype => 'date', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'date',
amprocrighttype => 'date', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'date',
amprocrighttype => 'date', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'date',
amprocrighttype => 'date', amprocnum => '11', amproc => 'hashint4' },
# minmax interval
{ amprocfamily => 'brin/interval_minmax_ops', amproclefttype => 'interval',
amprocrighttype => 'interval', amprocnum => '1',
@ -1073,6 +1422,26 @@
amprocrighttype => 'interval', amprocnum => '4',
amproc => 'brin_minmax_union' },
# bloom interval
{ amprocfamily => 'brin/interval_bloom_ops', amproclefttype => 'interval',
amprocrighttype => 'interval', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/interval_bloom_ops', amproclefttype => 'interval',
amprocrighttype => 'interval', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/interval_bloom_ops', amproclefttype => 'interval',
amprocrighttype => 'interval', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/interval_bloom_ops', amproclefttype => 'interval',
amprocrighttype => 'interval', amprocnum => '4',
amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/interval_bloom_ops', amproclefttype => 'interval',
amprocrighttype => 'interval', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/interval_bloom_ops', amproclefttype => 'interval',
amprocrighttype => 'interval', amprocnum => '11',
amproc => 'interval_hash' },
# minmax time with time zone
{ amprocfamily => 'brin/timetz_minmax_ops', amproclefttype => 'timetz',
amprocrighttype => 'timetz', amprocnum => '1',
@ -1087,6 +1456,26 @@
amprocrighttype => 'timetz', amprocnum => '4',
amproc => 'brin_minmax_union' },
# bloom time with time zone
{ amprocfamily => 'brin/timetz_bloom_ops', amproclefttype => 'timetz',
amprocrighttype => 'timetz', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/timetz_bloom_ops', amproclefttype => 'timetz',
amprocrighttype => 'timetz', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/timetz_bloom_ops', amproclefttype => 'timetz',
amprocrighttype => 'timetz', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/timetz_bloom_ops', amproclefttype => 'timetz',
amprocrighttype => 'timetz', amprocnum => '4',
amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/timetz_bloom_ops', amproclefttype => 'timetz',
amprocrighttype => 'timetz', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/timetz_bloom_ops', amproclefttype => 'timetz',
amprocrighttype => 'timetz', amprocnum => '11',
amproc => 'timetz_hash' },
# minmax bit
{ amprocfamily => 'brin/bit_minmax_ops', amproclefttype => 'bit',
amprocrighttype => 'bit', amprocnum => '1', amproc => 'brin_minmax_opcinfo' },
@ -1127,6 +1516,26 @@
amprocrighttype => 'numeric', amprocnum => '4',
amproc => 'brin_minmax_union' },
# bloom numeric
{ amprocfamily => 'brin/numeric_bloom_ops', amproclefttype => 'numeric',
amprocrighttype => 'numeric', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/numeric_bloom_ops', amproclefttype => 'numeric',
amprocrighttype => 'numeric', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/numeric_bloom_ops', amproclefttype => 'numeric',
amprocrighttype => 'numeric', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/numeric_bloom_ops', amproclefttype => 'numeric',
amprocrighttype => 'numeric', amprocnum => '4',
amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/numeric_bloom_ops', amproclefttype => 'numeric',
amprocrighttype => 'numeric', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/numeric_bloom_ops', amproclefttype => 'numeric',
amprocrighttype => 'numeric', amprocnum => '11',
amproc => 'hash_numeric' },
# minmax uuid
{ amprocfamily => 'brin/uuid_minmax_ops', amproclefttype => 'uuid',
amprocrighttype => 'uuid', amprocnum => '1',
@ -1140,6 +1549,24 @@
{ amprocfamily => 'brin/uuid_minmax_ops', amproclefttype => 'uuid',
amprocrighttype => 'uuid', amprocnum => '4', amproc => 'brin_minmax_union' },
# bloom uuid
{ amprocfamily => 'brin/uuid_bloom_ops', amproclefttype => 'uuid',
amprocrighttype => 'uuid', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/uuid_bloom_ops', amproclefttype => 'uuid',
amprocrighttype => 'uuid', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/uuid_bloom_ops', amproclefttype => 'uuid',
amprocrighttype => 'uuid', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/uuid_bloom_ops', amproclefttype => 'uuid',
amprocrighttype => 'uuid', amprocnum => '4', amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/uuid_bloom_ops', amproclefttype => 'uuid',
amprocrighttype => 'uuid', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/uuid_bloom_ops', amproclefttype => 'uuid',
amprocrighttype => 'uuid', amprocnum => '11', amproc => 'uuid_hash' },
# inclusion range types
{ amprocfamily => 'brin/range_inclusion_ops', amproclefttype => 'anyrange',
amprocrighttype => 'anyrange', amprocnum => '1',
@ -1177,6 +1604,26 @@
amprocrighttype => 'pg_lsn', amprocnum => '4',
amproc => 'brin_minmax_union' },
# bloom pg_lsn
{ amprocfamily => 'brin/pg_lsn_bloom_ops', amproclefttype => 'pg_lsn',
amprocrighttype => 'pg_lsn', amprocnum => '1',
amproc => 'brin_bloom_opcinfo' },
{ amprocfamily => 'brin/pg_lsn_bloom_ops', amproclefttype => 'pg_lsn',
amprocrighttype => 'pg_lsn', amprocnum => '2',
amproc => 'brin_bloom_add_value' },
{ amprocfamily => 'brin/pg_lsn_bloom_ops', amproclefttype => 'pg_lsn',
amprocrighttype => 'pg_lsn', amprocnum => '3',
amproc => 'brin_bloom_consistent' },
{ amprocfamily => 'brin/pg_lsn_bloom_ops', amproclefttype => 'pg_lsn',
amprocrighttype => 'pg_lsn', amprocnum => '4',
amproc => 'brin_bloom_union' },
{ amprocfamily => 'brin/pg_lsn_bloom_ops', amproclefttype => 'pg_lsn',
amprocrighttype => 'pg_lsn', amprocnum => '5',
amproc => 'brin_bloom_options' },
{ amprocfamily => 'brin/pg_lsn_bloom_ops', amproclefttype => 'pg_lsn',
amprocrighttype => 'pg_lsn', amprocnum => '11',
amproc => 'pg_lsn_hash' },
# inclusion box
{ amprocfamily => 'brin/box_inclusion_ops', amproclefttype => 'box',
amprocrighttype => 'box', amprocnum => '1',

View File

@ -266,67 +266,130 @@
{ opcmethod => 'brin', opcname => 'bytea_minmax_ops',
opcfamily => 'brin/bytea_minmax_ops', opcintype => 'bytea',
opckeytype => 'bytea' },
{ opcmethod => 'brin', opcname => 'bytea_bloom_ops',
opcfamily => 'brin/bytea_bloom_ops', opcintype => 'bytea',
opckeytype => 'bytea', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'char_minmax_ops',
opcfamily => 'brin/char_minmax_ops', opcintype => 'char',
opckeytype => 'char' },
{ opcmethod => 'brin', opcname => 'char_bloom_ops',
opcfamily => 'brin/char_bloom_ops', opcintype => 'char',
opckeytype => 'char', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'name_minmax_ops',
opcfamily => 'brin/name_minmax_ops', opcintype => 'name',
opckeytype => 'name' },
{ opcmethod => 'brin', opcname => 'name_bloom_ops',
opcfamily => 'brin/name_bloom_ops', opcintype => 'name',
opckeytype => 'name', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'int8_minmax_ops',
opcfamily => 'brin/integer_minmax_ops', opcintype => 'int8',
opckeytype => 'int8' },
{ opcmethod => 'brin', opcname => 'int8_bloom_ops',
opcfamily => 'brin/integer_bloom_ops', opcintype => 'int8',
opckeytype => 'int8', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'int2_minmax_ops',
opcfamily => 'brin/integer_minmax_ops', opcintype => 'int2',
opckeytype => 'int2' },
{ opcmethod => 'brin', opcname => 'int2_bloom_ops',
opcfamily => 'brin/integer_bloom_ops', opcintype => 'int2',
opckeytype => 'int2', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'int4_minmax_ops',
opcfamily => 'brin/integer_minmax_ops', opcintype => 'int4',
opckeytype => 'int4' },
{ opcmethod => 'brin', opcname => 'int4_bloom_ops',
opcfamily => 'brin/integer_bloom_ops', opcintype => 'int4',
opckeytype => 'int4', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'text_minmax_ops',
opcfamily => 'brin/text_minmax_ops', opcintype => 'text',
opckeytype => 'text' },
{ opcmethod => 'brin', opcname => 'text_bloom_ops',
opcfamily => 'brin/text_bloom_ops', opcintype => 'text',
opckeytype => 'text', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'oid_minmax_ops',
opcfamily => 'brin/oid_minmax_ops', opcintype => 'oid', opckeytype => 'oid' },
{ opcmethod => 'brin', opcname => 'oid_bloom_ops',
opcfamily => 'brin/oid_bloom_ops', opcintype => 'oid',
opckeytype => 'oid', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'tid_minmax_ops',
opcfamily => 'brin/tid_minmax_ops', opcintype => 'tid', opckeytype => 'tid' },
{ opcmethod => 'brin', opcname => 'tid_bloom_ops',
opcfamily => 'brin/tid_bloom_ops', opcintype => 'tid', opckeytype => 'tid',
opcdefault => 'f'},
{ opcmethod => 'brin', opcname => 'float4_minmax_ops',
opcfamily => 'brin/float_minmax_ops', opcintype => 'float4',
opckeytype => 'float4' },
{ opcmethod => 'brin', opcname => 'float4_bloom_ops',
opcfamily => 'brin/float_bloom_ops', opcintype => 'float4',
opckeytype => 'float4', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'float8_minmax_ops',
opcfamily => 'brin/float_minmax_ops', opcintype => 'float8',
opckeytype => 'float8' },
{ opcmethod => 'brin', opcname => 'float8_bloom_ops',
opcfamily => 'brin/float_bloom_ops', opcintype => 'float8',
opckeytype => 'float8', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'macaddr_minmax_ops',
opcfamily => 'brin/macaddr_minmax_ops', opcintype => 'macaddr',
opckeytype => 'macaddr' },
{ opcmethod => 'brin', opcname => 'macaddr_bloom_ops',
opcfamily => 'brin/macaddr_bloom_ops', opcintype => 'macaddr',
opckeytype => 'macaddr', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'macaddr8_minmax_ops',
opcfamily => 'brin/macaddr8_minmax_ops', opcintype => 'macaddr8',
opckeytype => 'macaddr8' },
{ opcmethod => 'brin', opcname => 'macaddr8_bloom_ops',
opcfamily => 'brin/macaddr8_bloom_ops', opcintype => 'macaddr8',
opckeytype => 'macaddr8', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'inet_minmax_ops',
opcfamily => 'brin/network_minmax_ops', opcintype => 'inet',
opcdefault => 'f', opckeytype => 'inet' },
{ opcmethod => 'brin', opcname => 'inet_bloom_ops',
opcfamily => 'brin/network_bloom_ops', opcintype => 'inet',
opcdefault => 'f', opckeytype => 'inet', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'inet_inclusion_ops',
opcfamily => 'brin/network_inclusion_ops', opcintype => 'inet',
opckeytype => 'inet' },
{ opcmethod => 'brin', opcname => 'bpchar_minmax_ops',
opcfamily => 'brin/bpchar_minmax_ops', opcintype => 'bpchar',
opckeytype => 'bpchar' },
{ opcmethod => 'brin', opcname => 'bpchar_bloom_ops',
opcfamily => 'brin/bpchar_bloom_ops', opcintype => 'bpchar',
opckeytype => 'bpchar', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'time_minmax_ops',
opcfamily => 'brin/time_minmax_ops', opcintype => 'time',
opckeytype => 'time' },
{ opcmethod => 'brin', opcname => 'time_bloom_ops',
opcfamily => 'brin/time_bloom_ops', opcintype => 'time',
opckeytype => 'time', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'date_minmax_ops',
opcfamily => 'brin/datetime_minmax_ops', opcintype => 'date',
opckeytype => 'date' },
{ opcmethod => 'brin', opcname => 'date_bloom_ops',
opcfamily => 'brin/datetime_bloom_ops', opcintype => 'date',
opckeytype => 'date', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'timestamp_minmax_ops',
opcfamily => 'brin/datetime_minmax_ops', opcintype => 'timestamp',
opckeytype => 'timestamp' },
{ opcmethod => 'brin', opcname => 'timestamp_bloom_ops',
opcfamily => 'brin/datetime_bloom_ops', opcintype => 'timestamp',
opckeytype => 'timestamp', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'timestamptz_minmax_ops',
opcfamily => 'brin/datetime_minmax_ops', opcintype => 'timestamptz',
opckeytype => 'timestamptz' },
{ opcmethod => 'brin', opcname => 'timestamptz_bloom_ops',
opcfamily => 'brin/datetime_bloom_ops', opcintype => 'timestamptz',
opckeytype => 'timestamptz', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'interval_minmax_ops',
opcfamily => 'brin/interval_minmax_ops', opcintype => 'interval',
opckeytype => 'interval' },
{ opcmethod => 'brin', opcname => 'interval_bloom_ops',
opcfamily => 'brin/interval_bloom_ops', opcintype => 'interval',
opckeytype => 'interval', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'timetz_minmax_ops',
opcfamily => 'brin/timetz_minmax_ops', opcintype => 'timetz',
opckeytype => 'timetz' },
{ opcmethod => 'brin', opcname => 'timetz_bloom_ops',
opcfamily => 'brin/timetz_bloom_ops', opcintype => 'timetz',
opckeytype => 'timetz', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'bit_minmax_ops',
opcfamily => 'brin/bit_minmax_ops', opcintype => 'bit', opckeytype => 'bit' },
{ opcmethod => 'brin', opcname => 'varbit_minmax_ops',
@ -335,18 +398,27 @@
{ opcmethod => 'brin', opcname => 'numeric_minmax_ops',
opcfamily => 'brin/numeric_minmax_ops', opcintype => 'numeric',
opckeytype => 'numeric' },
{ opcmethod => 'brin', opcname => 'numeric_bloom_ops',
opcfamily => 'brin/numeric_bloom_ops', opcintype => 'numeric',
opckeytype => 'numeric', opcdefault => 'f' },
# no brin opclass for record, anyarray
{ opcmethod => 'brin', opcname => 'uuid_minmax_ops',
opcfamily => 'brin/uuid_minmax_ops', opcintype => 'uuid',
opckeytype => 'uuid' },
{ opcmethod => 'brin', opcname => 'uuid_bloom_ops',
opcfamily => 'brin/uuid_bloom_ops', opcintype => 'uuid',
opckeytype => 'uuid', opcdefault => 'f' },
{ opcmethod => 'brin', opcname => 'range_inclusion_ops',
opcfamily => 'brin/range_inclusion_ops', opcintype => 'anyrange',
opckeytype => 'anyrange' },
{ opcmethod => 'brin', opcname => 'pg_lsn_minmax_ops',
opcfamily => 'brin/pg_lsn_minmax_ops', opcintype => 'pg_lsn',
opckeytype => 'pg_lsn' },
{ opcmethod => 'brin', opcname => 'pg_lsn_bloom_ops',
opcfamily => 'brin/pg_lsn_bloom_ops', opcintype => 'pg_lsn',
opckeytype => 'pg_lsn', opcdefault => 'f' },
# no brin opclass for enum, tsvector, tsquery, jsonb

View File

@ -182,50 +182,88 @@
opfmethod => 'gin', opfname => 'jsonb_path_ops' },
{ oid => '4054',
opfmethod => 'brin', opfname => 'integer_minmax_ops' },
{ oid => '4572',
opfmethod => 'brin', opfname => 'integer_bloom_ops' },
{ oid => '4055',
opfmethod => 'brin', opfname => 'numeric_minmax_ops' },
{ oid => '4056',
opfmethod => 'brin', opfname => 'text_minmax_ops' },
{ oid => '4573',
opfmethod => 'brin', opfname => 'text_bloom_ops' },
{ oid => '4574',
opfmethod => 'brin', opfname => 'numeric_bloom_ops' },
{ oid => '4058',
opfmethod => 'brin', opfname => 'timetz_minmax_ops' },
{ oid => '4575',
opfmethod => 'brin', opfname => 'timetz_bloom_ops' },
{ oid => '4059',
opfmethod => 'brin', opfname => 'datetime_minmax_ops' },
{ oid => '4576',
opfmethod => 'brin', opfname => 'datetime_bloom_ops' },
{ oid => '4062',
opfmethod => 'brin', opfname => 'char_minmax_ops' },
{ oid => '4577',
opfmethod => 'brin', opfname => 'char_bloom_ops' },
{ oid => '4064',
opfmethod => 'brin', opfname => 'bytea_minmax_ops' },
{ oid => '4578',
opfmethod => 'brin', opfname => 'bytea_bloom_ops' },
{ oid => '4065',
opfmethod => 'brin', opfname => 'name_minmax_ops' },
{ oid => '4579',
opfmethod => 'brin', opfname => 'name_bloom_ops' },
{ oid => '4068',
opfmethod => 'brin', opfname => 'oid_minmax_ops' },
{ oid => '4580',
opfmethod => 'brin', opfname => 'oid_bloom_ops' },
{ oid => '4069',
opfmethod => 'brin', opfname => 'tid_minmax_ops' },
{ oid => '4581',
opfmethod => 'brin', opfname => 'tid_bloom_ops' },
{ oid => '4070',
opfmethod => 'brin', opfname => 'float_minmax_ops' },
{ oid => '4582',
opfmethod => 'brin', opfname => 'float_bloom_ops' },
{ oid => '4074',
opfmethod => 'brin', opfname => 'macaddr_minmax_ops' },
{ oid => '4583',
opfmethod => 'brin', opfname => 'macaddr_bloom_ops' },
{ oid => '4109',
opfmethod => 'brin', opfname => 'macaddr8_minmax_ops' },
{ oid => '4584',
opfmethod => 'brin', opfname => 'macaddr8_bloom_ops' },
{ oid => '4075',
opfmethod => 'brin', opfname => 'network_minmax_ops' },
{ oid => '4102',
opfmethod => 'brin', opfname => 'network_inclusion_ops' },
{ oid => '4585',
opfmethod => 'brin', opfname => 'network_bloom_ops' },
{ oid => '4076',
opfmethod => 'brin', opfname => 'bpchar_minmax_ops' },
{ oid => '4586',
opfmethod => 'brin', opfname => 'bpchar_bloom_ops' },
{ oid => '4077',
opfmethod => 'brin', opfname => 'time_minmax_ops' },
{ oid => '4587',
opfmethod => 'brin', opfname => 'time_bloom_ops' },
{ oid => '4078',
opfmethod => 'brin', opfname => 'interval_minmax_ops' },
{ oid => '4588',
opfmethod => 'brin', opfname => 'interval_bloom_ops' },
{ oid => '4079',
opfmethod => 'brin', opfname => 'bit_minmax_ops' },
{ oid => '4080',
opfmethod => 'brin', opfname => 'varbit_minmax_ops' },
{ oid => '4081',
opfmethod => 'brin', opfname => 'uuid_minmax_ops' },
{ oid => '4589',
opfmethod => 'brin', opfname => 'uuid_bloom_ops' },
{ oid => '4103',
opfmethod => 'brin', opfname => 'range_inclusion_ops' },
{ oid => '4082',
opfmethod => 'brin', opfname => 'pg_lsn_minmax_ops' },
{ oid => '4590',
opfmethod => 'brin', opfname => 'pg_lsn_bloom_ops' },
{ oid => '4104',
opfmethod => 'brin', opfname => 'box_inclusion_ops' },
{ oid => '5000',

View File

@ -8255,6 +8255,26 @@
proargtypes => 'internal internal internal',
prosrc => 'brin_inclusion_union' },
# BRIN bloom
{ oid => '4591', descr => 'BRIN bloom support',
proname => 'brin_bloom_opcinfo', prorettype => 'internal',
proargtypes => 'internal', prosrc => 'brin_bloom_opcinfo' },
{ oid => '4592', descr => 'BRIN bloom support',
proname => 'brin_bloom_add_value', prorettype => 'bool',
proargtypes => 'internal internal internal internal',
prosrc => 'brin_bloom_add_value' },
{ oid => '4593', descr => 'BRIN bloom support',
proname => 'brin_bloom_consistent', prorettype => 'bool',
proargtypes => 'internal internal internal int4',
prosrc => 'brin_bloom_consistent' },
{ oid => '4594', descr => 'BRIN bloom support',
proname => 'brin_bloom_union', prorettype => 'bool',
proargtypes => 'internal internal internal',
prosrc => 'brin_bloom_union' },
{ oid => '4595', descr => 'BRIN bloom support',
proname => 'brin_bloom_options', prorettype => 'void', proisstrict => 'f',
proargtypes => 'internal', prosrc => 'brin_bloom_options' },
# userlock replacements
{ oid => '2880', descr => 'obtain exclusive advisory lock',
proname => 'pg_advisory_lock', provolatile => 'v', proparallel => 'r',
@ -11428,4 +11448,18 @@
proname => 'is_normalized', prorettype => 'bool', proargtypes => 'text text',
prosrc => 'unicode_is_normalized' },
{ oid => '4596', descr => 'I/O',
proname => 'brin_bloom_summary_in', prorettype => 'pg_brin_bloom_summary',
proargtypes => 'cstring', prosrc => 'brin_bloom_summary_in' },
{ oid => '4597', descr => 'I/O',
proname => 'brin_bloom_summary_out', prorettype => 'cstring',
proargtypes => 'pg_brin_bloom_summary', prosrc => 'brin_bloom_summary_out' },
{ oid => '4598', descr => 'I/O',
proname => 'brin_bloom_summary_recv', provolatile => 's',
prorettype => 'pg_brin_bloom_summary', proargtypes => 'internal',
prosrc => 'brin_bloom_summary_recv' },
{ oid => '4599', descr => 'I/O',
proname => 'brin_bloom_summary_send', provolatile => 's', prorettype => 'bytea',
proargtypes => 'pg_brin_bloom_summary', prosrc => 'brin_bloom_summary_send' },
]

View File

@ -679,5 +679,10 @@
typtype => 'p', typcategory => 'P', typinput => 'anycompatiblemultirange_in',
typoutput => 'anycompatiblemultirange_out', typreceive => '-', typsend => '-',
typalign => 'd', typstorage => 'x' },
{ oid => '4600',
descr => 'BRIN bloom summary',
typname => 'pg_brin_bloom_summary', typlen => '-1', typbyval => 'f', typcategory => 'S',
typinput => 'brin_bloom_summary_in', typoutput => 'brin_bloom_summary_out',
typreceive => 'brin_bloom_summary_recv', typsend => 'brin_bloom_summary_send',
typalign => 'i', typstorage => 'x', typcollation => 'default' },
]

View File

@ -0,0 +1,428 @@
CREATE TABLE brintest_bloom (byteacol bytea,
charcol "char",
namecol name,
int8col bigint,
int2col smallint,
int4col integer,
textcol text,
oidcol oid,
float4col real,
float8col double precision,
macaddrcol macaddr,
inetcol inet,
cidrcol cidr,
bpcharcol character,
datecol date,
timecol time without time zone,
timestampcol timestamp without time zone,
timestamptzcol timestamp with time zone,
intervalcol interval,
timetzcol time with time zone,
numericcol numeric,
uuidcol uuid,
lsncol pg_lsn
) WITH (fillfactor=10);
INSERT INTO brintest_bloom SELECT
repeat(stringu1, 8)::bytea,
substr(stringu1, 1, 1)::"char",
stringu1::name, 142857 * tenthous,
thousand,
twothousand,
repeat(stringu1, 8),
unique1::oid,
(four + 1.0)/(hundred+1),
odd::float8 / (tenthous + 1),
format('%s:00:%s:00:%s:00', to_hex(odd), to_hex(even), to_hex(hundred))::macaddr,
inet '10.2.3.4/24' + tenthous,
cidr '10.2.3/24' + tenthous,
substr(stringu1, 1, 1)::bpchar,
date '1995-08-15' + tenthous,
time '01:20:30' + thousand * interval '18.5 second',
timestamp '1942-07-23 03:05:09' + tenthous * interval '36.38 hours',
timestamptz '1972-10-10 03:00' + thousand * interval '1 hour',
justify_days(justify_hours(tenthous * interval '12 minutes')),
timetz '01:30:20+02' + hundred * interval '15 seconds',
tenthous::numeric(36,30) * fivethous * even / (hundred + 1),
format('%s%s-%s-%s-%s-%s%s%s', to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'))::uuid,
format('%s/%s%s', odd, even, tenthous)::pg_lsn
FROM tenk1 ORDER BY unique2 LIMIT 100;
-- throw in some NULL's and different values
INSERT INTO brintest_bloom (inetcol, cidrcol) SELECT
inet 'fe80::6e40:8ff:fea9:8c46' + tenthous,
cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous
FROM tenk1 ORDER BY thousand, tenthous LIMIT 25;
-- test bloom specific index options
-- ndistinct must be >= -1.0
CREATE INDEX brinidx_bloom ON brintest_bloom USING brin (
byteacol bytea_bloom_ops(n_distinct_per_range = -1.1)
);
ERROR: value -1.1 out of bounds for option "n_distinct_per_range"
DETAIL: Valid values are between "-1.000000" and "2147483647.000000".
-- false_positive_rate must be between 0.0001 and 0.25
CREATE INDEX brinidx_bloom ON brintest_bloom USING brin (
byteacol bytea_bloom_ops(false_positive_rate = 0.00009)
);
ERROR: value 0.00009 out of bounds for option "false_positive_rate"
DETAIL: Valid values are between "0.000100" and "0.250000".
CREATE INDEX brinidx_bloom ON brintest_bloom USING brin (
byteacol bytea_bloom_ops(false_positive_rate = 0.26)
);
ERROR: value 0.26 out of bounds for option "false_positive_rate"
DETAIL: Valid values are between "0.000100" and "0.250000".
CREATE INDEX brinidx_bloom ON brintest_bloom USING brin (
byteacol bytea_bloom_ops,
charcol char_bloom_ops,
namecol name_bloom_ops,
int8col int8_bloom_ops,
int2col int2_bloom_ops,
int4col int4_bloom_ops,
textcol text_bloom_ops,
oidcol oid_bloom_ops,
float4col float4_bloom_ops,
float8col float8_bloom_ops,
macaddrcol macaddr_bloom_ops,
inetcol inet_bloom_ops,
cidrcol inet_bloom_ops,
bpcharcol bpchar_bloom_ops,
datecol date_bloom_ops,
timecol time_bloom_ops,
timestampcol timestamp_bloom_ops,
timestamptzcol timestamptz_bloom_ops,
intervalcol interval_bloom_ops,
timetzcol timetz_bloom_ops,
numericcol numeric_bloom_ops,
uuidcol uuid_bloom_ops,
lsncol pg_lsn_bloom_ops
) with (pages_per_range = 1);
CREATE TABLE brinopers_bloom (colname name, typ text,
op text[], value text[], matches int[],
check (cardinality(op) = cardinality(value)),
check (cardinality(op) = cardinality(matches)));
INSERT INTO brinopers_bloom VALUES
('byteacol', 'bytea',
'{=}',
'{BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA}',
'{1}'),
('charcol', '"char"',
'{=}',
'{M}',
'{6}'),
('namecol', 'name',
'{=}',
'{MAAAAA}',
'{2}'),
('int2col', 'int2',
'{=}',
'{800}',
'{1}'),
('int4col', 'int4',
'{=}',
'{800}',
'{1}'),
('int8col', 'int8',
'{=}',
'{1257141600}',
'{1}'),
('textcol', 'text',
'{=}',
'{BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA}',
'{1}'),
('oidcol', 'oid',
'{=}',
'{8800}',
'{1}'),
('float4col', 'float4',
'{=}',
'{1}',
'{4}'),
('float8col', 'float8',
'{=}',
'{0}',
'{1}'),
('macaddrcol', 'macaddr',
'{=}',
'{2c:00:2d:00:16:00}',
'{2}'),
('inetcol', 'inet',
'{=}',
'{10.2.14.231/24}',
'{1}'),
('inetcol', 'cidr',
'{=}',
'{fe80::6e40:8ff:fea9:8c46}',
'{1}'),
('cidrcol', 'inet',
'{=}',
'{10.2.14/24}',
'{2}'),
('cidrcol', 'inet',
'{=}',
'{fe80::6e40:8ff:fea9:8c46}',
'{1}'),
('cidrcol', 'cidr',
'{=}',
'{10.2.14/24}',
'{2}'),
('cidrcol', 'cidr',
'{=}',
'{fe80::6e40:8ff:fea9:8c46}',
'{1}'),
('bpcharcol', 'bpchar',
'{=}',
'{W}',
'{6}'),
('datecol', 'date',
'{=}',
'{2009-12-01}',
'{1}'),
('timecol', 'time',
'{=}',
'{02:28:57}',
'{1}'),
('timestampcol', 'timestamp',
'{=}',
'{1964-03-24 19:26:45}',
'{1}'),
('timestamptzcol', 'timestamptz',
'{=}',
'{1972-10-19 09:00:00-07}',
'{1}'),
('intervalcol', 'interval',
'{=}',
'{1 mons 13 days 12:24}',
'{1}'),
('timetzcol', 'timetz',
'{=}',
'{01:35:50+02}',
'{2}'),
('numericcol', 'numeric',
'{=}',
'{2268164.347826086956521739130434782609}',
'{1}'),
('uuidcol', 'uuid',
'{=}',
'{52225222-5222-5222-5222-522252225222}',
'{1}'),
('lsncol', 'pg_lsn',
'{=, IS, IS NOT}',
'{44/455222, NULL, NULL}',
'{1, 25, 100}');
DO $x$
DECLARE
r record;
r2 record;
cond text;
idx_ctids tid[];
ss_ctids tid[];
count int;
plan_ok bool;
plan_line text;
BEGIN
FOR r IN SELECT colname, oper, typ, value[ordinality], matches[ordinality] FROM brinopers_bloom, unnest(op) WITH ORDINALITY AS oper LOOP
-- prepare the condition
IF r.value IS NULL THEN
cond := format('%I %s %L', r.colname, r.oper, r.value);
ELSE
cond := format('%I %s %L::%s', r.colname, r.oper, r.value, r.typ);
END IF;
-- run the query using the brin index
SET enable_seqscan = 0;
SET enable_bitmapscan = 1;
plan_ok := false;
FOR plan_line IN EXECUTE format($y$EXPLAIN SELECT array_agg(ctid) FROM brintest_bloom WHERE %s $y$, cond) LOOP
IF plan_line LIKE '%Bitmap Heap Scan on brintest_bloom%' THEN
plan_ok := true;
END IF;
END LOOP;
IF NOT plan_ok THEN
RAISE WARNING 'did not get bitmap indexscan plan for %', r;
END IF;
EXECUTE format($y$SELECT array_agg(ctid) FROM brintest_bloom WHERE %s $y$, cond)
INTO idx_ctids;
-- run the query using a seqscan
SET enable_seqscan = 1;
SET enable_bitmapscan = 0;
plan_ok := false;
FOR plan_line IN EXECUTE format($y$EXPLAIN SELECT array_agg(ctid) FROM brintest_bloom WHERE %s $y$, cond) LOOP
IF plan_line LIKE '%Seq Scan on brintest_bloom%' THEN
plan_ok := true;
END IF;
END LOOP;
IF NOT plan_ok THEN
RAISE WARNING 'did not get seqscan plan for %', r;
END IF;
EXECUTE format($y$SELECT array_agg(ctid) FROM brintest_bloom WHERE %s $y$, cond)
INTO ss_ctids;
-- make sure both return the same results
count := array_length(idx_ctids, 1);
IF NOT (count = array_length(ss_ctids, 1) AND
idx_ctids @> ss_ctids AND
idx_ctids <@ ss_ctids) THEN
-- report the results of each scan to make the differences obvious
RAISE WARNING 'something not right in %: count %', r, count;
SET enable_seqscan = 1;
SET enable_bitmapscan = 0;
FOR r2 IN EXECUTE 'SELECT ' || r.colname || ' FROM brintest_bloom WHERE ' || cond LOOP
RAISE NOTICE 'seqscan: %', r2;
END LOOP;
SET enable_seqscan = 0;
SET enable_bitmapscan = 1;
FOR r2 IN EXECUTE 'SELECT ' || r.colname || ' FROM brintest_bloom WHERE ' || cond LOOP
RAISE NOTICE 'bitmapscan: %', r2;
END LOOP;
END IF;
-- make sure we found expected number of matches
IF count != r.matches THEN RAISE WARNING 'unexpected number of results % for %', count, r; END IF;
END LOOP;
END;
$x$;
RESET enable_seqscan;
RESET enable_bitmapscan;
INSERT INTO brintest_bloom SELECT
repeat(stringu1, 42)::bytea,
substr(stringu1, 1, 1)::"char",
stringu1::name, 142857 * tenthous,
thousand,
twothousand,
repeat(stringu1, 42),
unique1::oid,
(four + 1.0)/(hundred+1),
odd::float8 / (tenthous + 1),
format('%s:00:%s:00:%s:00', to_hex(odd), to_hex(even), to_hex(hundred))::macaddr,
inet '10.2.3.4' + tenthous,
cidr '10.2.3/24' + tenthous,
substr(stringu1, 1, 1)::bpchar,
date '1995-08-15' + tenthous,
time '01:20:30' + thousand * interval '18.5 second',
timestamp '1942-07-23 03:05:09' + tenthous * interval '36.38 hours',
timestamptz '1972-10-10 03:00' + thousand * interval '1 hour',
justify_days(justify_hours(tenthous * interval '12 minutes')),
timetz '01:30:20' + hundred * interval '15 seconds',
tenthous::numeric(36,30) * fivethous * even / (hundred + 1),
format('%s%s-%s-%s-%s-%s%s%s', to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'))::uuid,
format('%s/%s%s', odd, even, tenthous)::pg_lsn
FROM tenk1 ORDER BY unique2 LIMIT 5 OFFSET 5;
SELECT brin_desummarize_range('brinidx_bloom', 0);
brin_desummarize_range
------------------------
(1 row)
VACUUM brintest_bloom; -- force a summarization cycle in brinidx
UPDATE brintest_bloom SET int8col = int8col * int4col;
UPDATE brintest_bloom SET textcol = '' WHERE textcol IS NOT NULL;
-- Tests for brin_summarize_new_values
SELECT brin_summarize_new_values('brintest_bloom'); -- error, not an index
ERROR: "brintest_bloom" is not an index
SELECT brin_summarize_new_values('tenk1_unique1'); -- error, not a BRIN index
ERROR: "tenk1_unique1" is not a BRIN index
SELECT brin_summarize_new_values('brinidx_bloom'); -- ok, no change expected
brin_summarize_new_values
---------------------------
0
(1 row)
-- Tests for brin_desummarize_range
SELECT brin_desummarize_range('brinidx_bloom', -1); -- error, invalid range
ERROR: block number out of range: -1
SELECT brin_desummarize_range('brinidx_bloom', 0);
brin_desummarize_range
------------------------
(1 row)
SELECT brin_desummarize_range('brinidx_bloom', 0);
brin_desummarize_range
------------------------
(1 row)
SELECT brin_desummarize_range('brinidx_bloom', 100000000);
brin_desummarize_range
------------------------
(1 row)
-- Test brin_summarize_range
CREATE TABLE brin_summarize_bloom (
value int
) WITH (fillfactor=10, autovacuum_enabled=false);
CREATE INDEX brin_summarize_bloom_idx ON brin_summarize_bloom USING brin (value) WITH (pages_per_range=2);
-- Fill a few pages
DO $$
DECLARE curtid tid;
BEGIN
LOOP
INSERT INTO brin_summarize_bloom VALUES (1) RETURNING ctid INTO curtid;
EXIT WHEN curtid > tid '(2, 0)';
END LOOP;
END;
$$;
-- summarize one range
SELECT brin_summarize_range('brin_summarize_bloom_idx', 0);
brin_summarize_range
----------------------
0
(1 row)
-- nothing: already summarized
SELECT brin_summarize_range('brin_summarize_bloom_idx', 1);
brin_summarize_range
----------------------
0
(1 row)
-- summarize one range
SELECT brin_summarize_range('brin_summarize_bloom_idx', 2);
brin_summarize_range
----------------------
1
(1 row)
-- nothing: page doesn't exist in table
SELECT brin_summarize_range('brin_summarize_bloom_idx', 4294967295);
brin_summarize_range
----------------------
0
(1 row)
-- invalid block number values
SELECT brin_summarize_range('brin_summarize_bloom_idx', -1);
ERROR: block number out of range: -1
SELECT brin_summarize_range('brin_summarize_bloom_idx', 4294967296);
ERROR: block number out of range: 4294967296
-- test brin cost estimates behave sanely based on correlation of values
CREATE TABLE brin_test_bloom (a INT, b INT);
INSERT INTO brin_test_bloom SELECT x/100,x%100 FROM generate_series(1,10000) x(x);
CREATE INDEX brin_test_bloom_a_idx ON brin_test_bloom USING brin (a) WITH (pages_per_range = 2);
CREATE INDEX brin_test_bloom_b_idx ON brin_test_bloom USING brin (b) WITH (pages_per_range = 2);
VACUUM ANALYZE brin_test_bloom;
-- Ensure brin index is used when columns are perfectly correlated
EXPLAIN (COSTS OFF) SELECT * FROM brin_test_bloom WHERE a = 1;
QUERY PLAN
--------------------------------------------------
Bitmap Heap Scan on brin_test_bloom
Recheck Cond: (a = 1)
-> Bitmap Index Scan on brin_test_bloom_a_idx
Index Cond: (a = 1)
(4 rows)
-- Ensure brin index is not used when values are not correlated
EXPLAIN (COSTS OFF) SELECT * FROM brin_test_bloom WHERE b = 1;
QUERY PLAN
-----------------------------
Seq Scan on brin_test_bloom
Filter: (b = 1)
(2 rows)

View File

@ -2037,6 +2037,7 @@ ORDER BY 1, 2, 3;
2742 | 16 | @@
3580 | 1 | <
3580 | 1 | <<
3580 | 1 | =
3580 | 2 | &<
3580 | 2 | <=
3580 | 3 | &&
@ -2100,7 +2101,7 @@ ORDER BY 1, 2, 3;
4000 | 28 | ^@
4000 | 29 | <^
4000 | 30 | >^
(123 rows)
(124 rows)
-- Check that all opclass search operators have selectivity estimators.
-- This is not absolutely required, but it seems a reasonable thing

View File

@ -4993,8 +4993,9 @@ List of access methods
List of operator classes
AM | Input type | Storage type | Operator class | Default?
------+------------+--------------+----------------+----------
brin | oid | | oid_bloom_ops | no
brin | oid | | oid_minmax_ops | yes
(1 row)
(2 rows)
\dAf spgist
List of operator families

View File

@ -67,13 +67,14 @@ WHERE p1.typtype not in ('p') AND p1.typname NOT LIKE E'\\_%'
WHERE p2.typname = ('_' || p1.typname)::name AND
p2.typelem = p1.oid and p1.typarray = p2.oid)
ORDER BY p1.oid;
oid | typname
------+-----------------
oid | typname
------+-----------------------
194 | pg_node_tree
3361 | pg_ndistinct
3402 | pg_dependencies
4600 | pg_brin_bloom_summary
5017 | pg_mcv_list
(4 rows)
(5 rows)
-- Make sure typarray points to a "true" array type of our own base
SELECT p1.oid, p1.typname as basetype, p2.typname as arraytype,

View File

@ -77,6 +77,11 @@ test: select_into select_distinct select_distinct_on select_implicit select_havi
# ----------
test: brin gin gist spgist privileges init_privs security_label collate matview lock replica_identity rowsecurity object_address tablesample groupingsets drop_operator password identity generated join_hash
# ----------
# Additional BRIN tests
# ----------
test: brin_bloom
# ----------
# Another group of parallel tests
# ----------

View File

@ -108,6 +108,7 @@ test: delete
test: namespace
test: prepared_xacts
test: brin
test: brin_bloom
test: gin
test: gist
test: spgist

View File

@ -0,0 +1,376 @@
CREATE TABLE brintest_bloom (byteacol bytea,
charcol "char",
namecol name,
int8col bigint,
int2col smallint,
int4col integer,
textcol text,
oidcol oid,
float4col real,
float8col double precision,
macaddrcol macaddr,
inetcol inet,
cidrcol cidr,
bpcharcol character,
datecol date,
timecol time without time zone,
timestampcol timestamp without time zone,
timestamptzcol timestamp with time zone,
intervalcol interval,
timetzcol time with time zone,
numericcol numeric,
uuidcol uuid,
lsncol pg_lsn
) WITH (fillfactor=10);
INSERT INTO brintest_bloom SELECT
repeat(stringu1, 8)::bytea,
substr(stringu1, 1, 1)::"char",
stringu1::name, 142857 * tenthous,
thousand,
twothousand,
repeat(stringu1, 8),
unique1::oid,
(four + 1.0)/(hundred+1),
odd::float8 / (tenthous + 1),
format('%s:00:%s:00:%s:00', to_hex(odd), to_hex(even), to_hex(hundred))::macaddr,
inet '10.2.3.4/24' + tenthous,
cidr '10.2.3/24' + tenthous,
substr(stringu1, 1, 1)::bpchar,
date '1995-08-15' + tenthous,
time '01:20:30' + thousand * interval '18.5 second',
timestamp '1942-07-23 03:05:09' + tenthous * interval '36.38 hours',
timestamptz '1972-10-10 03:00' + thousand * interval '1 hour',
justify_days(justify_hours(tenthous * interval '12 minutes')),
timetz '01:30:20+02' + hundred * interval '15 seconds',
tenthous::numeric(36,30) * fivethous * even / (hundred + 1),
format('%s%s-%s-%s-%s-%s%s%s', to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'))::uuid,
format('%s/%s%s', odd, even, tenthous)::pg_lsn
FROM tenk1 ORDER BY unique2 LIMIT 100;
-- throw in some NULL's and different values
INSERT INTO brintest_bloom (inetcol, cidrcol) SELECT
inet 'fe80::6e40:8ff:fea9:8c46' + tenthous,
cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous
FROM tenk1 ORDER BY thousand, tenthous LIMIT 25;
-- test bloom specific index options
-- ndistinct must be >= -1.0
CREATE INDEX brinidx_bloom ON brintest_bloom USING brin (
byteacol bytea_bloom_ops(n_distinct_per_range = -1.1)
);
-- false_positive_rate must be between 0.0001 and 0.25
CREATE INDEX brinidx_bloom ON brintest_bloom USING brin (
byteacol bytea_bloom_ops(false_positive_rate = 0.00009)
);
CREATE INDEX brinidx_bloom ON brintest_bloom USING brin (
byteacol bytea_bloom_ops(false_positive_rate = 0.26)
);
CREATE INDEX brinidx_bloom ON brintest_bloom USING brin (
byteacol bytea_bloom_ops,
charcol char_bloom_ops,
namecol name_bloom_ops,
int8col int8_bloom_ops,
int2col int2_bloom_ops,
int4col int4_bloom_ops,
textcol text_bloom_ops,
oidcol oid_bloom_ops,
float4col float4_bloom_ops,
float8col float8_bloom_ops,
macaddrcol macaddr_bloom_ops,
inetcol inet_bloom_ops,
cidrcol inet_bloom_ops,
bpcharcol bpchar_bloom_ops,
datecol date_bloom_ops,
timecol time_bloom_ops,
timestampcol timestamp_bloom_ops,
timestamptzcol timestamptz_bloom_ops,
intervalcol interval_bloom_ops,
timetzcol timetz_bloom_ops,
numericcol numeric_bloom_ops,
uuidcol uuid_bloom_ops,
lsncol pg_lsn_bloom_ops
) with (pages_per_range = 1);
CREATE TABLE brinopers_bloom (colname name, typ text,
op text[], value text[], matches int[],
check (cardinality(op) = cardinality(value)),
check (cardinality(op) = cardinality(matches)));
INSERT INTO brinopers_bloom VALUES
('byteacol', 'bytea',
'{=}',
'{BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA}',
'{1}'),
('charcol', '"char"',
'{=}',
'{M}',
'{6}'),
('namecol', 'name',
'{=}',
'{MAAAAA}',
'{2}'),
('int2col', 'int2',
'{=}',
'{800}',
'{1}'),
('int4col', 'int4',
'{=}',
'{800}',
'{1}'),
('int8col', 'int8',
'{=}',
'{1257141600}',
'{1}'),
('textcol', 'text',
'{=}',
'{BNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAABNAAAA}',
'{1}'),
('oidcol', 'oid',
'{=}',
'{8800}',
'{1}'),
('float4col', 'float4',
'{=}',
'{1}',
'{4}'),
('float8col', 'float8',
'{=}',
'{0}',
'{1}'),
('macaddrcol', 'macaddr',
'{=}',
'{2c:00:2d:00:16:00}',
'{2}'),
('inetcol', 'inet',
'{=}',
'{10.2.14.231/24}',
'{1}'),
('inetcol', 'cidr',
'{=}',
'{fe80::6e40:8ff:fea9:8c46}',
'{1}'),
('cidrcol', 'inet',
'{=}',
'{10.2.14/24}',
'{2}'),
('cidrcol', 'inet',
'{=}',
'{fe80::6e40:8ff:fea9:8c46}',
'{1}'),
('cidrcol', 'cidr',
'{=}',
'{10.2.14/24}',
'{2}'),
('cidrcol', 'cidr',
'{=}',
'{fe80::6e40:8ff:fea9:8c46}',
'{1}'),
('bpcharcol', 'bpchar',
'{=}',
'{W}',
'{6}'),
('datecol', 'date',
'{=}',
'{2009-12-01}',
'{1}'),
('timecol', 'time',
'{=}',
'{02:28:57}',
'{1}'),
('timestampcol', 'timestamp',
'{=}',
'{1964-03-24 19:26:45}',
'{1}'),
('timestamptzcol', 'timestamptz',
'{=}',
'{1972-10-19 09:00:00-07}',
'{1}'),
('intervalcol', 'interval',
'{=}',
'{1 mons 13 days 12:24}',
'{1}'),
('timetzcol', 'timetz',
'{=}',
'{01:35:50+02}',
'{2}'),
('numericcol', 'numeric',
'{=}',
'{2268164.347826086956521739130434782609}',
'{1}'),
('uuidcol', 'uuid',
'{=}',
'{52225222-5222-5222-5222-522252225222}',
'{1}'),
('lsncol', 'pg_lsn',
'{=, IS, IS NOT}',
'{44/455222, NULL, NULL}',
'{1, 25, 100}');
DO $x$
DECLARE
r record;
r2 record;
cond text;
idx_ctids tid[];
ss_ctids tid[];
count int;
plan_ok bool;
plan_line text;
BEGIN
FOR r IN SELECT colname, oper, typ, value[ordinality], matches[ordinality] FROM brinopers_bloom, unnest(op) WITH ORDINALITY AS oper LOOP
-- prepare the condition
IF r.value IS NULL THEN
cond := format('%I %s %L', r.colname, r.oper, r.value);
ELSE
cond := format('%I %s %L::%s', r.colname, r.oper, r.value, r.typ);
END IF;
-- run the query using the brin index
SET enable_seqscan = 0;
SET enable_bitmapscan = 1;
plan_ok := false;
FOR plan_line IN EXECUTE format($y$EXPLAIN SELECT array_agg(ctid) FROM brintest_bloom WHERE %s $y$, cond) LOOP
IF plan_line LIKE '%Bitmap Heap Scan on brintest_bloom%' THEN
plan_ok := true;
END IF;
END LOOP;
IF NOT plan_ok THEN
RAISE WARNING 'did not get bitmap indexscan plan for %', r;
END IF;
EXECUTE format($y$SELECT array_agg(ctid) FROM brintest_bloom WHERE %s $y$, cond)
INTO idx_ctids;
-- run the query using a seqscan
SET enable_seqscan = 1;
SET enable_bitmapscan = 0;
plan_ok := false;
FOR plan_line IN EXECUTE format($y$EXPLAIN SELECT array_agg(ctid) FROM brintest_bloom WHERE %s $y$, cond) LOOP
IF plan_line LIKE '%Seq Scan on brintest_bloom%' THEN
plan_ok := true;
END IF;
END LOOP;
IF NOT plan_ok THEN
RAISE WARNING 'did not get seqscan plan for %', r;
END IF;
EXECUTE format($y$SELECT array_agg(ctid) FROM brintest_bloom WHERE %s $y$, cond)
INTO ss_ctids;
-- make sure both return the same results
count := array_length(idx_ctids, 1);
IF NOT (count = array_length(ss_ctids, 1) AND
idx_ctids @> ss_ctids AND
idx_ctids <@ ss_ctids) THEN
-- report the results of each scan to make the differences obvious
RAISE WARNING 'something not right in %: count %', r, count;
SET enable_seqscan = 1;
SET enable_bitmapscan = 0;
FOR r2 IN EXECUTE 'SELECT ' || r.colname || ' FROM brintest_bloom WHERE ' || cond LOOP
RAISE NOTICE 'seqscan: %', r2;
END LOOP;
SET enable_seqscan = 0;
SET enable_bitmapscan = 1;
FOR r2 IN EXECUTE 'SELECT ' || r.colname || ' FROM brintest_bloom WHERE ' || cond LOOP
RAISE NOTICE 'bitmapscan: %', r2;
END LOOP;
END IF;
-- make sure we found expected number of matches
IF count != r.matches THEN RAISE WARNING 'unexpected number of results % for %', count, r; END IF;
END LOOP;
END;
$x$;
RESET enable_seqscan;
RESET enable_bitmapscan;
INSERT INTO brintest_bloom SELECT
repeat(stringu1, 42)::bytea,
substr(stringu1, 1, 1)::"char",
stringu1::name, 142857 * tenthous,
thousand,
twothousand,
repeat(stringu1, 42),
unique1::oid,
(four + 1.0)/(hundred+1),
odd::float8 / (tenthous + 1),
format('%s:00:%s:00:%s:00', to_hex(odd), to_hex(even), to_hex(hundred))::macaddr,
inet '10.2.3.4' + tenthous,
cidr '10.2.3/24' + tenthous,
substr(stringu1, 1, 1)::bpchar,
date '1995-08-15' + tenthous,
time '01:20:30' + thousand * interval '18.5 second',
timestamp '1942-07-23 03:05:09' + tenthous * interval '36.38 hours',
timestamptz '1972-10-10 03:00' + thousand * interval '1 hour',
justify_days(justify_hours(tenthous * interval '12 minutes')),
timetz '01:30:20' + hundred * interval '15 seconds',
tenthous::numeric(36,30) * fivethous * even / (hundred + 1),
format('%s%s-%s-%s-%s-%s%s%s', to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'), to_char(tenthous, 'FM0000'))::uuid,
format('%s/%s%s', odd, even, tenthous)::pg_lsn
FROM tenk1 ORDER BY unique2 LIMIT 5 OFFSET 5;
SELECT brin_desummarize_range('brinidx_bloom', 0);
VACUUM brintest_bloom; -- force a summarization cycle in brinidx
UPDATE brintest_bloom SET int8col = int8col * int4col;
UPDATE brintest_bloom SET textcol = '' WHERE textcol IS NOT NULL;
-- Tests for brin_summarize_new_values
SELECT brin_summarize_new_values('brintest_bloom'); -- error, not an index
SELECT brin_summarize_new_values('tenk1_unique1'); -- error, not a BRIN index
SELECT brin_summarize_new_values('brinidx_bloom'); -- ok, no change expected
-- Tests for brin_desummarize_range
SELECT brin_desummarize_range('brinidx_bloom', -1); -- error, invalid range
SELECT brin_desummarize_range('brinidx_bloom', 0);
SELECT brin_desummarize_range('brinidx_bloom', 0);
SELECT brin_desummarize_range('brinidx_bloom', 100000000);
-- Test brin_summarize_range
CREATE TABLE brin_summarize_bloom (
value int
) WITH (fillfactor=10, autovacuum_enabled=false);
CREATE INDEX brin_summarize_bloom_idx ON brin_summarize_bloom USING brin (value) WITH (pages_per_range=2);
-- Fill a few pages
DO $$
DECLARE curtid tid;
BEGIN
LOOP
INSERT INTO brin_summarize_bloom VALUES (1) RETURNING ctid INTO curtid;
EXIT WHEN curtid > tid '(2, 0)';
END LOOP;
END;
$$;
-- summarize one range
SELECT brin_summarize_range('brin_summarize_bloom_idx', 0);
-- nothing: already summarized
SELECT brin_summarize_range('brin_summarize_bloom_idx', 1);
-- summarize one range
SELECT brin_summarize_range('brin_summarize_bloom_idx', 2);
-- nothing: page doesn't exist in table
SELECT brin_summarize_range('brin_summarize_bloom_idx', 4294967295);
-- invalid block number values
SELECT brin_summarize_range('brin_summarize_bloom_idx', -1);
SELECT brin_summarize_range('brin_summarize_bloom_idx', 4294967296);
-- test brin cost estimates behave sanely based on correlation of values
CREATE TABLE brin_test_bloom (a INT, b INT);
INSERT INTO brin_test_bloom SELECT x/100,x%100 FROM generate_series(1,10000) x(x);
CREATE INDEX brin_test_bloom_a_idx ON brin_test_bloom USING brin (a) WITH (pages_per_range = 2);
CREATE INDEX brin_test_bloom_b_idx ON brin_test_bloom USING brin (b) WITH (pages_per_range = 2);
VACUUM ANALYZE brin_test_bloom;
-- Ensure brin index is used when columns are perfectly correlated
EXPLAIN (COSTS OFF) SELECT * FROM brin_test_bloom WHERE a = 1;
-- Ensure brin index is not used when values are not correlated
EXPLAIN (COSTS OFF) SELECT * FROM brin_test_bloom WHERE b = 1;