Commit 72ccf55c authored by Tomas Vondra's avatar Tomas Vondra

Move IS [NOT] NULL handling from BRIN support functions

The handling of IS [NOT] NULL clauses is independent of an opclass, and
most of the code was exactly the same in both minmax and inclusion. So
instead move the code from support procedures to the AM.

This simplifies the code - especially the support procedures - quite a
bit, as they don't need to care about NULL values and flags at all. It
also means the IS [NOT] NULL clauses can be evaluated without invoking
the support procedure.

Author: Tomas Vondra <tomas.vondra@postgresql.org>
Author: Nikita Glukhov <n.gluhov@postgrespro.ru>
Reviewed-by: default avatarNikita Glukhov <n.gluhov@postgrespro.ru>
Reviewed-by: default avatarMark Dilger <hornschnorter@gmail.com>
Reviewed-by: default avatarAlexander Korotkov <aekorotkov@gmail.com>
Reviewed-by: default avatarMasahiko Sawada <masahiko.sawada@enterprisedb.com>
Reviewed-by: default avatarJohn Naylor <john.naylor@enterprisedb.com>
Discussion: https://postgr.es/m/c1138ead-7668-f0e1-0638-c3be3237e812@2ndquadrant.com
parent a1c649d8
This diff is collapsed.
...@@ -110,6 +110,7 @@ brin_inclusion_opcinfo(PG_FUNCTION_ARGS) ...@@ -110,6 +110,7 @@ brin_inclusion_opcinfo(PG_FUNCTION_ARGS)
*/ */
result = palloc0(MAXALIGN(SizeofBrinOpcInfo(3)) + sizeof(InclusionOpaque)); result = palloc0(MAXALIGN(SizeofBrinOpcInfo(3)) + sizeof(InclusionOpaque));
result->oi_nstored = 3; result->oi_nstored = 3;
result->oi_regular_nulls = true;
result->oi_opaque = (InclusionOpaque *) result->oi_opaque = (InclusionOpaque *)
MAXALIGN((char *) result + SizeofBrinOpcInfo(3)); MAXALIGN((char *) result + SizeofBrinOpcInfo(3));
...@@ -141,7 +142,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS) ...@@ -141,7 +142,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS)
BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0); BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1); BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
Datum newval = PG_GETARG_DATUM(2); Datum newval = PG_GETARG_DATUM(2);
bool isnull = PG_GETARG_BOOL(3); bool isnull PG_USED_FOR_ASSERTS_ONLY = PG_GETARG_BOOL(3);
Oid colloid = PG_GET_COLLATION(); Oid colloid = PG_GET_COLLATION();
FmgrInfo *finfo; FmgrInfo *finfo;
Datum result; Datum result;
...@@ -149,18 +150,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS) ...@@ -149,18 +150,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS)
AttrNumber attno; AttrNumber attno;
Form_pg_attribute attr; Form_pg_attribute attr;
/* Assert(!isnull);
* 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; attno = column->bv_attno;
attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1); attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1);
...@@ -268,52 +258,9 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) ...@@ -268,52 +258,9 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS)
int nkeys = PG_GETARG_INT32(3); int nkeys = PG_GETARG_INT32(3);
Oid colloid = PG_GET_COLLATION(); Oid colloid = PG_GET_COLLATION();
int keyno; int keyno;
bool has_regular_keys = false;
/* Handle IS NULL/IS NOT NULL tests */
for (keyno = 0; keyno < nkeys; keyno++)
{
ScanKey key = keys[keyno];
Assert(key->sk_attno == column->bv_attno); /* make sure we got some scan keys */
Assert((nkeys > 0) && (keys != NULL));
/* Skip regular scan keys (and remember that we have some). */
if ((!key->sk_flags & SK_ISNULL))
{
has_regular_keys = true;
continue;
}
if (key->sk_flags & SK_SEARCHNULL)
{
if (column->bv_allnulls || column->bv_hasnulls)
continue; /* this key is fine, continue */
PG_RETURN_BOOL(false);
}
/*
* For IS NOT NULL, we can only skip ranges that are known to have
* only nulls.
*/
if (key->sk_flags & SK_SEARCHNOTNULL)
{
if (column->bv_allnulls)
PG_RETURN_BOOL(false);
continue;
}
/*
* Neither IS NULL nor IS NOT NULL was used; assume all indexable
* operators are strict and return false.
*/
PG_RETURN_BOOL(false);
}
/* If there are no regular keys, the page range is considered consistent. */
if (!has_regular_keys)
PG_RETURN_BOOL(true);
/* /*
* If is all nulls, it cannot possibly be consistent (at this point we * If is all nulls, it cannot possibly be consistent (at this point we
...@@ -331,9 +278,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) ...@@ -331,9 +278,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS)
{ {
ScanKey key = keys[keyno]; ScanKey key = keys[keyno];
/* Skip IS NULL/IS NOT NULL keys (already handled above). */ /* NULL keys are handled and filtered-out in bringetbitmap */
if (key->sk_flags & SK_ISNULL) Assert(!(key->sk_flags & SK_ISNULL));
continue;
/* /*
* When there are multiple scan keys, failure to meet the criteria for * When there are multiple scan keys, failure to meet the criteria for
...@@ -574,37 +520,11 @@ brin_inclusion_union(PG_FUNCTION_ARGS) ...@@ -574,37 +520,11 @@ brin_inclusion_union(PG_FUNCTION_ARGS)
Datum result; Datum result;
Assert(col_a->bv_attno == col_b->bv_attno); Assert(col_a->bv_attno == col_b->bv_attno);
Assert(!col_a->bv_allnulls && !col_b->bv_allnulls);
/* 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; attno = col_a->bv_attno;
attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1); attr = TupleDescAttr(bdesc->bd_tupdesc, 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 B includes empty elements, mark A similarly, if needed. */
if (!DatumGetBool(col_a->bv_values[INCLUSION_CONTAINS_EMPTY]) && if (!DatumGetBool(col_a->bv_values[INCLUSION_CONTAINS_EMPTY]) &&
DatumGetBool(col_b->bv_values[INCLUSION_CONTAINS_EMPTY])) DatumGetBool(col_b->bv_values[INCLUSION_CONTAINS_EMPTY]))
......
...@@ -48,6 +48,7 @@ brin_minmax_opcinfo(PG_FUNCTION_ARGS) ...@@ -48,6 +48,7 @@ brin_minmax_opcinfo(PG_FUNCTION_ARGS)
result = palloc0(MAXALIGN(SizeofBrinOpcInfo(2)) + result = palloc0(MAXALIGN(SizeofBrinOpcInfo(2)) +
sizeof(MinmaxOpaque)); sizeof(MinmaxOpaque));
result->oi_nstored = 2; result->oi_nstored = 2;
result->oi_regular_nulls = true;
result->oi_opaque = (MinmaxOpaque *) result->oi_opaque = (MinmaxOpaque *)
MAXALIGN((char *) result + SizeofBrinOpcInfo(2)); MAXALIGN((char *) result + SizeofBrinOpcInfo(2));
result->oi_typcache[0] = result->oi_typcache[1] = result->oi_typcache[0] = result->oi_typcache[1] =
...@@ -69,7 +70,7 @@ brin_minmax_add_value(PG_FUNCTION_ARGS) ...@@ -69,7 +70,7 @@ brin_minmax_add_value(PG_FUNCTION_ARGS)
BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0); BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1); BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
Datum newval = PG_GETARG_DATUM(2); Datum newval = PG_GETARG_DATUM(2);
bool isnull = PG_GETARG_DATUM(3); bool isnull PG_USED_FOR_ASSERTS_ONLY = PG_GETARG_DATUM(3);
Oid colloid = PG_GET_COLLATION(); Oid colloid = PG_GET_COLLATION();
FmgrInfo *cmpFn; FmgrInfo *cmpFn;
Datum compar; Datum compar;
...@@ -77,18 +78,7 @@ brin_minmax_add_value(PG_FUNCTION_ARGS) ...@@ -77,18 +78,7 @@ brin_minmax_add_value(PG_FUNCTION_ARGS)
Form_pg_attribute attr; Form_pg_attribute attr;
AttrNumber attno; AttrNumber attno;
/* Assert(!isnull);
* 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; attno = column->bv_attno;
attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1); attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1);
...@@ -156,52 +146,9 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) ...@@ -156,52 +146,9 @@ brin_minmax_consistent(PG_FUNCTION_ARGS)
int nkeys = PG_GETARG_INT32(3); int nkeys = PG_GETARG_INT32(3);
Oid colloid = PG_GET_COLLATION(); Oid colloid = PG_GET_COLLATION();
int keyno; int keyno;
bool has_regular_keys = false;
/* handle IS NULL/IS NOT NULL tests */
for (keyno = 0; keyno < nkeys; keyno++)
{
ScanKey key = keys[keyno];
Assert(key->sk_attno == column->bv_attno);
/* Skip regular scan keys (and remember that we have some). */
if ((!key->sk_flags & SK_ISNULL))
{
has_regular_keys = true;
continue;
}
if (key->sk_flags & SK_SEARCHNULL) /* make sure we got some scan keys */
{ Assert((nkeys > 0) && (keys != NULL));
if (column->bv_allnulls || column->bv_hasnulls)
continue; /* this key is fine, continue */
PG_RETURN_BOOL(false);
}
/*
* For IS NOT NULL, we can only skip ranges that are known to have
* only nulls.
*/
if (key->sk_flags & SK_SEARCHNOTNULL)
{
if (column->bv_allnulls)
PG_RETURN_BOOL(false);
continue;
}
/*
* Neither IS NULL nor IS NOT NULL was used; assume all indexable
* operators are strict and return false.
*/
PG_RETURN_BOOL(false);
}
/* If there are no regular keys, the page range is considered consistent. */
if (!has_regular_keys)
PG_RETURN_BOOL(true);
/* /*
* If is all nulls, it cannot possibly be consistent (at this point we * If is all nulls, it cannot possibly be consistent (at this point we
...@@ -215,9 +162,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) ...@@ -215,9 +162,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS)
{ {
ScanKey key = keys[keyno]; ScanKey key = keys[keyno];
/* ignore IS NULL/IS NOT NULL tests handled above */ /* NULL keys are handled and filtered-out in bringetbitmap */
if (key->sk_flags & SK_ISNULL) Assert(!(key->sk_flags & SK_ISNULL));
continue;
/* /*
* When there are multiple scan keys, failure to meet the criteria for * When there are multiple scan keys, failure to meet the criteria for
...@@ -307,34 +253,11 @@ brin_minmax_union(PG_FUNCTION_ARGS) ...@@ -307,34 +253,11 @@ brin_minmax_union(PG_FUNCTION_ARGS)
bool needsadj; bool needsadj;
Assert(col_a->bv_attno == col_b->bv_attno); Assert(col_a->bv_attno == col_b->bv_attno);
Assert(!col_a->bv_allnulls && !col_b->bv_allnulls);
/* 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; attno = col_a->bv_attno;
attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1); attr = TupleDescAttr(bdesc->bd_tupdesc, 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[0] = datumCopy(col_b->bv_values[0],
attr->attbyval, attr->attlen);
col_a->bv_values[1] = datumCopy(col_b->bv_values[1],
attr->attbyval, attr->attlen);
PG_RETURN_VOID();
}
/* Adjust minimum, if B's min is less than A's min */ /* Adjust minimum, if B's min is less than A's min */
finfo = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid, finfo = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid,
BTLessStrategyNumber); BTLessStrategyNumber);
......
...@@ -27,6 +27,9 @@ typedef struct BrinOpcInfo ...@@ -27,6 +27,9 @@ typedef struct BrinOpcInfo
/* Number of columns stored in an index column of this opclass */ /* Number of columns stored in an index column of this opclass */
uint16 oi_nstored; uint16 oi_nstored;
/* Regular processing of NULLs in BrinValues? */
bool oi_regular_nulls;
/* Opaque pointer for the opclass' private use */ /* Opaque pointer for the opclass' private use */
void *oi_opaque; void *oi_opaque;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment