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:
Alvaro Herrera 2015-05-15 18:05:22 -03:00
parent 199f5973c5
commit b0b7be6133
18 changed files with 928 additions and 105 deletions

View File

@ -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>&gt;</literal>
</entry>
</row>
<row>
<entry><literal>inet_inclusion_ops</literal></entry>
<entry><type>inet</type></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&gt;&gt;</>
<literal>&gt;&gt;=</>
<literal>&lt;&lt;</literal>
<literal>&lt;&lt;=</literal>
<literal>=</literal>
</entry>
</row>
<row>
<entry><literal>bpchar_minmax_ops</literal></entry>
<entry><type>character</type></entry>
@ -372,6 +386,25 @@
<literal>&gt;</literal>
</entry>
</row>
<row>
<entry><literal>range_inclusion_ops</></entry>
<entry><type>any range type</type></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&amp;&gt;</>
<literal>&amp;&lt;</>
<literal>&gt;&gt;</>
<literal>&lt;&lt;</>
<literal>&lt;@</>
<literal>=</>
<literal>@&gt;</>
<literal>&lt;</literal>
<literal>&lt;=</literal>
<literal>=</literal>
<literal>&gt;=</literal>
<literal>&gt;</literal>
</entry>
</row>
<row>
<entry><literal>pg_lsn_minmax_ops</literal></entry>
<entry><type>pg_lsn</type></entry>
@ -383,6 +416,24 @@
<literal>&gt;</literal>
</entry>
</row>
<row>
<entry><literal>box_inclusion_ops</></entry>
<entry><type>box</type></entry>
<entry>
<literal>&amp;&amp;</>
<literal>&amp;&gt;</>
<literal>&amp;&lt;</>
<literal>&gt;&gt;</>
<literal>&lt;&lt;</>
<literal>&lt;@</>
<literal>~=</>
<literal>@&gt;</>
<literal>&amp;&gt;|</>
<literal>|&amp;&lt;</>
<literal>&gt;&gt;|</>
<literal>|&lt;&lt;</literal>
</entry>
</row>
</tbody>
</tgroup>
</table>

View File

@ -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

View File

@ -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

View 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];
}

View File

@ -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,

View File

@ -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
/*

View File

@ -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 */

View File

@ -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

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201505151
#define CATALOG_VERSION_NO 201505152
#endif

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -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);