mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-11 19:20:40 +08:00
Add BRIN infrastructure for "inclusion" opclasses
This lets BRIN be used with R-Tree-like indexing strategies. Also provided are operator classes for range types, box and inet/cidr. The infrastructure provided here should be sufficient to create operator classes for similar datatypes; for instance, opclasses for PostGIS geometries should be doable, though we didn't try to implement one. (A box/point opclass was also submitted, but we ripped it out before commit because the handling of floating point comparisons in existing code is inconsistent and would generate corrupt indexes.) Author: Emre Hasegeli. Cosmetic changes by me Review: Andreas Karlsson
This commit is contained in:
parent
199f5973c5
commit
b0b7be6133
@ -72,7 +72,9 @@
|
||||
<para>
|
||||
The <firstterm>minmax</>
|
||||
operator classes store the minimum and the maximum values appearing
|
||||
in the indexed column within the range.
|
||||
in the indexed column within the range. The <firstterm>inclusion</>
|
||||
operator classes store a value which includes the values in the indexed
|
||||
column within the range.
|
||||
</para>
|
||||
|
||||
<table id="brin-builtin-opclasses-table">
|
||||
@ -251,6 +253,18 @@
|
||||
<literal>></literal>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>inet_inclusion_ops</literal></entry>
|
||||
<entry><type>inet</type></entry>
|
||||
<entry>
|
||||
<literal>&&</>
|
||||
<literal>>></>
|
||||
<literal>>>=</>
|
||||
<literal><<</literal>
|
||||
<literal><<=</literal>
|
||||
<literal>=</literal>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>bpchar_minmax_ops</literal></entry>
|
||||
<entry><type>character</type></entry>
|
||||
@ -372,6 +386,25 @@
|
||||
<literal>></literal>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>range_inclusion_ops</></entry>
|
||||
<entry><type>any range type</type></entry>
|
||||
<entry>
|
||||
<literal>&&</>
|
||||
<literal>&></>
|
||||
<literal>&<</>
|
||||
<literal>>></>
|
||||
<literal><<</>
|
||||
<literal><@</>
|
||||
<literal>=</>
|
||||
<literal>@></>
|
||||
<literal><</literal>
|
||||
<literal><=</literal>
|
||||
<literal>=</literal>
|
||||
<literal>>=</literal>
|
||||
<literal>></literal>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>pg_lsn_minmax_ops</literal></entry>
|
||||
<entry><type>pg_lsn</type></entry>
|
||||
@ -383,6 +416,24 @@
|
||||
<literal>></literal>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>box_inclusion_ops</></entry>
|
||||
<entry><type>box</type></entry>
|
||||
<entry>
|
||||
<literal>&&</>
|
||||
<literal>&></>
|
||||
<literal>&<</>
|
||||
<literal>>></>
|
||||
<literal><<</>
|
||||
<literal><@</>
|
||||
<literal>~=</>
|
||||
<literal>@></>
|
||||
<literal>&>|</>
|
||||
<literal>|&<</>
|
||||
<literal>>>|</>
|
||||
<literal>|<<</literal>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
@ -13,6 +13,6 @@ top_builddir = ../../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
OBJS = brin.o brin_pageops.o brin_revmap.o brin_tuple.o brin_xlog.o \
|
||||
brin_minmax.o
|
||||
brin_minmax.o brin_inclusion.o
|
||||
|
||||
include $(top_srcdir)/src/backend/common.mk
|
||||
|
@ -105,11 +105,6 @@ brininsert(PG_FUNCTION_ARGS)
|
||||
BrinMemTuple *dtup;
|
||||
BlockNumber heapBlk;
|
||||
int keyno;
|
||||
#ifdef USE_ASSERT_CHECKING
|
||||
BrinTuple *tmptup;
|
||||
BrinMemTuple *tmpdtup;
|
||||
Size tmpsiz;
|
||||
#endif
|
||||
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
@ -137,45 +132,6 @@ brininsert(PG_FUNCTION_ARGS)
|
||||
|
||||
dtup = brin_deform_tuple(bdesc, brtup);
|
||||
|
||||
#ifdef USE_ASSERT_CHECKING
|
||||
{
|
||||
/*
|
||||
* When assertions are enabled, we use this as an opportunity to
|
||||
* test the "union" method, which would otherwise be used very
|
||||
* rarely: first create a placeholder tuple, and addValue the
|
||||
* value we just got into it. Then union the existing index tuple
|
||||
* with the updated placeholder tuple. The tuple resulting from
|
||||
* that union should be identical to the one resulting from the
|
||||
* regular operation (straight addValue) below.
|
||||
*
|
||||
* Here we create the tuple to compare with; the actual comparison
|
||||
* is below.
|
||||
*/
|
||||
tmptup = brin_form_placeholder_tuple(bdesc, heapBlk, &tmpsiz);
|
||||
tmpdtup = brin_deform_tuple(bdesc, tmptup);
|
||||
for (keyno = 0; keyno < bdesc->bd_tupdesc->natts; keyno++)
|
||||
{
|
||||
BrinValues *bval;
|
||||
FmgrInfo *addValue;
|
||||
|
||||
bval = &tmpdtup->bt_columns[keyno];
|
||||
addValue = index_getprocinfo(idxRel, keyno + 1,
|
||||
BRIN_PROCNUM_ADDVALUE);
|
||||
FunctionCall4Coll(addValue,
|
||||
idxRel->rd_indcollation[keyno],
|
||||
PointerGetDatum(bdesc),
|
||||
PointerGetDatum(bval),
|
||||
values[keyno],
|
||||
nulls[keyno]);
|
||||
}
|
||||
|
||||
union_tuples(bdesc, tmpdtup, brtup);
|
||||
|
||||
tmpdtup->bt_placeholder = dtup->bt_placeholder;
|
||||
tmptup = brin_form_tuple(bdesc, heapBlk, tmpdtup, &tmpsiz);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compare the key values of the new tuple to the stored index values;
|
||||
* our deformed tuple will get updated if the new tuple doesn't fit
|
||||
@ -202,20 +158,6 @@ brininsert(PG_FUNCTION_ARGS)
|
||||
need_insert |= DatumGetBool(result);
|
||||
}
|
||||
|
||||
#ifdef USE_ASSERT_CHECKING
|
||||
{
|
||||
/*
|
||||
* Now we can compare the tuple produced by the union function
|
||||
* with the one from plain addValue.
|
||||
*/
|
||||
BrinTuple *cmptup;
|
||||
Size cmpsz;
|
||||
|
||||
cmptup = brin_form_tuple(bdesc, heapBlk, dtup, &cmpsz);
|
||||
Assert(brin_tuples_equal(tmptup, tmpsiz, cmptup, cmpsz));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!need_insert)
|
||||
{
|
||||
/*
|
||||
@ -323,8 +265,6 @@ brinbeginscan(PG_FUNCTION_ARGS)
|
||||
* If a TID from the revmap is read as InvalidTID, we know that range is
|
||||
* unsummarized. Pages in those ranges need to be returned regardless of scan
|
||||
* keys.
|
||||
*
|
||||
* XXX see _bt_first on what to do about sk_subtype.
|
||||
*/
|
||||
Datum
|
||||
bringetbitmap(PG_FUNCTION_ARGS)
|
||||
@ -340,7 +280,6 @@ bringetbitmap(PG_FUNCTION_ARGS)
|
||||
BlockNumber nblocks;
|
||||
BlockNumber heapBlk;
|
||||
int totalpages = 0;
|
||||
int keyno;
|
||||
FmgrInfo *consistentFn;
|
||||
MemoryContext oldcxt;
|
||||
MemoryContext perRangeCxt;
|
||||
@ -359,18 +298,11 @@ bringetbitmap(PG_FUNCTION_ARGS)
|
||||
heap_close(heapRel, AccessShareLock);
|
||||
|
||||
/*
|
||||
* Obtain consistent functions for all indexed column. Maybe it'd be
|
||||
* possible to do this lazily only the first time we see a scan key that
|
||||
* involves each particular attribute.
|
||||
* Make room for the consistent support procedures of indexed columns. We
|
||||
* don't look them up here; we do that lazily the first time we see a scan
|
||||
* key reference each of them. We rely on zeroing fn_oid to InvalidOid.
|
||||
*/
|
||||
consistentFn = palloc(sizeof(FmgrInfo) * bdesc->bd_tupdesc->natts);
|
||||
for (keyno = 0; keyno < bdesc->bd_tupdesc->natts; keyno++)
|
||||
{
|
||||
FmgrInfo *tmp;
|
||||
|
||||
tmp = index_getprocinfo(idxRel, keyno + 1, BRIN_PROCNUM_CONSISTENT);
|
||||
fmgr_info_copy(&consistentFn[keyno], tmp, CurrentMemoryContext);
|
||||
}
|
||||
consistentFn = palloc0(sizeof(FmgrInfo) * bdesc->bd_tupdesc->natts);
|
||||
|
||||
/*
|
||||
* Setup and use a per-range memory context, which is reset every time we
|
||||
@ -418,7 +350,6 @@ bringetbitmap(PG_FUNCTION_ARGS)
|
||||
else
|
||||
{
|
||||
BrinMemTuple *dtup;
|
||||
int keyno;
|
||||
|
||||
dtup = brin_deform_tuple(bdesc, tup);
|
||||
if (dtup->bt_placeholder)
|
||||
@ -431,6 +362,8 @@ bringetbitmap(PG_FUNCTION_ARGS)
|
||||
}
|
||||
else
|
||||
{
|
||||
int keyno;
|
||||
|
||||
/*
|
||||
* Compare scan keys with summary values stored for the range.
|
||||
* If scan keys are matched, the page range must be added to
|
||||
@ -456,6 +389,17 @@ bringetbitmap(PG_FUNCTION_ARGS)
|
||||
(key->sk_collation ==
|
||||
bdesc->bd_tupdesc->attrs[keyattno - 1]->attcollation));
|
||||
|
||||
/* First time this column? look up consistent function */
|
||||
if (consistentFn[keyattno - 1].fn_oid == InvalidOid)
|
||||
{
|
||||
FmgrInfo *tmp;
|
||||
|
||||
tmp = index_getprocinfo(idxRel, keyattno,
|
||||
BRIN_PROCNUM_CONSISTENT);
|
||||
fmgr_info_copy(&consistentFn[keyattno - 1], tmp,
|
||||
CurrentMemoryContext);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the scan key is consistent with the page
|
||||
* range values; if so, have the pages in the range added
|
||||
|
696
src/backend/access/brin/brin_inclusion.c
Normal file
696
src/backend/access/brin/brin_inclusion.c
Normal file
@ -0,0 +1,696 @@
|
||||
/*
|
||||
* brin_inclusion.c
|
||||
* Implementation of inclusion opclasses for BRIN
|
||||
*
|
||||
* This module provides framework BRIN support functions for the "inclusion"
|
||||
* operator classes. A few SQL-level support functions are also required for
|
||||
* each opclass.
|
||||
*
|
||||
* The "inclusion" BRIN strategy is useful for types that support R-Tree
|
||||
* operations. This implementation is a straight mapping of those operations
|
||||
* to the block-range nature of BRIN, with two exceptions: (a) we explicitly
|
||||
* support "empty" elements: at least with range types, we need to consider
|
||||
* emptiness separately from regular R-Tree strategies; and (b) we need to
|
||||
* consider "unmergeable" elements, that is, a set of elements for whose union
|
||||
* no representation exists. The only case where that happens as of this
|
||||
* writing is the INET type, where IPv6 values cannot be merged with IPv4
|
||||
* values.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/backend/access/brin/brin_inclusion.c
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/brin_internal.h"
|
||||
#include "access/brin_tuple.h"
|
||||
#include "access/genam.h"
|
||||
#include "access/skey.h"
|
||||
#include "catalog/pg_amop.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "utils/datum.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
/*
|
||||
* Additional SQL level support functions
|
||||
*
|
||||
* Procedure numbers must not use values reserved for BRIN itself; see
|
||||
* brin_internal.h.
|
||||
*/
|
||||
#define INCLUSION_MAX_PROCNUMS 4 /* maximum support procs we need */
|
||||
#define PROCNUM_MERGE 11 /* required */
|
||||
#define PROCNUM_MERGEABLE 12 /* optional */
|
||||
#define PROCNUM_CONTAINS 13 /* optional */
|
||||
#define PROCNUM_EMPTY 14 /* optional */
|
||||
|
||||
|
||||
/*
|
||||
* Subtract this from procnum to obtain index in InclusionOpaque arrays
|
||||
* (Must be equal to minimum of private procnums).
|
||||
*/
|
||||
#define PROCNUM_BASE 11
|
||||
|
||||
/*-
|
||||
* The values stored in the bv_values arrays correspond to:
|
||||
*
|
||||
* 0 - the union of the values in the block range
|
||||
* 1 - whether an empty value is present in any tuple in the block range
|
||||
* 2 - whether the values in the block range cannot be merged (e.g. an IPv6
|
||||
* address amidst IPv4 addresses).
|
||||
*/
|
||||
#define INCLUSION_UNION 0
|
||||
#define INCLUSION_UNMERGEABLE 1
|
||||
#define INCLUSION_CONTAINS_EMPTY 2
|
||||
|
||||
|
||||
typedef struct InclusionOpaque
|
||||
{
|
||||
FmgrInfo extra_procinfos[INCLUSION_MAX_PROCNUMS];
|
||||
bool extra_proc_missing[INCLUSION_MAX_PROCNUMS];
|
||||
Oid cached_subtype;
|
||||
FmgrInfo strategy_procinfos[RTMaxStrategyNumber];
|
||||
} InclusionOpaque;
|
||||
|
||||
Datum brin_inclusion_opcinfo(PG_FUNCTION_ARGS);
|
||||
Datum brin_inclusion_add_value(PG_FUNCTION_ARGS);
|
||||
Datum brin_inclusion_consistent(PG_FUNCTION_ARGS);
|
||||
Datum brin_inclusion_union(PG_FUNCTION_ARGS);
|
||||
static FmgrInfo *inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno,
|
||||
uint16 procnum);
|
||||
static FmgrInfo *inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno,
|
||||
Oid subtype, uint16 strategynum);
|
||||
|
||||
|
||||
/*
|
||||
* BRIN inclusion OpcInfo function
|
||||
*/
|
||||
Datum
|
||||
brin_inclusion_opcinfo(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid typoid = PG_GETARG_OID(0);
|
||||
BrinOpcInfo *result;
|
||||
TypeCacheEntry *bool_typcache = lookup_type_cache(BOOLOID, 0);
|
||||
|
||||
/*
|
||||
* All members of opaque are initialized lazily; both procinfo arrays
|
||||
* start out as non-initialized by having fn_oid be InvalidOid, and
|
||||
* "missing" to false, by zeroing here. strategy_procinfos elements can
|
||||
* be invalidated when cached_subtype changes by zeroing fn_oid.
|
||||
* extra_procinfo entries are never invalidated, but if a lookup fails
|
||||
* (which is expected), extra_proc_missing is set to true, indicating not
|
||||
* to look it up again.
|
||||
*/
|
||||
result = palloc0(MAXALIGN(SizeofBrinOpcInfo(3)) + sizeof(InclusionOpaque));
|
||||
result->oi_nstored = 3;
|
||||
result->oi_opaque = (InclusionOpaque *)
|
||||
MAXALIGN((char *) result + SizeofBrinOpcInfo(3));
|
||||
|
||||
/* the union */
|
||||
result->oi_typcache[INCLUSION_UNION] =
|
||||
lookup_type_cache(typoid, 0);
|
||||
|
||||
/* includes elements that are not mergeable */
|
||||
result->oi_typcache[INCLUSION_UNMERGEABLE] = bool_typcache;
|
||||
|
||||
/* includes the empty element */
|
||||
result->oi_typcache[INCLUSION_CONTAINS_EMPTY] = bool_typcache;
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* BRIN inclusion add value function
|
||||
*
|
||||
* 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 union 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_inclusion_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_GETARG_BOOL(3);
|
||||
Oid colloid = PG_GET_COLLATION();
|
||||
FmgrInfo *finfo;
|
||||
Datum result;
|
||||
bool new = false;
|
||||
AttrNumber attno;
|
||||
Form_pg_attribute attr;
|
||||
|
||||
/*
|
||||
* If the new value is null, we record that we saw it if it's the first
|
||||
* one; otherwise, there's nothing to do.
|
||||
*/
|
||||
if (isnull)
|
||||
{
|
||||
if (column->bv_hasnulls)
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
column->bv_hasnulls = true;
|
||||
PG_RETURN_BOOL(true);
|
||||
}
|
||||
|
||||
attno = column->bv_attno;
|
||||
attr = bdesc->bd_tupdesc->attrs[attno - 1];
|
||||
|
||||
/*
|
||||
* If the recorded value is null, copy the new value (which we know to be
|
||||
* not null), and we're almost done.
|
||||
*/
|
||||
if (column->bv_allnulls)
|
||||
{
|
||||
column->bv_values[INCLUSION_UNION] =
|
||||
datumCopy(newval, attr->attbyval, attr->attlen);
|
||||
column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(false);
|
||||
column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(false);
|
||||
column->bv_allnulls = false;
|
||||
new = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* No need for further processing if the block range is marked as
|
||||
* containing unmergeable values.
|
||||
*/
|
||||
if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE]))
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
/*
|
||||
* If the opclass supports the concept of empty values, test the passed
|
||||
* new value for emptiness; if it returns true, we need to set the
|
||||
* "contains empty" flag in the element (unless already set).
|
||||
*/
|
||||
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_EMPTY);
|
||||
if (finfo != NULL && DatumGetBool(FunctionCall1Coll(finfo, colloid, newval)))
|
||||
{
|
||||
if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]))
|
||||
{
|
||||
column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(true);
|
||||
PG_RETURN_BOOL(true);
|
||||
}
|
||||
|
||||
PG_RETURN_BOOL(false);
|
||||
}
|
||||
|
||||
if (new)
|
||||
PG_RETURN_BOOL(true);
|
||||
|
||||
/* Check if the new value is already contained. */
|
||||
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_CONTAINS);
|
||||
if (finfo != NULL &&
|
||||
DatumGetBool(FunctionCall2Coll(finfo, colloid,
|
||||
column->bv_values[INCLUSION_UNION],
|
||||
newval)))
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
/*
|
||||
* Check if the new value is mergeable to the existing union. If it is
|
||||
* not, mark the value as containing unmergeable elements and get out.
|
||||
*
|
||||
* Note: at this point we could remove the value from the union, since
|
||||
* it's not going to be used any longer. However, the BRIN framework
|
||||
* doesn't allow for the value not being present. Improve someday.
|
||||
*/
|
||||
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE);
|
||||
if (finfo != NULL &&
|
||||
!DatumGetBool(FunctionCall2Coll(finfo, colloid,
|
||||
column->bv_values[INCLUSION_UNION],
|
||||
newval)))
|
||||
{
|
||||
column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(true);
|
||||
PG_RETURN_BOOL(true);
|
||||
}
|
||||
|
||||
/* Finally, merge the new value to the existing union. */
|
||||
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE);
|
||||
Assert(finfo != NULL);
|
||||
result = FunctionCall2Coll(finfo, colloid,
|
||||
column->bv_values[INCLUSION_UNION], newval);
|
||||
if (!attr->attbyval)
|
||||
pfree(DatumGetPointer(column->bv_values[INCLUSION_UNION]));
|
||||
column->bv_values[INCLUSION_UNION] = result;
|
||||
|
||||
PG_RETURN_BOOL(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* BRIN inclusion consistent function
|
||||
*
|
||||
* All of the strategies are optional.
|
||||
*/
|
||||
Datum
|
||||
brin_inclusion_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
|
||||
BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
|
||||
ScanKey key = (ScanKey) PG_GETARG_POINTER(2);
|
||||
Oid colloid = PG_GET_COLLATION(),
|
||||
subtype;
|
||||
Datum unionval;
|
||||
AttrNumber attno;
|
||||
Datum query;
|
||||
FmgrInfo *finfo;
|
||||
Datum result;
|
||||
|
||||
Assert(key->sk_attno == column->bv_attno);
|
||||
|
||||
/* Handle IS NULL/IS NOT NULL tests. */
|
||||
if (key->sk_flags & SK_ISNULL)
|
||||
{
|
||||
if (key->sk_flags & SK_SEARCHNULL)
|
||||
{
|
||||
if (column->bv_allnulls || column->bv_hasnulls)
|
||||
PG_RETURN_BOOL(true);
|
||||
PG_RETURN_BOOL(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* For IS NOT NULL, we can only skip ranges that are known to have
|
||||
* only nulls.
|
||||
*/
|
||||
Assert(key->sk_flags & SK_SEARCHNOTNULL);
|
||||
PG_RETURN_BOOL(!column->bv_allnulls);
|
||||
}
|
||||
|
||||
/* If it is all nulls, it cannot possibly be consistent. */
|
||||
if (column->bv_allnulls)
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
/* It has to be checked, if it contains elements that are not mergeable. */
|
||||
if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE]))
|
||||
PG_RETURN_BOOL(true);
|
||||
|
||||
attno = key->sk_attno;
|
||||
subtype = key->sk_subtype;
|
||||
query = key->sk_argument;
|
||||
unionval = column->bv_values[INCLUSION_UNION];
|
||||
switch (key->sk_strategy)
|
||||
{
|
||||
/*
|
||||
* Placement strategies
|
||||
*
|
||||
* These are implemented by logically negating the result of the
|
||||
* converse placement operator; for this to work, the converse operator
|
||||
* must be part of the opclass. An error will be thrown by
|
||||
* inclusion_get_strategy_procinfo() if the required strategy is not
|
||||
* part of the opclass.
|
||||
*
|
||||
* These all return false if either argument is empty, so there is
|
||||
* no need to check for empty elements.
|
||||
*/
|
||||
|
||||
case RTLeftStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTOverRightStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
PG_RETURN_BOOL(!DatumGetBool(result));
|
||||
|
||||
case RTOverLeftStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTRightStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
PG_RETURN_BOOL(!DatumGetBool(result));
|
||||
|
||||
case RTOverRightStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTLeftStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
PG_RETURN_BOOL(!DatumGetBool(result));
|
||||
|
||||
case RTRightStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTOverLeftStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
PG_RETURN_BOOL(!DatumGetBool(result));
|
||||
|
||||
case RTBelowStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTOverAboveStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
PG_RETURN_BOOL(!DatumGetBool(result));
|
||||
|
||||
case RTOverBelowStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTAboveStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
PG_RETURN_BOOL(!DatumGetBool(result));
|
||||
|
||||
case RTOverAboveStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTBelowStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
PG_RETURN_BOOL(!DatumGetBool(result));
|
||||
|
||||
case RTAboveStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTOverBelowStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
PG_RETURN_BOOL(!DatumGetBool(result));
|
||||
|
||||
/*
|
||||
* Overlap and contains strategies
|
||||
*
|
||||
* These strategies are simple enough that we can simply call the
|
||||
* operator and return its result. Empty elements don't change
|
||||
* the result.
|
||||
*/
|
||||
|
||||
case RTOverlapStrategyNumber:
|
||||
case RTContainsStrategyNumber:
|
||||
case RTOldContainsStrategyNumber:
|
||||
case RTContainsElemStrategyNumber:
|
||||
case RTSubStrategyNumber:
|
||||
case RTSubEqualStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
key->sk_strategy);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
PG_RETURN_DATUM(result);
|
||||
|
||||
/*
|
||||
* Contained by strategies
|
||||
*
|
||||
* We cannot just call the original operator for the contained by
|
||||
* strategies because some elements can be contained even though
|
||||
* the union is not; instead we use the overlap operator.
|
||||
*
|
||||
* We check for empty elements separately as they are not merged to
|
||||
* the union but contained by everything.
|
||||
*/
|
||||
|
||||
case RTContainedByStrategyNumber:
|
||||
case RTOldContainedByStrategyNumber:
|
||||
case RTSuperStrategyNumber:
|
||||
case RTSuperEqualStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTOverlapStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
if (DatumGetBool(result))
|
||||
PG_RETURN_BOOL(true);
|
||||
|
||||
PG_RETURN_DATUM(column->bv_values[INCLUSION_CONTAINS_EMPTY]);
|
||||
|
||||
/*
|
||||
* Adjacent strategy
|
||||
*
|
||||
* We test for overlap first but to be safe we need to call
|
||||
* the actual adjacent operator also.
|
||||
*
|
||||
* An empty element cannot be adjacent to any other, so there is
|
||||
* no need to check for it.
|
||||
*/
|
||||
|
||||
case RTAdjacentStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTOverlapStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
if (DatumGetBool(result))
|
||||
PG_RETURN_BOOL(true);
|
||||
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTAdjacentStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
PG_RETURN_DATUM(result);
|
||||
|
||||
/*
|
||||
* Basic comparison strategies
|
||||
*
|
||||
* It is straightforward to support the equality strategies with
|
||||
* the contains operator. Generally, inequality strategies do not
|
||||
* make much sense for the types which will be used with the
|
||||
* inclusion BRIN family of opclasses, but is is possible to
|
||||
* implement them with logical negation of the left-of and right-of
|
||||
* operators.
|
||||
*
|
||||
* NB: These strategies cannot be used with geometric datatypes
|
||||
* that use comparison of areas! The only exception is the "same"
|
||||
* strategy.
|
||||
*
|
||||
* Empty elements are considered to be less than the others. We
|
||||
* cannot use the empty support function to check the query is an
|
||||
* empty element, because the query can be another data type than
|
||||
* the empty support function argument. So we will return true,
|
||||
* if there is a possibility that empty elements will change the
|
||||
* result.
|
||||
*/
|
||||
|
||||
case RTLessStrategyNumber:
|
||||
case RTLessEqualStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTRightStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
if (!DatumGetBool(result))
|
||||
PG_RETURN_BOOL(true);
|
||||
|
||||
PG_RETURN_DATUM(column->bv_values[INCLUSION_CONTAINS_EMPTY]);
|
||||
|
||||
case RTSameStrategyNumber:
|
||||
case RTEqualStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTContainsStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
if (DatumGetBool(result))
|
||||
PG_RETURN_BOOL(true);
|
||||
|
||||
PG_RETURN_DATUM(column->bv_values[INCLUSION_CONTAINS_EMPTY]);
|
||||
|
||||
case RTGreaterEqualStrategyNumber:
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTLeftStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
if (!DatumGetBool(result))
|
||||
PG_RETURN_BOOL(true);
|
||||
|
||||
PG_RETURN_DATUM(column->bv_values[INCLUSION_CONTAINS_EMPTY]);
|
||||
|
||||
case RTGreaterStrategyNumber:
|
||||
/* no need to check for empty elements */
|
||||
finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
|
||||
RTLeftStrategyNumber);
|
||||
result = FunctionCall2Coll(finfo, colloid, unionval, query);
|
||||
PG_RETURN_BOOL(!DatumGetBool(result));
|
||||
|
||||
default:
|
||||
/* shouldn't happen */
|
||||
elog(ERROR, "invalid strategy number %d", key->sk_strategy);
|
||||
PG_RETURN_BOOL(false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BRIN inclusion union function
|
||||
*
|
||||
* Given two BrinValues, update the first of them as a union of the summary
|
||||
* values contained in both. The second one is untouched.
|
||||
*/
|
||||
Datum
|
||||
brin_inclusion_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
|
||||
BrinValues *col_a = (BrinValues *) PG_GETARG_POINTER(1);
|
||||
BrinValues *col_b = (BrinValues *) PG_GETARG_POINTER(2);
|
||||
Oid colloid = PG_GET_COLLATION();
|
||||
AttrNumber attno;
|
||||
Form_pg_attribute attr;
|
||||
FmgrInfo *finfo;
|
||||
Datum result;
|
||||
|
||||
Assert(col_a->bv_attno == col_b->bv_attno);
|
||||
|
||||
/* Adjust "hasnulls". */
|
||||
if (!col_a->bv_hasnulls && col_b->bv_hasnulls)
|
||||
col_a->bv_hasnulls = true;
|
||||
|
||||
/* If there are no values in B, there's nothing left to do. */
|
||||
if (col_b->bv_allnulls)
|
||||
PG_RETURN_VOID();
|
||||
|
||||
attno = col_a->bv_attno;
|
||||
attr = bdesc->bd_tupdesc->attrs[attno - 1];
|
||||
|
||||
/*
|
||||
* Adjust "allnulls". If A doesn't have values, just copy the values from
|
||||
* B into A, and we're done. We cannot run the operators in this case,
|
||||
* because values in A might contain garbage. Note we already established
|
||||
* that B contains values.
|
||||
*/
|
||||
if (col_a->bv_allnulls)
|
||||
{
|
||||
col_a->bv_allnulls = false;
|
||||
col_a->bv_values[INCLUSION_UNION] =
|
||||
datumCopy(col_b->bv_values[INCLUSION_UNION],
|
||||
attr->attbyval, attr->attlen);
|
||||
col_a->bv_values[INCLUSION_UNMERGEABLE] =
|
||||
col_b->bv_values[INCLUSION_UNMERGEABLE];
|
||||
col_a->bv_values[INCLUSION_CONTAINS_EMPTY] =
|
||||
col_b->bv_values[INCLUSION_CONTAINS_EMPTY];
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/* If B includes empty elements, mark A similarly, if needed. */
|
||||
if (!DatumGetBool(col_a->bv_values[INCLUSION_CONTAINS_EMPTY]) &&
|
||||
DatumGetBool(col_b->bv_values[INCLUSION_CONTAINS_EMPTY]))
|
||||
col_a->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(true);
|
||||
|
||||
/* Check if A includes elements that are not mergeable. */
|
||||
if (DatumGetBool(col_a->bv_values[INCLUSION_UNMERGEABLE]))
|
||||
PG_RETURN_VOID();
|
||||
|
||||
/* If B includes elements that are not mergeable, mark A similarly. */
|
||||
if (DatumGetBool(col_b->bv_values[INCLUSION_UNMERGEABLE]))
|
||||
{
|
||||
col_a->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(true);
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/* Check if A and B are mergeable; if not, mark A unmergeable. */
|
||||
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE);
|
||||
if (finfo != NULL &&
|
||||
!DatumGetBool(FunctionCall2Coll(finfo, colloid,
|
||||
col_a->bv_values[INCLUSION_UNION],
|
||||
col_b->bv_values[INCLUSION_UNION])))
|
||||
{
|
||||
col_a->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(true);
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/* Finally, merge B to A. */
|
||||
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE);
|
||||
Assert(finfo != NULL);
|
||||
result = FunctionCall2Coll(finfo, colloid,
|
||||
col_a->bv_values[INCLUSION_UNION],
|
||||
col_b->bv_values[INCLUSION_UNION]);
|
||||
if (!attr->attbyval)
|
||||
pfree(DatumGetPointer(col_a->bv_values[INCLUSION_UNION]));
|
||||
col_a->bv_values[INCLUSION_UNION] = result;
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache and return inclusion opclass support procedure
|
||||
*
|
||||
* Return the procedure corresponding to the given function support number
|
||||
* or null if it is not exists.
|
||||
*/
|
||||
static FmgrInfo *
|
||||
inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
|
||||
{
|
||||
InclusionOpaque *opaque;
|
||||
uint16 basenum = procnum - PROCNUM_BASE;
|
||||
|
||||
/*
|
||||
* We cache these in the opaque struct, to avoid repetitive syscache
|
||||
* lookups.
|
||||
*/
|
||||
opaque = (InclusionOpaque *) 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];
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache and return the procedure of the given strategy
|
||||
*
|
||||
* Return the procedure corresponding to the given sub-type and strategy
|
||||
* number. The data type of the index will be used as the left hand side of
|
||||
* the operator and the given sub-type will be used as the right hand side.
|
||||
* Throws an error if the pg_amop row does not exist, but that should not
|
||||
* happen with a properly configured opclass.
|
||||
*
|
||||
* It always throws an error when the data type of the opclass is different
|
||||
* from the data type of the column or the expression. That happens when the
|
||||
* column data type has implicit cast to the opclass data type. We don't
|
||||
* bother casting types, because this situation can easily be avoided by
|
||||
* setting storage data type to that of the opclass. The same problem does not
|
||||
* apply to the data type of the right hand side, because the type in the
|
||||
* ScanKey always matches the opclass' one.
|
||||
*
|
||||
* Note: this function mirrors minmax_get_strategy_procinfo; if changes are
|
||||
* made here, see that function too.
|
||||
*/
|
||||
static FmgrInfo *
|
||||
inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype,
|
||||
uint16 strategynum)
|
||||
{
|
||||
InclusionOpaque *opaque;
|
||||
|
||||
Assert(strategynum >= 1 &&
|
||||
strategynum <= RTMaxStrategyNumber);
|
||||
|
||||
opaque = (InclusionOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
|
||||
|
||||
/*
|
||||
* We cache the procedures for the last sub-type in the opaque struct, to
|
||||
* avoid repetitive syscache lookups. If the sub-type is changed,
|
||||
* invalidate all the cached entries.
|
||||
*/
|
||||
if (opaque->cached_subtype != subtype)
|
||||
{
|
||||
uint16 i;
|
||||
|
||||
for (i = 1; i <= RTMaxStrategyNumber; i++)
|
||||
opaque->strategy_procinfos[i - 1].fn_oid = InvalidOid;
|
||||
opaque->cached_subtype = subtype;
|
||||
}
|
||||
|
||||
if (opaque->strategy_procinfos[strategynum - 1].fn_oid == InvalidOid)
|
||||
{
|
||||
Form_pg_attribute attr;
|
||||
HeapTuple tuple;
|
||||
Oid opfamily,
|
||||
oprid;
|
||||
bool isNull;
|
||||
|
||||
opfamily = bdesc->bd_index->rd_opfamily[attno - 1];
|
||||
attr = bdesc->bd_tupdesc->attrs[attno - 1];
|
||||
tuple = SearchSysCache4(AMOPSTRATEGY, ObjectIdGetDatum(opfamily),
|
||||
ObjectIdGetDatum(attr->atttypid),
|
||||
ObjectIdGetDatum(subtype),
|
||||
Int16GetDatum(strategynum));
|
||||
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
|
||||
strategynum, attr->atttypid, subtype, opfamily);
|
||||
|
||||
oprid = DatumGetObjectId(SysCacheGetAttr(AMOPSTRATEGY, tuple,
|
||||
Anum_pg_amop_amopopr, &isNull));
|
||||
ReleaseSysCache(tuple);
|
||||
Assert(!isNull && RegProcedureIsValid(oprid));
|
||||
|
||||
fmgr_info_cxt(get_opcode(oprid),
|
||||
&opaque->strategy_procinfos[strategynum - 1],
|
||||
bdesc->bd_context);
|
||||
}
|
||||
|
||||
return &opaque->strategy_procinfos[strategynum - 1];
|
||||
}
|
@ -28,6 +28,10 @@ typedef struct MinmaxOpaque
|
||||
FmgrInfo strategy_procinfos[BTMaxStrategyNumber];
|
||||
} MinmaxOpaque;
|
||||
|
||||
Datum brin_minmax_opcinfo(PG_FUNCTION_ARGS);
|
||||
Datum brin_minmax_add_value(PG_FUNCTION_ARGS);
|
||||
Datum brin_minmax_consistent(PG_FUNCTION_ARGS);
|
||||
Datum brin_minmax_union(PG_FUNCTION_ARGS);
|
||||
static FmgrInfo *minmax_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno,
|
||||
Oid subtype, uint16 strategynum);
|
||||
|
||||
@ -302,6 +306,9 @@ brin_minmax_union(PG_FUNCTION_ARGS)
|
||||
|
||||
/*
|
||||
* Cache and return the procedure for the given strategy.
|
||||
*
|
||||
* Note: this function mirrors inclusion_get_strategy_procinfo; see notes
|
||||
* there. If changes are made here, see that function too.
|
||||
*/
|
||||
static FmgrInfo *
|
||||
minmax_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype,
|
||||
|
@ -62,9 +62,9 @@
|
||||
#define INETSTRAT_GT RTGreaterStrategyNumber
|
||||
#define INETSTRAT_GE RTGreaterEqualStrategyNumber
|
||||
#define INETSTRAT_SUB RTSubStrategyNumber
|
||||
#define INETSTRAT_SUBEQ RTSubOrEqualStrategyNumber
|
||||
#define INETSTRAT_SUBEQ RTSubEqualStrategyNumber
|
||||
#define INETSTRAT_SUP RTSuperStrategyNumber
|
||||
#define INETSTRAT_SUPEQ RTSuperOrEqualStrategyNumber
|
||||
#define INETSTRAT_SUPEQ RTSuperEqualStrategyNumber
|
||||
|
||||
|
||||
/*
|
||||
|
@ -86,10 +86,4 @@ extern BrinDesc *brin_build_desc(Relation rel);
|
||||
extern void brin_free_desc(BrinDesc *bdesc);
|
||||
extern Datum brin_summarize_new_values(PG_FUNCTION_ARGS);
|
||||
|
||||
/* brin_minmax.c */
|
||||
extern Datum brin_minmax_opcinfo(PG_FUNCTION_ARGS);
|
||||
extern Datum brin_minmax_add_value(PG_FUNCTION_ARGS);
|
||||
extern Datum brin_minmax_consistent(PG_FUNCTION_ARGS);
|
||||
extern Datum brin_minmax_union(PG_FUNCTION_ARGS);
|
||||
|
||||
#endif /* BRIN_INTERNAL_H */
|
||||
|
@ -65,9 +65,9 @@ typedef uint16 StrategyNumber;
|
||||
#define RTGreaterStrategyNumber 22 /* for > */
|
||||
#define RTGreaterEqualStrategyNumber 23 /* for >= */
|
||||
#define RTSubStrategyNumber 24 /* for inet >> */
|
||||
#define RTSubOrEqualStrategyNumber 25 /* for inet <<= */
|
||||
#define RTSubEqualStrategyNumber 25 /* for inet <<= */
|
||||
#define RTSuperStrategyNumber 26 /* for inet << */
|
||||
#define RTSuperOrEqualStrategyNumber 27 /* for inet >>= */
|
||||
#define RTSuperEqualStrategyNumber 27 /* for inet >>= */
|
||||
|
||||
#define RTMaxStrategyNumber 27
|
||||
|
||||
|
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 201505151
|
||||
#define CATALOG_VERSION_NO 201505152
|
||||
|
||||
#endif
|
||||
|
@ -132,7 +132,8 @@ DESCR("GIN index access method");
|
||||
DATA(insert OID = 4000 ( spgist 0 5 f f f f f t f t f f f 0 spginsert spgbeginscan spggettuple spggetbitmap spgrescan spgendscan spgmarkpos spgrestrpos spgbuild spgbuildempty spgbulkdelete spgvacuumcleanup spgcanreturn spgcostestimate spgoptions ));
|
||||
DESCR("SP-GiST index access method");
|
||||
#define SPGIST_AM_OID 4000
|
||||
DATA(insert OID = 3580 ( brin 5 14 f f f f t t f t t f f 0 brininsert brinbeginscan - bringetbitmap brinrescan brinendscan brinmarkpos brinrestrpos brinbuild brinbuildempty brinbulkdelete brinvacuumcleanup - brincostestimate brinoptions ));
|
||||
DATA(insert OID = 3580 ( brin 0 15 f f f f t t f t t f f 0 brininsert brinbeginscan - bringetbitmap brinrescan brinendscan brinmarkpos brinrestrpos brinbuild brinbuildempty brinbulkdelete brinvacuumcleanup - brincostestimate brinoptions ));
|
||||
DESCR("block range index (BRIN) access method");
|
||||
#define BRIN_AM_OID 3580
|
||||
|
||||
#endif /* PG_AM_H */
|
||||
|
@ -977,6 +977,13 @@ DATA(insert ( 4075 869 869 2 s 1204 3580 0 ));
|
||||
DATA(insert ( 4075 869 869 3 s 1201 3580 0 ));
|
||||
DATA(insert ( 4075 869 869 4 s 1206 3580 0 ));
|
||||
DATA(insert ( 4075 869 869 5 s 1205 3580 0 ));
|
||||
/* inclusion inet */
|
||||
DATA(insert ( 4102 869 869 3 s 3552 3580 0 ));
|
||||
DATA(insert ( 4102 869 869 7 s 934 3580 0 ));
|
||||
DATA(insert ( 4102 869 869 8 s 932 3580 0 ));
|
||||
DATA(insert ( 4102 869 869 18 s 1201 3580 0 ));
|
||||
DATA(insert ( 4102 869 869 24 s 933 3580 0 ));
|
||||
DATA(insert ( 4102 869 869 26 s 931 3580 0 ));
|
||||
/* minmax character */
|
||||
DATA(insert ( 4076 1042 1042 1 s 1058 3580 0 ));
|
||||
DATA(insert ( 4076 1042 1042 2 s 1059 3580 0 ));
|
||||
@ -1072,11 +1079,41 @@ DATA(insert ( 4081 2950 2950 2 s 2976 3580 0 ));
|
||||
DATA(insert ( 4081 2950 2950 3 s 2972 3580 0 ));
|
||||
DATA(insert ( 4081 2950 2950 4 s 2977 3580 0 ));
|
||||
DATA(insert ( 4081 2950 2950 5 s 2975 3580 0 ));
|
||||
/* inclusion range types */
|
||||
DATA(insert ( 4103 3831 3831 1 s 3893 3580 0 ));
|
||||
DATA(insert ( 4103 3831 3831 2 s 3895 3580 0 ));
|
||||
DATA(insert ( 4103 3831 3831 3 s 3888 3580 0 ));
|
||||
DATA(insert ( 4103 3831 3831 4 s 3896 3580 0 ));
|
||||
DATA(insert ( 4103 3831 3831 5 s 3894 3580 0 ));
|
||||
DATA(insert ( 4103 3831 3831 7 s 3890 3580 0 ));
|
||||
DATA(insert ( 4103 3831 3831 8 s 3892 3580 0 ));
|
||||
DATA(insert ( 4103 3831 2283 16 s 3889 3580 0 ));
|
||||
DATA(insert ( 4103 3831 3831 17 s 3897 3580 0 ));
|
||||
DATA(insert ( 4103 3831 3831 18 s 3882 3580 0 ));
|
||||
DATA(insert ( 4103 3831 3831 20 s 3884 3580 0 ));
|
||||
DATA(insert ( 4103 3831 3831 21 s 3885 3580 0 ));
|
||||
DATA(insert ( 4103 3831 3831 22 s 3887 3580 0 ));
|
||||
DATA(insert ( 4103 3831 3831 23 s 3886 3580 0 ));
|
||||
/* minmax pg_lsn */
|
||||
DATA(insert ( 4082 3220 3220 1 s 3224 3580 0 ));
|
||||
DATA(insert ( 4082 3220 3220 2 s 3226 3580 0 ));
|
||||
DATA(insert ( 4082 3220 3220 3 s 3222 3580 0 ));
|
||||
DATA(insert ( 4082 3220 3220 4 s 3227 3580 0 ));
|
||||
DATA(insert ( 4082 3220 3220 5 s 3225 3580 0 ));
|
||||
/* inclusion box */
|
||||
DATA(insert ( 4104 603 603 1 s 493 3580 0 ));
|
||||
DATA(insert ( 4104 603 603 2 s 494 3580 0 ));
|
||||
DATA(insert ( 4104 603 603 3 s 500 3580 0 ));
|
||||
DATA(insert ( 4104 603 603 4 s 495 3580 0 ));
|
||||
DATA(insert ( 4104 603 603 5 s 496 3580 0 ));
|
||||
DATA(insert ( 4104 603 603 6 s 499 3580 0 ));
|
||||
DATA(insert ( 4104 603 603 7 s 498 3580 0 ));
|
||||
DATA(insert ( 4104 603 603 8 s 497 3580 0 ));
|
||||
DATA(insert ( 4104 603 603 9 s 2571 3580 0 ));
|
||||
DATA(insert ( 4104 603 603 10 s 2570 3580 0 ));
|
||||
DATA(insert ( 4104 603 603 11 s 2573 3580 0 ));
|
||||
DATA(insert ( 4104 603 603 12 s 2572 3580 0 ));
|
||||
/* we could, but choose not to, supply entries for strategies 13 and 14 */
|
||||
DATA(insert ( 4104 603 600 7 s 433 3580 0 ));
|
||||
|
||||
#endif /* PG_AMOP_H */
|
||||
|
@ -551,6 +551,14 @@ DATA(insert ( 4075 869 869 1 3383 ));
|
||||
DATA(insert ( 4075 869 869 2 3384 ));
|
||||
DATA(insert ( 4075 869 869 3 3385 ));
|
||||
DATA(insert ( 4075 869 869 4 3386 ));
|
||||
/* inclusion inet */
|
||||
DATA(insert ( 4102 869 869 1 4105 ));
|
||||
DATA(insert ( 4102 869 869 2 4106 ));
|
||||
DATA(insert ( 4102 869 869 3 4107 ));
|
||||
DATA(insert ( 4102 869 869 4 4108 ));
|
||||
DATA(insert ( 4102 869 869 11 4063 ));
|
||||
DATA(insert ( 4102 869 869 12 4071 ));
|
||||
DATA(insert ( 4102 869 869 13 930 ));
|
||||
/* minmax character */
|
||||
DATA(insert ( 4076 1042 1042 1 3383 ));
|
||||
DATA(insert ( 4076 1042 1042 2 3384 ));
|
||||
@ -631,10 +639,25 @@ DATA(insert ( 4081 2950 2950 1 3383 ));
|
||||
DATA(insert ( 4081 2950 2950 2 3384 ));
|
||||
DATA(insert ( 4081 2950 2950 3 3385 ));
|
||||
DATA(insert ( 4081 2950 2950 4 3386 ));
|
||||
/* inclusion range types */
|
||||
DATA(insert ( 4103 3831 3831 1 4105 ));
|
||||
DATA(insert ( 4103 3831 3831 2 4106 ));
|
||||
DATA(insert ( 4103 3831 3831 3 4107 ));
|
||||
DATA(insert ( 4103 3831 3831 4 4108 ));
|
||||
DATA(insert ( 4103 3831 3831 11 4057 ));
|
||||
DATA(insert ( 4103 3831 3831 13 3859 ));
|
||||
DATA(insert ( 4103 3831 3831 14 3850 ));
|
||||
/* minmax pg_lsn */
|
||||
DATA(insert ( 4082 3220 3220 1 3383 ));
|
||||
DATA(insert ( 4082 3220 3220 2 3384 ));
|
||||
DATA(insert ( 4082 3220 3220 3 3385 ));
|
||||
DATA(insert ( 4082 3220 3220 4 3386 ));
|
||||
/* inclusion box */
|
||||
DATA(insert ( 4104 603 603 1 4105 ));
|
||||
DATA(insert ( 4104 603 603 2 4106 ));
|
||||
DATA(insert ( 4104 603 603 3 4107 ));
|
||||
DATA(insert ( 4104 603 603 4 4108 ));
|
||||
DATA(insert ( 4104 603 603 11 4067 ));
|
||||
DATA(insert ( 4104 603 603 13 187 ));
|
||||
|
||||
#endif /* PG_AMPROC_H */
|
||||
|
@ -253,6 +253,7 @@ DATA(insert ( 3580 abstime_minmax_ops PGNSP PGUID 4072 702 t 702 ));
|
||||
DATA(insert ( 3580 reltime_minmax_ops PGNSP PGUID 4073 703 t 703 ));
|
||||
DATA(insert ( 3580 macaddr_minmax_ops PGNSP PGUID 4074 829 t 829 ));
|
||||
DATA(insert ( 3580 inet_minmax_ops PGNSP PGUID 4075 869 f 869 ));
|
||||
DATA(insert ( 3580 inet_inclusion_ops PGNSP PGUID 4102 869 t 869 ));
|
||||
DATA(insert ( 3580 bpchar_minmax_ops PGNSP PGUID 4076 1042 t 1042 ));
|
||||
DATA(insert ( 3580 time_minmax_ops PGNSP PGUID 4077 1083 t 1083 ));
|
||||
DATA(insert ( 3580 date_minmax_ops PGNSP PGUID 4059 1082 t 1082 ));
|
||||
@ -265,7 +266,10 @@ DATA(insert ( 3580 varbit_minmax_ops PGNSP PGUID 4080 1562 t 1562 ));
|
||||
DATA(insert ( 3580 numeric_minmax_ops PGNSP PGUID 4055 1700 t 1700 ));
|
||||
/* no brin opclass for record, anyarray */
|
||||
DATA(insert ( 3580 uuid_minmax_ops PGNSP PGUID 4081 2950 t 2950 ));
|
||||
DATA(insert ( 3580 range_inclusion_ops PGNSP PGUID 4103 3831 t 3831 ));
|
||||
DATA(insert ( 3580 pg_lsn_minmax_ops PGNSP PGUID 4082 3220 t 3220 ));
|
||||
/* no brin opclass for enum, tsvector, tsquery, jsonb, range */
|
||||
/* no brin opclass for enum, tsvector, tsquery, jsonb */
|
||||
DATA(insert ( 3580 box_inclusion_ops PGNSP PGUID 4104 603 t 603 ));
|
||||
/* no brin opclass for the geometric types except box */
|
||||
|
||||
#endif /* PG_OPCLASS_H */
|
||||
|
@ -172,12 +172,15 @@ DATA(insert OID = 4072 ( 3580 abstime_minmax_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4073 ( 3580 reltime_minmax_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4074 ( 3580 macaddr_minmax_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4075 ( 3580 network_minmax_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4102 ( 3580 network_inclusion_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4076 ( 3580 bpchar_minmax_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4077 ( 3580 time_minmax_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4078 ( 3580 interval_minmax_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4079 ( 3580 bit_minmax_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4080 ( 3580 varbit_minmax_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4081 ( 3580 uuid_minmax_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4103 ( 3580 range_inclusion_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4082 ( 3580 pg_lsn_minmax_ops PGNSP PGUID ));
|
||||
DATA(insert OID = 4104 ( 3580 box_inclusion_ops PGNSP PGUID ));
|
||||
|
||||
#endif /* PG_OPFAMILY_H */
|
||||
|
@ -4225,6 +4225,16 @@ DESCR("BRIN minmax support");
|
||||
DATA(insert OID = 3386 ( brin_minmax_union PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_minmax_union _null_ _null_ _null_ ));
|
||||
DESCR("BRIN minmax support");
|
||||
|
||||
/* BRIN inclusion */
|
||||
DATA(insert OID = 4105 ( brin_inclusion_opcinfo PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ _null_ brin_inclusion_opcinfo _null_ _null_ _null_ ));
|
||||
DESCR("BRIN inclusion support");
|
||||
DATA(insert OID = 4106 ( brin_inclusion_add_value PGNSP PGUID 12 1 0 0 0 f f f f t f i 4 0 16 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_inclusion_add_value _null_ _null_ _null_ ));
|
||||
DESCR("BRIN inclusion support");
|
||||
DATA(insert OID = 4107 ( brin_inclusion_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_inclusion_consistent _null_ _null_ _null_ ));
|
||||
DESCR("BRIN inclusion support");
|
||||
DATA(insert OID = 4108 ( brin_inclusion_union PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ _null_ brin_inclusion_union _null_ _null_ _null_ ));
|
||||
DESCR("BRIN inclusion support");
|
||||
|
||||
/* userlock replacements */
|
||||
DATA(insert OID = 2880 ( pg_advisory_lock PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ _null_ pg_advisory_lock_int8 _null_ _null_ _null_ ));
|
||||
DESCR("obtain exclusive advisory lock");
|
||||
|
@ -23,7 +23,9 @@ CREATE TABLE brintest (byteacol bytea,
|
||||
varbitcol bit varying(16),
|
||||
numericcol numeric,
|
||||
uuidcol uuid,
|
||||
lsncol pg_lsn
|
||||
int4rangecol int4range,
|
||||
lsncol pg_lsn,
|
||||
boxcol box
|
||||
) WITH (fillfactor=10, autovacuum_enabled=off);
|
||||
INSERT INTO brintest SELECT
|
||||
repeat(stringu1, 8)::bytea,
|
||||
@ -50,12 +52,15 @@ INSERT INTO brintest SELECT
|
||||
tenthous::bit(16)::varbit,
|
||||
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 LIMIT 25;
|
||||
int4range(thousand, twothousand),
|
||||
format('%s/%s%s', odd, even, tenthous)::pg_lsn,
|
||||
box(point(odd, even), point(thousand, twothousand))
|
||||
FROM tenk1 LIMIT 100;
|
||||
-- throw in some NULL's and different values
|
||||
INSERT INTO brintest (inetcol, cidrcol) SELECT
|
||||
INSERT INTO brintest (inetcol, cidrcol, int4rangecol) SELECT
|
||||
inet 'fe80::6e40:8ff:fea9:8c46' + tenthous,
|
||||
cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous
|
||||
cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous,
|
||||
'empty'::int4range
|
||||
FROM tenk1 LIMIT 25;
|
||||
CREATE INDEX brinidx ON brintest USING brin (
|
||||
byteacol,
|
||||
@ -70,6 +75,7 @@ CREATE INDEX brinidx ON brintest USING brin (
|
||||
float4col,
|
||||
float8col,
|
||||
macaddrcol,
|
||||
inetcol inet_inclusion_ops,
|
||||
inetcol inet_minmax_ops,
|
||||
bpcharcol,
|
||||
datecol,
|
||||
@ -82,7 +88,9 @@ CREATE INDEX brinidx ON brintest USING brin (
|
||||
varbitcol,
|
||||
numericcol,
|
||||
uuidcol,
|
||||
lsncol
|
||||
int4rangecol,
|
||||
lsncol,
|
||||
boxcol
|
||||
) with (pages_per_range = 1);
|
||||
CREATE TABLE brinopers (colname name, typ text, op text[], value text[],
|
||||
check (cardinality(op) = cardinality(value)));
|
||||
@ -128,7 +136,12 @@ INSERT INTO brinopers VALUES
|
||||
('varbitcol', 'varbit(16)', '{>, >=, =, <=, <}', '{0000000000000100, 0000000000000100, 0001010001100110, 1111111111111000, 1111111111111000}'),
|
||||
('numericcol', 'numeric', '{>, >=, =, <=, <}', '{0.00, 0.01, 2268164.347826086956521739130434782609, 99470151.9, 99470151.9}'),
|
||||
('uuidcol', 'uuid', '{>, >=, =, <=, <}', '{00040004-0004-0004-0004-000400040004, 00040004-0004-0004-0004-000400040004, 52225222-5222-5222-5222-522252225222, 99989998-9998-9998-9998-999899989998, 99989998-9998-9998-9998-999899989998}'),
|
||||
('lsncol', 'pg_lsn', '{>, >=, =, <=, <, IS, IS NOT}', '{0/1200, 0/1200, 44/455222, 198/1999799, 198/1999799, NULL, NULL}');
|
||||
('int4rangecol', 'int4range', '{<<, &<, &&, &>, >>, @>, <@, =, <, <=, >, >=}', '{"[10000,)","[10000,)","(,]","[3,4)","[36,44)","(1500,1501]","[3,4)","[222,1222)","[36,44)","[43,1043)","[367,4466)","[519,)"}'),
|
||||
('int4rangecol', 'int4range', '{@>, <@, =, <=, >, >=}', '{empty, empty, empty, empty, empty, empty}'),
|
||||
('int4rangecol', 'int4', '{@>}', '{1500}'),
|
||||
('lsncol', 'pg_lsn', '{>, >=, =, <=, <, IS, IS NOT}', '{0/1200, 0/1200, 44/455222, 198/1999799, 198/1999799, NULL, NULL}'),
|
||||
('boxcol', 'point', '{@>}', '{"(500,43)"}'),
|
||||
('boxcol', 'box', '{<<, &<, &&, &>, >>, <<|, &<|, |&>, |>>, @>, <@, ~=}', '{"((1000,2000),(3000,4000))","((1,2),(3000,4000))","((1,2),(3000,4000))","((1,2),(3000,4000))","((1,2),(3,4))","((1000,2000),(3000,4000))","((1,2000),(3,4000))","((1000,2),(3000,4))","((1,2),(3,4))","((1,2),(300,400))","((1,2),(3000,4000))","((222,1222),(44,45))"}');
|
||||
DO $x$
|
||||
DECLARE
|
||||
r record;
|
||||
@ -222,7 +235,9 @@ INSERT INTO brintest SELECT
|
||||
tenthous::bit(16)::varbit,
|
||||
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
|
||||
int4range(thousand, twothousand),
|
||||
format('%s/%s%s', odd, even, tenthous)::pg_lsn,
|
||||
box(point(odd, even), point(thousand, twothousand))
|
||||
FROM tenk1 LIMIT 5 OFFSET 5;
|
||||
SELECT brin_summarize_new_values('brinidx'::regclass);
|
||||
brin_summarize_new_values
|
||||
|
@ -1657,10 +1657,33 @@ ORDER BY 1, 2, 3;
|
||||
2742 | 10 | ?|
|
||||
2742 | 11 | ?&
|
||||
3580 | 1 | <
|
||||
3580 | 1 | <<
|
||||
3580 | 2 | &<
|
||||
3580 | 2 | <=
|
||||
3580 | 3 | &&
|
||||
3580 | 3 | =
|
||||
3580 | 4 | &>
|
||||
3580 | 4 | >=
|
||||
3580 | 5 | >
|
||||
3580 | 5 | >>
|
||||
3580 | 6 | ~=
|
||||
3580 | 7 | >>=
|
||||
3580 | 7 | @>
|
||||
3580 | 8 | <<=
|
||||
3580 | 8 | <@
|
||||
3580 | 9 | &<|
|
||||
3580 | 10 | <<|
|
||||
3580 | 11 | |>>
|
||||
3580 | 12 | |&>
|
||||
3580 | 16 | @>
|
||||
3580 | 17 | -|-
|
||||
3580 | 18 | =
|
||||
3580 | 20 | <
|
||||
3580 | 21 | <=
|
||||
3580 | 22 | >
|
||||
3580 | 23 | >=
|
||||
3580 | 24 | >>
|
||||
3580 | 26 | <<
|
||||
4000 | 1 | <<
|
||||
4000 | 1 | ~<~
|
||||
4000 | 2 | &<
|
||||
@ -1683,7 +1706,7 @@ ORDER BY 1, 2, 3;
|
||||
4000 | 15 | >
|
||||
4000 | 16 | @>
|
||||
4000 | 18 | =
|
||||
(85 rows)
|
||||
(108 rows)
|
||||
|
||||
-- Check that all opclass search operators have selectivity estimators.
|
||||
-- This is not absolutely required, but it seems a reasonable thing
|
||||
|
@ -23,7 +23,9 @@ CREATE TABLE brintest (byteacol bytea,
|
||||
varbitcol bit varying(16),
|
||||
numericcol numeric,
|
||||
uuidcol uuid,
|
||||
lsncol pg_lsn
|
||||
int4rangecol int4range,
|
||||
lsncol pg_lsn,
|
||||
boxcol box
|
||||
) WITH (fillfactor=10, autovacuum_enabled=off);
|
||||
|
||||
INSERT INTO brintest SELECT
|
||||
@ -51,13 +53,16 @@ INSERT INTO brintest SELECT
|
||||
tenthous::bit(16)::varbit,
|
||||
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 LIMIT 25;
|
||||
int4range(thousand, twothousand),
|
||||
format('%s/%s%s', odd, even, tenthous)::pg_lsn,
|
||||
box(point(odd, even), point(thousand, twothousand))
|
||||
FROM tenk1 LIMIT 100;
|
||||
|
||||
-- throw in some NULL's and different values
|
||||
INSERT INTO brintest (inetcol, cidrcol) SELECT
|
||||
INSERT INTO brintest (inetcol, cidrcol, int4rangecol) SELECT
|
||||
inet 'fe80::6e40:8ff:fea9:8c46' + tenthous,
|
||||
cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous
|
||||
cidr 'fe80::6e40:8ff:fea9:8c46' + tenthous,
|
||||
'empty'::int4range
|
||||
FROM tenk1 LIMIT 25;
|
||||
|
||||
CREATE INDEX brinidx ON brintest USING brin (
|
||||
@ -73,6 +78,7 @@ CREATE INDEX brinidx ON brintest USING brin (
|
||||
float4col,
|
||||
float8col,
|
||||
macaddrcol,
|
||||
inetcol inet_inclusion_ops,
|
||||
inetcol inet_minmax_ops,
|
||||
bpcharcol,
|
||||
datecol,
|
||||
@ -85,7 +91,9 @@ CREATE INDEX brinidx ON brintest USING brin (
|
||||
varbitcol,
|
||||
numericcol,
|
||||
uuidcol,
|
||||
lsncol
|
||||
int4rangecol,
|
||||
lsncol,
|
||||
boxcol
|
||||
) with (pages_per_range = 1);
|
||||
|
||||
CREATE TABLE brinopers (colname name, typ text, op text[], value text[],
|
||||
@ -133,7 +141,12 @@ INSERT INTO brinopers VALUES
|
||||
('varbitcol', 'varbit(16)', '{>, >=, =, <=, <}', '{0000000000000100, 0000000000000100, 0001010001100110, 1111111111111000, 1111111111111000}'),
|
||||
('numericcol', 'numeric', '{>, >=, =, <=, <}', '{0.00, 0.01, 2268164.347826086956521739130434782609, 99470151.9, 99470151.9}'),
|
||||
('uuidcol', 'uuid', '{>, >=, =, <=, <}', '{00040004-0004-0004-0004-000400040004, 00040004-0004-0004-0004-000400040004, 52225222-5222-5222-5222-522252225222, 99989998-9998-9998-9998-999899989998, 99989998-9998-9998-9998-999899989998}'),
|
||||
('lsncol', 'pg_lsn', '{>, >=, =, <=, <, IS, IS NOT}', '{0/1200, 0/1200, 44/455222, 198/1999799, 198/1999799, NULL, NULL}');
|
||||
('int4rangecol', 'int4range', '{<<, &<, &&, &>, >>, @>, <@, =, <, <=, >, >=}', '{"[10000,)","[10000,)","(,]","[3,4)","[36,44)","(1500,1501]","[3,4)","[222,1222)","[36,44)","[43,1043)","[367,4466)","[519,)"}'),
|
||||
('int4rangecol', 'int4range', '{@>, <@, =, <=, >, >=}', '{empty, empty, empty, empty, empty, empty}'),
|
||||
('int4rangecol', 'int4', '{@>}', '{1500}'),
|
||||
('lsncol', 'pg_lsn', '{>, >=, =, <=, <, IS, IS NOT}', '{0/1200, 0/1200, 44/455222, 198/1999799, 198/1999799, NULL, NULL}'),
|
||||
('boxcol', 'point', '{@>}', '{"(500,43)"}'),
|
||||
('boxcol', 'box', '{<<, &<, &&, &>, >>, <<|, &<|, |&>, |>>, @>, <@, ~=}', '{"((1000,2000),(3000,4000))","((1,2),(3000,4000))","((1,2),(3000,4000))","((1,2),(3000,4000))","((1,2),(3,4))","((1000,2000),(3000,4000))","((1,2000),(3,4000))","((1000,2),(3000,4))","((1,2),(3,4))","((1,2),(300,400))","((1,2),(3000,4000))","((222,1222),(44,45))"}');
|
||||
|
||||
DO $x$
|
||||
DECLARE
|
||||
@ -229,7 +242,9 @@ INSERT INTO brintest SELECT
|
||||
tenthous::bit(16)::varbit,
|
||||
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
|
||||
int4range(thousand, twothousand),
|
||||
format('%s/%s%s', odd, even, tenthous)::pg_lsn,
|
||||
box(point(odd, even), point(thousand, twothousand))
|
||||
FROM tenk1 LIMIT 5 OFFSET 5;
|
||||
|
||||
SELECT brin_summarize_new_values('brinidx'::regclass);
|
||||
|
Loading…
Reference in New Issue
Block a user