public inbox for [email protected]help / color / mirror / Atom feed
Partitioned tables vs GRANT 38+ messages / 7 participants [nested] [flat]
* Partitioned tables vs GRANT @ 2017-04-07 18:05 Joe Conway <[email protected]> 2017-04-07 18:31 ` Re: Partitioned tables vs GRANT Keith Fiske <[email protected]> 2017-04-07 18:46 ` Re: Partitioned tables vs GRANT Tom Lane <[email protected]> 0 siblings, 2 replies; 38+ messages in thread From: Joe Conway @ 2017-04-07 18:05 UTC (permalink / raw) To: pgsql-hackers Apparently INSERT and SELECT on the parent partitioned table skip normal acl checks on the partitions. Is that intended behavior? 8<--------------------------- test=# create user part_test; CREATE ROLE test=# test=# create table t1 (id int) partition by range ((id % 4)); CREATE TABLE test=# create table t1_0 partition of t1 for values from (0) to (1); CREATE TABLE test=# create table t1_1 partition of t1 for values from (1) to (2); CREATE TABLE test=# create table t1_2 partition of t1 for values from (2) to (3); CREATE TABLE test=# create table t1_3 partition of t1 for values from (3) to (4); CREATE TABLE test=# grant all on TABLE t1 to part_test; GRANT test=# set session authorization part_test ; SET test=> select current_user; current_user -------------- part_test (1 row) test=> insert into t1 values(0),(1),(2),(3); INSERT 0 4 test=> insert into t1_0 values(0); ERROR: permission denied for relation t1_0 test=> insert into t1_1 values(1); ERROR: permission denied for relation t1_1 test=> insert into t1_2 values(2); ERROR: permission denied for relation t1_2 test=> insert into t1_3 values(3); ERROR: permission denied for relation t1_3 test=> select * from t1; id ---- 0 1 2 3 (4 rows) test=> select * from t1_0; ERROR: permission denied for relation t1_0 test=> select * from t1_1; ERROR: permission denied for relation t1_1 test=> select * from t1_2; ERROR: permission denied for relation t1_2 test=> select * from t1_3; ERROR: permission denied for relation t1_3 test=> reset session authorization; RESET test=# drop table if exists t1; DROP TABLE 8<--------------------------- Joe -- Crunchy Data - http://crunchydata.com PostgreSQL Support for Secure Enterprises Consulting, Training, & Open Source Development Attachments: [application/pgp-signature] signature.asc (819B, ../../[email protected]/2-signature.asc) download ^ permalink raw reply [nested|flat] 38+ messages in thread
* Re: Partitioned tables vs GRANT 2017-04-07 18:05 Partitioned tables vs GRANT Joe Conway <[email protected]> @ 2017-04-07 18:31 ` Keith Fiske <[email protected]> 1 sibling, 0 replies; 38+ messages in thread From: Keith Fiske @ 2017-04-07 18:31 UTC (permalink / raw) To: pgsql-hackers On Fri, Apr 7, 2017 at 2:05 PM, Joe Conway <[email protected]> wrote: > Apparently INSERT and SELECT on the parent partitioned table skip normal > acl checks on the partitions. Is that intended behavior? > > 8<--------------------------- > test=# create user part_test; > CREATE ROLE > test=# > test=# create table t1 (id int) partition by range ((id % 4)); > CREATE TABLE > test=# create table t1_0 partition of t1 for values from (0) to (1); > CREATE TABLE > test=# create table t1_1 partition of t1 for values from (1) to (2); > CREATE TABLE > test=# create table t1_2 partition of t1 for values from (2) to (3); > CREATE TABLE > test=# create table t1_3 partition of t1 for values from (3) to (4); > CREATE TABLE > test=# grant all on TABLE t1 to part_test; > GRANT > test=# set session authorization part_test ; > SET > test=> select current_user; > current_user > -------------- > part_test > (1 row) > > test=> insert into t1 values(0),(1),(2),(3); > INSERT 0 4 > test=> insert into t1_0 values(0); > ERROR: permission denied for relation t1_0 > test=> insert into t1_1 values(1); > ERROR: permission denied for relation t1_1 > test=> insert into t1_2 values(2); > ERROR: permission denied for relation t1_2 > test=> insert into t1_3 values(3); > ERROR: permission denied for relation t1_3 > test=> select * from t1; > id > ---- > 0 > 1 > 2 > 3 > (4 rows) > > test=> select * from t1_0; > ERROR: permission denied for relation t1_0 > test=> select * from t1_1; > ERROR: permission denied for relation t1_1 > test=> select * from t1_2; > ERROR: permission denied for relation t1_2 > test=> select * from t1_3; > ERROR: permission denied for relation t1_3 > test=> reset session authorization; > RESET > test=# drop table if exists t1; > DROP TABLE > 8<--------------------------- > > Joe > > -- > Crunchy Data - http://crunchydata.com > PostgreSQL Support for Secure Enterprises > Consulting, Training, & Open Source Development > > I encountered that as well testing for native in pg_partman. I had to include the code for non-native that propagates ownership/privileges from the parent to the child. Another question to ask is that if you change privileges on the parent, does that automatically change them for all children as well? I encountered this being a rather expensive operation using plpgsql methods to fix it when the child count grows high. That's why I have resetting all child table privileges as a separate, manual function and changes only apply to new partitions automatically. Hopefully internally there's a more efficient way. Keith ^ permalink raw reply [nested|flat] 38+ messages in thread
* Re: Partitioned tables vs GRANT 2017-04-07 18:05 Partitioned tables vs GRANT Joe Conway <[email protected]> @ 2017-04-07 18:46 ` Tom Lane <[email protected]> 2017-04-08 00:02 ` Re: Partitioned tables vs GRANT Keith Fiske <[email protected]> 1 sibling, 1 reply; 38+ messages in thread From: Tom Lane @ 2017-04-07 18:46 UTC (permalink / raw) To: Joe Conway <[email protected]>; +Cc: pgsql-hackers Joe Conway <[email protected]> writes: > Apparently INSERT and SELECT on the parent partitioned table skip normal > acl checks on the partitions. Is that intended behavior? Yes, this matches normal inheritance behavior. regards, tom lane -- Sent via pgsql-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers ^ permalink raw reply [nested|flat] 38+ messages in thread
* Re: Partitioned tables vs GRANT 2017-04-07 18:05 Partitioned tables vs GRANT Joe Conway <[email protected]> 2017-04-07 18:46 ` Re: Partitioned tables vs GRANT Tom Lane <[email protected]> @ 2017-04-08 00:02 ` Keith Fiske <[email protected]> 2017-04-08 00:41 ` Re: Partitioned tables vs GRANT Tom Lane <[email protected]> 0 siblings, 1 reply; 38+ messages in thread From: Keith Fiske @ 2017-04-08 00:02 UTC (permalink / raw) To: Tom Lane <[email protected]>; +Cc: Joe Conway <[email protected]>; pgsql-hackers On Fri, Apr 7, 2017 at 2:46 PM, Tom Lane <[email protected]> wrote: > Joe Conway <[email protected]> writes: > > Apparently INSERT and SELECT on the parent partitioned table skip normal > > acl checks on the partitions. Is that intended behavior? > > Yes, this matches normal inheritance behavior. > > regards, tom lane > > > -- > Sent via pgsql-hackers mailing list ([email protected]) > To make changes to your subscription: > http://www.postgresql.org/mailpref/pgsql-hackers > Should that really be normal partitioning behavior though? Pretty sure people would expect child tables to have consistent permissions in a partition set and I'd think setting them on the parent should be what they expect the children to have. Keith ^ permalink raw reply [nested|flat] 38+ messages in thread
* Re: Partitioned tables vs GRANT 2017-04-07 18:05 Partitioned tables vs GRANT Joe Conway <[email protected]> 2017-04-07 18:46 ` Re: Partitioned tables vs GRANT Tom Lane <[email protected]> 2017-04-08 00:02 ` Re: Partitioned tables vs GRANT Keith Fiske <[email protected]> @ 2017-04-08 00:41 ` Tom Lane <[email protected]> 2017-04-08 01:18 ` Re: Partitioned tables vs GRANT Keith Fiske <[email protected]> 0 siblings, 1 reply; 38+ messages in thread From: Tom Lane @ 2017-04-08 00:41 UTC (permalink / raw) To: Keith Fiske <[email protected]>; +Cc: Joe Conway <[email protected]>; pgsql-hackers Keith Fiske <[email protected]> writes: > On Fri, Apr 7, 2017 at 2:46 PM, Tom Lane <[email protected]> wrote: >> Joe Conway <[email protected]> writes: >>> Apparently INSERT and SELECT on the parent partitioned table skip normal >>> acl checks on the partitions. Is that intended behavior? >> Yes, this matches normal inheritance behavior. > Should that really be normal partitioning behavior though? Yes, it should. Consider the alternatives: 1. Owner must remember to run around and grant permissions on all child tables along with the parent. 2. The system silently(?) doesn't show you some rows that are supposed to be visible when scanning the parent table. If you want RLS, use RLS; this is not that, and is not a good substitute. (We've been around on this topic before, btw. See the archives.) regards, tom lane -- Sent via pgsql-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers ^ permalink raw reply [nested|flat] 38+ messages in thread
* Re: Partitioned tables vs GRANT 2017-04-07 18:05 Partitioned tables vs GRANT Joe Conway <[email protected]> 2017-04-07 18:46 ` Re: Partitioned tables vs GRANT Tom Lane <[email protected]> 2017-04-08 00:02 ` Re: Partitioned tables vs GRANT Keith Fiske <[email protected]> 2017-04-08 00:41 ` Re: Partitioned tables vs GRANT Tom Lane <[email protected]> @ 2017-04-08 01:18 ` Keith Fiske <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Keith Fiske @ 2017-04-08 01:18 UTC (permalink / raw) To: Tom Lane <[email protected]>; +Cc: Joe Conway <[email protected]>; pgsql-hackers On Fri, Apr 7, 2017 at 8:41 PM, Tom Lane <[email protected]> wrote: > Keith Fiske <[email protected]> writes: > > On Fri, Apr 7, 2017 at 2:46 PM, Tom Lane <[email protected]> wrote: > >> Joe Conway <[email protected]> writes: > >>> Apparently INSERT and SELECT on the parent partitioned table skip > normal > >>> acl checks on the partitions. Is that intended behavior? > > >> Yes, this matches normal inheritance behavior. > > > Should that really be normal partitioning behavior though? > > Yes, it should. Consider the alternatives: > > 1. Owner must remember to run around and grant permissions on all child > tables along with the parent. > I'm not following. That's what Joe is saying is happening now. The child tables are not getting the parent privileges so this is what the owner must remember to do every time they add a new child if they want to role to be able to interact directly with the children. They can select, insert, etc with the parent, but any direct interaction with the child is denied. I know you're all trying to make the planner work so queries work efficiently from the parent, but they'll never be as good as being able to hit the child tables directly if they know where the data they want is. Why even leave the child tables visible at all they can't be interacted with the same as the parent? I thought that was supposed to be one of the advantages to doing partitioning this way vs how Oracle & MySQL do it. > 2. The system silently(?) doesn't show you some rows that are supposed > to be visible when scanning the parent table. > > If you want RLS, use RLS; this is not that, and is not a good substitute. > Agreed. It appears the rows are visible if the role has select privileges on the parent. But they cannot select directly from children. Not sure what this has to do with RLS. > > (We've been around on this topic before, btw. See the archives.) > > regards, tom lane > ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --vurodj3csurzcvv3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200906.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/6] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --2wz2lexbyaxcz4wc Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support-20200911b.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/5] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index f1beb2eff9..25ae02a999 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -388,8 +388,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -414,10 +416,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -439,14 +444,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -454,9 +457,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -543,6 +560,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.21.3 --2llqbgqyhgtvqz5p Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200513.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 02/10] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --6k3bcoookz7x4sns Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200911.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/5] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index f1beb2eff9..25ae02a999 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -388,8 +388,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -414,10 +416,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -439,14 +444,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -454,9 +457,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -543,6 +560,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --23ba6kc72aujkita Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200703.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 6777d48faf..caf7b62688 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -389,8 +389,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -415,10 +417,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -440,14 +445,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -455,9 +458,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -544,6 +561,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.25.4 --jsivyprvf2oxfjz3 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200807.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* [PATCH 2/5] Move IS NOT NULL checks to bringetbitmap @ 2019-06-09 20:05 Tomas Vondra <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Tomas Vondra @ 2019-06-09 20:05 UTC (permalink / raw) --- src/backend/access/brin/brin.c | 116 ++++++++++++++++++++--- src/backend/access/brin/brin_inclusion.c | 62 +----------- src/backend/access/brin/brin_minmax.c | 62 +----------- 3 files changed, 109 insertions(+), 131 deletions(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index f1beb2eff9..25ae02a999 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -388,8 +388,10 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BrinMemTuple *dtup; BrinTuple *btup = NULL; Size btupsz = 0; - ScanKey **keys; - int *nkeys; + ScanKey **keys, + **nullkeys; + int *nkeys, + *nnullkeys; int keyno; opaque = (BrinOpaque *) scan->opaque; @@ -414,10 +416,13 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) /* * Make room for per-attribute lists of scan keys that we'll pass to the - * consistent support procedure. + * consistent support procedure. We keep null and regular keys separate, + * so that we can easily pass regular keys to the consistent function. */ keys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); + nullkeys = palloc0(sizeof(ScanKey *) * bdesc->bd_tupdesc->natts); nkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); + nnullkeys = palloc0(sizeof(int) * bdesc->bd_tupdesc->natts); /* * Preprocess the scan keys - split them into per-attribute arrays. @@ -439,14 +444,12 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) keyattno - 1)->attcollation)); /* First time we see this index attribute, so init as needed. */ - if (!keys[keyattno-1]) + if (consistentFn[keyattno - 1].fn_oid == InvalidOid) { FmgrInfo *tmp; - keys[keyattno-1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); - - /* First time this column, so look up consistent function */ - Assert(consistentFn[keyattno - 1].fn_oid == InvalidOid); + Assert((keys[keyattno - 1] == NULL) && (nkeys[keyattno - 1] == 0)); + Assert((nullkeys[keyattno - 1] == NULL) && (nnullkeys[keyattno - 1] == 0)); tmp = index_getprocinfo(idxRel, keyattno, BRIN_PROCNUM_CONSISTENT); @@ -454,9 +457,23 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) CurrentMemoryContext); } - /* Add key to the per-attribute array. */ - keys[keyattno - 1][nkeys[keyattno - 1]] = key; - nkeys[keyattno - 1]++; + /* Add key to the proper per-attribute array. */ + if (key->sk_flags & SK_ISNULL) + { + if (!nullkeys[keyattno - 1]) + nullkeys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + nullkeys[keyattno - 1][nnullkeys[keyattno - 1]] = key; + nnullkeys[keyattno - 1]++; + } + else + { + if (!keys[keyattno - 1]) + keys[keyattno - 1] = palloc0(sizeof(ScanKey) * scan->numberOfKeys); + + keys[keyattno - 1][nkeys[keyattno - 1]] = key; + nkeys[keyattno - 1]++; + } } /* allocate an initial in-memory tuple, out of the per-range memcxt */ @@ -543,6 +560,83 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) Assert((nkeys[attno - 1] > 0) && (nkeys[attno - 1] <= scan->numberOfKeys)); + /* + * First check if there are any IS [NOT] NULL scan keys, and + * if we're violating them. In that case we can terminate + * early, without invoking the support function. + * + * As there may be more keys, we can only detemine mismatch + * within this loop. + */ + for (keyno = 0; (keyno < nnullkeys[attno - 1]); keyno++) + { + ScanKey key = nullkeys[attno - 1][keyno]; + + Assert(key->sk_attno == bval->bv_attno); + + /* interrupt the loop as soon as we find a mismatch */ + if (!addrange) + break; + + /* handle IS NULL/IS NOT NULL tests */ + if (key->sk_flags & SK_ISNULL) + { + /* IS NULL scan key, but range has no NULLs */ + if (key->sk_flags & SK_SEARCHNULL) + { + if (!bval->bv_allnulls && !bval->bv_hasnulls) + addrange = false; + + continue; + } + + /* + * For IS NOT NULL, we can only skip ranges that are + * known to have only nulls. + */ + if (key->sk_flags & SK_SEARCHNOTNULL) + { + if (bval->bv_allnulls) + addrange = false; + + continue; + } + + /* + * Neither IS NULL nor IS NOT NULL was used; assume all + * indexable operators are strict and thus return false + * with NULL value in the scan key. + */ + addrange = false; + } + } + + /* + * If any of the IS [NOT] NULL keys failed, the page range as + * a whole can't pass. So terminate the loop. + */ + if (!addrange) + break; + + /* + * So either there are no IS [NOT] NULL keys, or all passed. If + * there are no regular scan keys, we're done - the page range + * matches. If there are regular keys, but the page range is + * marked as 'all nulls' it can't possibly pass (we're assuming + * the operators are strict). + */ + + /* No regular scan keys - page range as a whole passes. */ + if (!nkeys[attno - 1]) + continue; + + /* If it is all nulls, it cannot possibly be consistent. */ + if (bval->bv_allnulls) + { + addrange = false; + break; + } + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 8968886ff5..22edc6b46f 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -265,63 +265,6 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); int keyno; bool matches; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) @@ -333,9 +276,8 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = inclusion_consistent_key(bdesc, column, key, colloid); diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 1219a3a2ab..7a7bd21cec 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -153,63 +153,6 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) Oid colloid = PG_GET_COLLATION(); Datum matches; int keyno; - bool regular_keys = false; - - /* - * First check if there are any IS NULL scan keys, and if we're - * violating them. In that case we can terminate early, without - * inspecting the ranges. - */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - 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) - 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); - } - else - /* note we have regular (non-NULL) scan keys */ - regular_keys = true; - } - - /* - * If the page range is all nulls, it cannot possibly be consistent if - * there are some regular scan keys. - */ - if (column->bv_allnulls && regular_keys) - PG_RETURN_BOOL(false); - - /* If there are no regular keys, the page range is considered consistent. */ - if (!regular_keys) - PG_RETURN_BOOL(true); matches = true; @@ -217,9 +160,8 @@ brin_minmax_consistent(PG_FUNCTION_ARGS) { ScanKey key = keys[keyno]; - /* ignore IS NULL/IS NOT NULL tests handled above */ - if (key->sk_flags & SK_ISNULL) - continue; + /* NULL keys are handled and filtered-out in bringetbitmap */ + Assert(!(key->sk_flags & SK_ISNULL)); matches = minmax_consistent_key(bdesc, column, key, colloid); -- 2.21.1 --mdnsfkfco6eh7s2p Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0003-Move-processing-of-NULLs-from-BRIN-support--20200402.patch" ^ permalink raw reply [nested|flat] 38+ messages in thread
* Re: Size vs size_t or, um, PgSize? @ 2023-07-03 18:46 Daniel Gustafsson <[email protected]> 2023-07-03 19:02 ` Re: Size vs size_t or, um, PgSize? Thomas Munro <[email protected]> 2023-07-03 22:20 ` Re: Size vs size_t or, um, PgSize? Tom Lane <[email protected]> 0 siblings, 2 replies; 38+ messages in thread From: Daniel Gustafsson @ 2023-07-03 18:46 UTC (permalink / raw) To: Yurii Rashkovskii <[email protected]>; +Cc: [email protected] > On 3 Jul 2023, at 20:32, Yurii Rashkovskii <[email protected]> wrote: > I couldn't find any rationale as to why we might want to have this alias and not use size_t. Any insight on this would be appreciated. This used to be a typedef for unsigned int a very long time ago. > Would there be any sense in changing it all to size_t or renaming it to something else? > > I understand that they will break some extensions, so if we don't want them to have to go through with the renaming, can we enable backward compatibility with a macro? > > If there's a willingness to try this out, I am happy to prepare a patch. This has been discussed a number of times in the past, and the conclusion from last time IIRC was to use size_t for new code and only change the existing instances when touched for other reasons to avoid churn. -- Daniel Gustafsson ^ permalink raw reply [nested|flat] 38+ messages in thread
* Re: Size vs size_t or, um, PgSize? 2023-07-03 18:46 Re: Size vs size_t or, um, PgSize? Daniel Gustafsson <[email protected]> @ 2023-07-03 19:02 ` Thomas Munro <[email protected]> 2023-07-03 19:14 ` Re: Size vs size_t or, um, PgSize? Yurii Rashkovskii <[email protected]> 1 sibling, 1 reply; 38+ messages in thread From: Thomas Munro @ 2023-07-03 19:02 UTC (permalink / raw) To: Daniel Gustafsson <[email protected]>; +Cc: Yurii Rashkovskii <[email protected]>; [email protected] On Tue, Jul 4, 2023 at 6:46 AM Daniel Gustafsson <[email protected]> wrote: > > On 3 Jul 2023, at 20:32, Yurii Rashkovskii <[email protected]> wrote: > > If there's a willingness to try this out, I am happy to prepare a patch. > > This has been discussed a number of times in the past, and the conclusion from > last time IIRC was to use size_t for new code and only change the existing > instances when touched for other reasons to avoid churn. One such earlier discussion: https://www.postgresql.org/message-id/flat/CAEepm%3D1eA0vsgA7-2oigKzqg10YeXoPWiS-fCuQRDLwwmgMXag%40m... I personally wouldn't mind if we just flipped to standard types everywhere, but I guess it wouldn't help with your problem with extensions on macOS as you probably also want to target released branches, not just master/17+. But renaming in the back branches doesn't sound like something we'd do... ^ permalink raw reply [nested|flat] 38+ messages in thread
* Re: Size vs size_t or, um, PgSize? 2023-07-03 18:46 Re: Size vs size_t or, um, PgSize? Daniel Gustafsson <[email protected]> 2023-07-03 19:02 ` Re: Size vs size_t or, um, PgSize? Thomas Munro <[email protected]> @ 2023-07-03 19:14 ` Yurii Rashkovskii <[email protected]> 2023-07-03 19:20 ` Re: Size vs size_t or, um, PgSize? Daniel Gustafsson <[email protected]> 0 siblings, 1 reply; 38+ messages in thread From: Yurii Rashkovskii @ 2023-07-03 19:14 UTC (permalink / raw) To: Thomas Munro <[email protected]>; +Cc: Daniel Gustafsson <[email protected]>; [email protected] Hi Thomas, On Mon, Jul 3, 2023 at 12:03 PM Thomas Munro <[email protected]> wrote: > On Tue, Jul 4, 2023 at 6:46 AM Daniel Gustafsson <[email protected]> wrote: > > > On 3 Jul 2023, at 20:32, Yurii Rashkovskii <[email protected]> wrote: > > > If there's a willingness to try this out, I am happy to prepare a > patch. > > > > This has been discussed a number of times in the past, and the > conclusion from > > last time IIRC was to use size_t for new code and only change the > existing > > instances when touched for other reasons to avoid churn. > > One such earlier discussion: > > > https://www.postgresql.org/message-id/flat/CAEepm%3D1eA0vsgA7-2oigKzqg10YeXoPWiS-fCuQRDLwwmgMXag%40m... > > I personally wouldn't mind if we just flipped to standard types > everywhere, but I guess it wouldn't help with your problem with > extensions on macOS as you probably also want to target released > branches, not just master/17+. But renaming in the back branches > doesn't sound like something we'd do... > Of course, it would have been great to have it backported in the ideal world, but it isn't realistic, as you say. That being said, going ahead with the global renaming of Size to size_t will mostly eliminate this clash in, say, five years when old versions will be gone. At least it'll be fixed then. Otherwise, it'll never be fixed at all. To me, having the problem gone in the future beats having the problem forever. -- Y. ^ permalink raw reply [nested|flat] 38+ messages in thread
* Re: Size vs size_t or, um, PgSize? 2023-07-03 18:46 Re: Size vs size_t or, um, PgSize? Daniel Gustafsson <[email protected]> 2023-07-03 19:02 ` Re: Size vs size_t or, um, PgSize? Thomas Munro <[email protected]> 2023-07-03 19:14 ` Re: Size vs size_t or, um, PgSize? Yurii Rashkovskii <[email protected]> @ 2023-07-03 19:20 ` Daniel Gustafsson <[email protected]> 2023-07-03 19:37 ` Re: Size vs size_t or, um, PgSize? Yurii Rashkovskii <[email protected]> 0 siblings, 1 reply; 38+ messages in thread From: Daniel Gustafsson @ 2023-07-03 19:20 UTC (permalink / raw) To: Yurii Rashkovskii <[email protected]>; +Cc: Thomas Munro <[email protected]>; [email protected] > On 3 Jul 2023, at 21:14, Yurii Rashkovskii <[email protected]> wrote: > That being said, going ahead with the global renaming of Size to size_t will mostly eliminate this clash in, say, five years when old versions will be gone. At least it'll be fixed then. Otherwise, it'll never be fixed at all. To me, having the problem gone in the future beats having the problem forever. I would also like all Size instances gone, but the cost during backpatching will likely be very high. There are ~1300 or so of them in the code, and that's a lot of potential conflicts during the coming 5 years of backpatches. -- Daniel Gustafsson ^ permalink raw reply [nested|flat] 38+ messages in thread
* Re: Size vs size_t or, um, PgSize? 2023-07-03 18:46 Re: Size vs size_t or, um, PgSize? Daniel Gustafsson <[email protected]> 2023-07-03 19:02 ` Re: Size vs size_t or, um, PgSize? Thomas Munro <[email protected]> 2023-07-03 19:14 ` Re: Size vs size_t or, um, PgSize? Yurii Rashkovskii <[email protected]> 2023-07-03 19:20 ` Re: Size vs size_t or, um, PgSize? Daniel Gustafsson <[email protected]> @ 2023-07-03 19:37 ` Yurii Rashkovskii <[email protected]> 0 siblings, 0 replies; 38+ messages in thread From: Yurii Rashkovskii @ 2023-07-03 19:37 UTC (permalink / raw) To: Daniel Gustafsson <[email protected]>; +Cc: Thomas Munro <[email protected]>; [email protected] Daniel, On Mon, Jul 3, 2023 at 12:20 PM Daniel Gustafsson <[email protected]> wrote: > > On 3 Jul 2023, at 21:14, Yurii Rashkovskii <[email protected]> wrote: > > > That being said, going ahead with the global renaming of Size to size_t > will mostly eliminate this clash in, say, five years when old versions will > be gone. At least it'll be fixed then. Otherwise, it'll never be fixed at > all. To me, having the problem gone in the future beats having the problem > forever. > > I would also like all Size instances gone, but the cost during backpatching > will likely be very high. There are ~1300 or so of them in the code, and > that's a lot of potential conflicts during the coming 5 years of > backpatches. > > I understand. How about a workaround for extension builders? Something like ``` /* Use this if you run into Size type redefinition */ #ifdef DONT_TYPEDEF_SIZE #define Size size_t #else typedef size_t Size; #endif ``` This way, extension developers can specify DONT_TYPEDEF_SIZE. However, this would have to be backported, but to minimal/no effect if I am not missing anything. Not beautiful, but better than freezing the status quo forever? -- Y. ^ permalink raw reply [nested|flat] 38+ messages in thread
* Re: Size vs size_t or, um, PgSize? 2023-07-03 18:46 Re: Size vs size_t or, um, PgSize? Daniel Gustafsson <[email protected]> @ 2023-07-03 22:20 ` Tom Lane <[email protected]> 1 sibling, 0 replies; 38+ messages in thread From: Tom Lane @ 2023-07-03 22:20 UTC (permalink / raw) To: Daniel Gustafsson <[email protected]>; +Cc: Yurii Rashkovskii <[email protected]>; [email protected] Daniel Gustafsson <[email protected]> writes: > On 3 Jul 2023, at 20:32, Yurii Rashkovskii <[email protected]> wrote: >> I couldn't find any rationale as to why we might want to have this alias and not use size_t. Any insight on this would be appreciated. > This used to be a typedef for unsigned int a very long time ago. I'm fairly sure that Size dates from before we could expect the system headers to provide size_t everywhere. > This has been discussed a number of times in the past, and the conclusion from > last time IIRC was to use size_t for new code and only change the existing > instances when touched for other reasons to avoid churn. Yeah. The code-churn costs of s/Size/size_t/g outweigh the possible gain, at least from our admittedly project-centric point of view. But I don't have a whole lot of sympathy for arguments about "this other code I'd like to also use has its own definition for Size", because you could potentially make that complaint about just about every typedef we've got. If you have conflicts like that, you have to resolve them by methods like #define hacks or factoring your code so it doesn't need to include Postgres headers in the same files that include $other-project-headers. regards, tom lane ^ permalink raw reply [nested|flat] 38+ messages in thread
end of thread, other threads:[~2023-07-03 22:20 UTC | newest] Thread overview: 38+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2017-04-07 18:05 Partitioned tables vs GRANT Joe Conway <[email protected]> 2017-04-07 18:31 ` Keith Fiske <[email protected]> 2017-04-07 18:46 ` Tom Lane <[email protected]> 2017-04-08 00:02 ` Keith Fiske <[email protected]> 2017-04-08 00:41 ` Tom Lane <[email protected]> 2017-04-08 01:18 ` Keith Fiske <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/6] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/5] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 02/10] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/5] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/8] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2019-06-09 20:05 [PATCH 2/5] Move IS NOT NULL checks to bringetbitmap Tomas Vondra <[email protected]> 2023-07-03 18:46 Re: Size vs size_t or, um, PgSize? Daniel Gustafsson <[email protected]> 2023-07-03 19:02 ` Re: Size vs size_t or, um, PgSize? Thomas Munro <[email protected]> 2023-07-03 19:14 ` Re: Size vs size_t or, um, PgSize? Yurii Rashkovskii <[email protected]> 2023-07-03 19:20 ` Re: Size vs size_t or, um, PgSize? Daniel Gustafsson <[email protected]> 2023-07-03 19:37 ` Re: Size vs size_t or, um, PgSize? Yurii Rashkovskii <[email protected]> 2023-07-03 22:20 ` Re: Size vs size_t or, um, PgSize? Tom Lane <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox