Columnar: separate plan and runtime quals. (#5261)

* Columnar: separate plain and exec quals.

Make a clear separation between plain quals, which contain constants
or extern params; and exec quals, which contain exec params and can't
be evaluated until a rescan.

Fixes #5258.

* more vanilla tests

Co-authored-by: Onur Tirtir <onurcantirtir@gmail.com>
pull/5276/head
jeff-davis 2021-09-13 10:54:53 -07:00 committed by GitHub
parent d48ceee238
commit 6e8b19984e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 460 additions and 29 deletions

View File

@ -1100,6 +1100,29 @@ ParameterizationAsString(PlannerInfo *root, Relids paramRelids, StringInfo buf)
}
/*
* ContainsExecParams tests whether the node contains any exec params. The
* signature accepts an extra argument for use with expression_tree_walker.
*/
static bool
ContainsExecParams(Node *node, void *notUsed)
{
if (node == NULL)
{
return false;
}
else if (IsA(node, Param))
{
Param *param = castNode(Param, node);
if (param->paramkind == PARAM_EXEC)
{
return true;
}
}
return expression_tree_walker(node, ContainsExecParams, NULL);
}
/*
* Create and add a path with the given parameterization paramRelids.
*
@ -1133,11 +1156,8 @@ AddColumnarScanPath(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte,
path->param_info = get_baserel_parampathinfo(root, rel, paramRelids);
/*
* Now, baserestrictinfo contains the clauses referencing only this rel,
* and ppi_clauses (if present) represents the join clauses that reference
* this rel and rels contained in paramRelids (after accounting for
* ECs). Combine the two lists of clauses, extracting the actual clause
* from the rinfo, and filtering out pseudoconstants and SAOPs.
* Usable clauses for this parameterization exist in baserestrictinfo and
* ppi_clauses.
*/
List *allClauses = copyObject(rel->baserestrictinfo);
if (path->param_info != NULL)
@ -1145,20 +1165,47 @@ AddColumnarScanPath(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte,
allClauses = list_concat(allClauses, path->param_info->ppi_clauses);
}
/*
* This is the set of clauses that can be pushed down for this
* parameterization (with the given paramRelids), and will be used to
* construct the CustomScan plan.
*/
List *pushdownClauses = FilterPushdownClauses(root, rel, allClauses);
allClauses = FilterPushdownClauses(root, rel, allClauses);
/*
* Plain clauses may contain extern params, but not exec params, and can
* be evaluated at init time or rescan time. Track them in another list
* that is a subset of allClauses.
*
* Note: although typically baserestrictinfo contains plain clauses,
* that's not always true. It can also contain a qual referencing a Var at
* a higher query level, which can be turned into an exec param, and
* therefore it won't be a plain clause.
*/
List *plainClauses = NIL;
ListCell *lc;
foreach(lc, allClauses)
{
RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
if (bms_is_subset(rinfo->required_relids, rel->relids) &&
!ContainsExecParams((Node *) rinfo->clause, NULL))
{
plainClauses = lappend(plainClauses, rinfo);
}
}
/*
* We can't make our own CustomPath structure, so we need to put
* everything in the custom_private list. To keep the two lists separate,
* we make them sublists in a 2-element list.
*/
if (EnableColumnarQualPushdown)
{
cpath->custom_private = pushdownClauses;
cpath->custom_private = list_make2(copyObject(plainClauses),
copyObject(allClauses));
}
else
{
cpath->custom_private = list_make2(NIL, NIL);
}
int numberOfColumnsRead = bms_num_members(rte->selectedCols);
int numberOfClausesPushed = list_length(cpath->custom_private);
int numberOfClausesPushed = list_length(allClauses);
CostColumnarScan(root, rel, rte->relid, cpath, numberOfColumnsRead,
numberOfClausesPushed);
@ -1188,8 +1235,9 @@ CostColumnarScan(PlannerInfo *root, RelOptInfo *rel, Oid relationId,
{
Path *path = &cpath->path;
List *allClauses = lsecond(cpath->custom_private);
Selectivity clauseSel = clauselist_selectivity(
root, cpath->custom_private, rel->relid, JOIN_INNER, NULL);
root, allClauses, rel->relid, JOIN_INNER, NULL);
/*
* We already filtered out clauses where the overall selectivity would be
@ -1297,18 +1345,28 @@ ColumnarScanPath_PlanCustomPath(PlannerInfo *root,
if (EnableColumnarQualPushdown)
{
/*
* List of pushed-down clauses. The Vars referencing other relations
* will be changed into exec Params by create_customscan_plan().
* Lists of pushed-down clauses. The Vars in custom_exprs referencing
* other relations will be changed into exec Params by
* create_customscan_plan().
*
* XXX: this just means what will be pushed into the columnar reader
* code; some of these may not be usable. We should fix this by
* passing down something more like ScanKeys, where we've already
* verified that the operators match the btree opclass of the chunk
* predicates.
* Like CustomPath->custom_private, keep a list of plain clauses
* separate from the list of all clauses by making them sublists of a
* 2-element list.
*
* XXX: custom_exprs are the quals that will be pushed into the
* columnar reader code; some of these may not be usable. We should
* fix this by processing the quals more completely and using
* ScanKeys.
*/
cscan->custom_exprs = copyObject(
extract_actual_clauses(best_path->custom_private,
false /* no pseudoconstants */));
List *plainClauses = extract_actual_clauses(
linitial(best_path->custom_private), false /* no pseudoconstants */);
List *allClauses = extract_actual_clauses(
lsecond(best_path->custom_private), false /* no pseudoconstants */);
cscan->custom_exprs = copyObject(list_make2(plainClauses, allClauses));
}
else
{
cscan->custom_exprs = list_make2(NIL, NIL);
}
cscan->scan.plan.qual = extract_actual_clauses(
@ -1447,10 +1505,10 @@ ColumnarScan_BeginCustomScan(CustomScanState *cscanstate, EState *estate, int ef
columnarScanState->css_RuntimeContext = cscanstate->ss.ps.ps_ExprContext;
cscanstate->ss.ps.ps_ExprContext = stdecontext;
/* XXX: separate into runtime clauses and normal clauses */
ResetExprContext(columnarScanState->css_RuntimeContext);
List *plainClauses = linitial(cscan->custom_exprs);
columnarScanState->qual = (List *) EvalParamsMutator(
(Node *) cscan->custom_exprs, columnarScanState->css_RuntimeContext);
(Node *) plainClauses, columnarScanState->css_RuntimeContext);
/* scan slot is already initialized */
}
@ -1604,8 +1662,9 @@ ColumnarScan_ReScanCustomScan(CustomScanState *node)
ColumnarScanState *columnarScanState = (ColumnarScanState *) node;
ResetExprContext(columnarScanState->css_RuntimeContext);
List *allClauses = lsecond(cscan->custom_exprs);
columnarScanState->qual = (List *) EvalParamsMutator(
(Node *) cscan->custom_exprs, columnarScanState->css_RuntimeContext);
(Node *) allClauses, columnarScanState->css_RuntimeContext);
TableScanDesc scanDesc = node->ss.ss_currentScanDesc;
@ -1635,7 +1694,7 @@ ColumnarScan_ExplainCustomScan(CustomScanState *node, List *ancestors,
projectedColumnsStr, es);
CustomScan *cscan = castNode(CustomScan, node->ss.ps.plan);
List *chunkGroupFilter = cscan->custom_exprs;
List *chunkGroupFilter = lsecond(cscan->custom_exprs);
if (chunkGroupFilter != NULL)
{
const char *pushdownClausesStr = ColumnarPushdownClausesStr(

View File

@ -746,3 +746,76 @@ select filtered_row_count('execute foo(3)');
(1 row)
drop table columnar_prepared_stmt;
--
-- https://github.com/citusdata/citus/issues/5258
--
set default_table_access_method to columnar;
CREATE TABLE atest1 ( a int, b text );
CREATE TABLE atest2 (col1 varchar(10), col2 boolean);
INSERT INTO atest1 VALUES (1, 'one');
SELECT * FROM atest1; -- ok
a | b
---------------------------------------------------------------------
1 | one
(1 row)
SELECT * FROM atest2; -- ok
col1 | col2
---------------------------------------------------------------------
(0 rows)
INSERT INTO atest1 VALUES (2, 'two'); -- ok
INSERT INTO atest1 SELECT 1, b FROM atest1; -- ok
SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) );
col1 | col2
---------------------------------------------------------------------
(0 rows)
CREATE TABLE t1 (name TEXT, n INTEGER);
CREATE TABLE t2 (name TEXT, n INTEGER);
CREATE TABLE t3 (name TEXT, n INTEGER);
INSERT INTO t1 VALUES ( 'bb', 11 );
INSERT INTO t2 VALUES ( 'bb', 12 );
INSERT INTO t2 VALUES ( 'cc', 22 );
INSERT INTO t2 VALUES ( 'ee', 42 );
INSERT INTO t3 VALUES ( 'bb', 13 );
INSERT INTO t3 VALUES ( 'cc', 23 );
INSERT INTO t3 VALUES ( 'dd', 33 );
SELECT * FROM
(SELECT name, n as s1_n, 1 as s1_1 FROM t1) as s1
NATURAL INNER JOIN
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
NATURAL INNER JOIN
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
name | s1_n | s1_1 | s2_n | s2_2 | s3_n | s3_2
---------------------------------------------------------------------
bb | 11 | 1 | 12 | 2 | 13 | 3
(1 row)
CREATE TABLE numrange_test (nr NUMRANGE);
INSERT INTO numrange_test VALUES('[,)');
INSERT INTO numrange_test VALUES('[3,]');
INSERT INTO numrange_test VALUES('[, 5)');
INSERT INTO numrange_test VALUES(numrange(1.1, 2.2));
INSERT INTO numrange_test VALUES('empty');
INSERT INTO numrange_test VALUES(numrange(1.7, 1.7, '[]'));
create table numrange_test2(nr numrange);
INSERT INTO numrange_test2 VALUES('[, 5)');
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2));
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2));
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2,'()'));
INSERT INTO numrange_test2 VALUES('empty');
set enable_nestloop=t;
set enable_hashjoin=f;
set enable_mergejoin=f;
select * from numrange_test natural join numrange_test2 order by nr;
nr
---------------------------------------------------------------------
empty
(,5)
[1.1,2.2)
[1.1,2.2)
(4 rows)
DROP TABLE atest1, atest2, t1, t2, t3, numrange_test, numrange_test2;
set default_table_access_method to default;

View File

@ -746,3 +746,76 @@ select filtered_row_count('execute foo(3)');
(1 row)
drop table columnar_prepared_stmt;
--
-- https://github.com/citusdata/citus/issues/5258
--
set default_table_access_method to columnar;
CREATE TABLE atest1 ( a int, b text );
CREATE TABLE atest2 (col1 varchar(10), col2 boolean);
INSERT INTO atest1 VALUES (1, 'one');
SELECT * FROM atest1; -- ok
a | b
---------------------------------------------------------------------
1 | one
(1 row)
SELECT * FROM atest2; -- ok
col1 | col2
---------------------------------------------------------------------
(0 rows)
INSERT INTO atest1 VALUES (2, 'two'); -- ok
INSERT INTO atest1 SELECT 1, b FROM atest1; -- ok
SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) );
col1 | col2
---------------------------------------------------------------------
(0 rows)
CREATE TABLE t1 (name TEXT, n INTEGER);
CREATE TABLE t2 (name TEXT, n INTEGER);
CREATE TABLE t3 (name TEXT, n INTEGER);
INSERT INTO t1 VALUES ( 'bb', 11 );
INSERT INTO t2 VALUES ( 'bb', 12 );
INSERT INTO t2 VALUES ( 'cc', 22 );
INSERT INTO t2 VALUES ( 'ee', 42 );
INSERT INTO t3 VALUES ( 'bb', 13 );
INSERT INTO t3 VALUES ( 'cc', 23 );
INSERT INTO t3 VALUES ( 'dd', 33 );
SELECT * FROM
(SELECT name, n as s1_n, 1 as s1_1 FROM t1) as s1
NATURAL INNER JOIN
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
NATURAL INNER JOIN
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
name | s1_n | s1_1 | s2_n | s2_2 | s3_n | s3_2
---------------------------------------------------------------------
bb | 11 | 1 | 12 | 2 | 13 | 3
(1 row)
CREATE TABLE numrange_test (nr NUMRANGE);
INSERT INTO numrange_test VALUES('[,)');
INSERT INTO numrange_test VALUES('[3,]');
INSERT INTO numrange_test VALUES('[, 5)');
INSERT INTO numrange_test VALUES(numrange(1.1, 2.2));
INSERT INTO numrange_test VALUES('empty');
INSERT INTO numrange_test VALUES(numrange(1.7, 1.7, '[]'));
create table numrange_test2(nr numrange);
INSERT INTO numrange_test2 VALUES('[, 5)');
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2));
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2));
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2,'()'));
INSERT INTO numrange_test2 VALUES('empty');
set enable_nestloop=t;
set enable_hashjoin=f;
set enable_mergejoin=f;
select * from numrange_test natural join numrange_test2 order by nr;
nr
---------------------------------------------------------------------
empty
(,5)
[1.1,2.2)
[1.1,2.2)
(4 rows)
DROP TABLE atest1, atest2, t1, t2, t3, numrange_test, numrange_test2;
set default_table_access_method to default;

View File

@ -187,3 +187,52 @@ UNION
SET client_min_messages TO WARNING;
DROP SCHEMA columnar_join CASCADE;
--
-- https://github.com/citusdata/citus/issues/5258
--
set default_table_access_method to columnar;
CREATE TABLE atest1 ( a int, b text );
CREATE TABLE atest2 (col1 varchar(10), col2 boolean);
INSERT INTO atest1 VALUES (1, 'one');
SELECT * FROM atest1; -- ok
a | b
---------------------------------------------------------------------
1 | one
(1 row)
SELECT * FROM atest2; -- ok
col1 | col2
---------------------------------------------------------------------
(0 rows)
INSERT INTO atest1 VALUES (2, 'two'); -- ok
INSERT INTO atest1 SELECT 1, b FROM atest1; -- ok
SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) );
col1 | col2
---------------------------------------------------------------------
(0 rows)
DROP TABLE atest1;
DROP TABLE atest2;
set default_table_access_method to default;
create temp table t1 (f1 numeric(14,0), f2 varchar(30)) USING columnar;
select * from
(select distinct f1, f2, (select f2 from t1 x where x.f1 = up.f1) as fs
from t1 up) ss
group by f1,f2,fs;
f1 | f2 | fs
---------------------------------------------------------------------
(0 rows)
drop table t1;
CREATE TABLE tbl1(c0 int4range) USING COLUMNAR;
CREATE TABLE tbl2(c0 int4range);
INSERT INTO tbl1(c0) VALUES('[0,1]'::int4range);
INSERT INTO tbl1(c0) VALUES('[0,1]'::int4range);
SELECT tbl1.c0 FROM tbl1 JOIN tbl2 ON tbl1.c0=tbl2.c0 WHERE tbl2.c0<=tbl2.c0 ISNULL;
c0
---------------------------------------------------------------------
(0 rows)
DROP TABLE tbl1;
DROP TABLE tbl2;

View File

@ -713,5 +713,58 @@ SELECT * FROM (
SELECT * FROM search_graph ORDER BY seq
) as foo;
ERROR: recursive CTEs are not supported in distributed queries
--
-- https://github.com/citusdata/citus/issues/5258
--
CREATE TABLE nummultirange_test (nmr NUMMULTIRANGE) USING columnar;
INSERT INTO nummultirange_test VALUES('{}');
INSERT INTO nummultirange_test VALUES('{[,)}');
INSERT INTO nummultirange_test VALUES('{[3,]}');
INSERT INTO nummultirange_test VALUES('{[, 5)}');
INSERT INTO nummultirange_test VALUES(nummultirange());
INSERT INTO nummultirange_test VALUES(nummultirange(variadic '{}'::numrange[]));
INSERT INTO nummultirange_test VALUES(nummultirange(numrange(1.1, 2.2)));
INSERT INTO nummultirange_test VALUES('{empty}');
INSERT INTO nummultirange_test VALUES(nummultirange(numrange(1.7, 1.7, '[]'), numrange(1.7, 1.9)));
INSERT INTO nummultirange_test VALUES(nummultirange(numrange(1.7, 1.7, '[]'), numrange(1.9, 2.1)));
create table nummultirange_test2(nmr nummultirange) USING columnar;
INSERT INTO nummultirange_test2 VALUES('{[, 5)}');
INSERT INTO nummultirange_test2 VALUES(nummultirange(numrange(1.1, 2.2)));
INSERT INTO nummultirange_test2 VALUES(nummultirange(numrange(1.1, 2.2)));
INSERT INTO nummultirange_test2 VALUES(nummultirange(numrange(1.1, 2.2,'()')));
INSERT INTO nummultirange_test2 VALUES('{}');
select * from nummultirange_test2 where nmr = '{}';
nmr
---------------------------------------------------------------------
{}
(1 row)
select * from nummultirange_test2 where nmr = nummultirange(numrange(1.1, 2.2));
nmr
---------------------------------------------------------------------
{[1.1,2.2)}
{[1.1,2.2)}
(2 rows)
select * from nummultirange_test2 where nmr = nummultirange(numrange(1.1, 2.3));
nmr
---------------------------------------------------------------------
(0 rows)
set enable_nestloop=t;
set enable_hashjoin=f;
set enable_mergejoin=f;
select * from nummultirange_test natural join nummultirange_test2 order by nmr;
nmr
---------------------------------------------------------------------
{}
{}
{}
{}
{(,5)}
{[1.1,2.2)}
{[1.1,2.2)}
(7 rows)
set client_min_messages to error;
drop schema pg14 cascade;

View File

@ -316,3 +316,61 @@ select filtered_row_count('execute foo(3)');
select filtered_row_count('execute foo(3)');
select filtered_row_count('execute foo(3)');
drop table columnar_prepared_stmt;
--
-- https://github.com/citusdata/citus/issues/5258
--
set default_table_access_method to columnar;
CREATE TABLE atest1 ( a int, b text );
CREATE TABLE atest2 (col1 varchar(10), col2 boolean);
INSERT INTO atest1 VALUES (1, 'one');
SELECT * FROM atest1; -- ok
SELECT * FROM atest2; -- ok
INSERT INTO atest1 VALUES (2, 'two'); -- ok
INSERT INTO atest1 SELECT 1, b FROM atest1; -- ok
SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) );
CREATE TABLE t1 (name TEXT, n INTEGER);
CREATE TABLE t2 (name TEXT, n INTEGER);
CREATE TABLE t3 (name TEXT, n INTEGER);
INSERT INTO t1 VALUES ( 'bb', 11 );
INSERT INTO t2 VALUES ( 'bb', 12 );
INSERT INTO t2 VALUES ( 'cc', 22 );
INSERT INTO t2 VALUES ( 'ee', 42 );
INSERT INTO t3 VALUES ( 'bb', 13 );
INSERT INTO t3 VALUES ( 'cc', 23 );
INSERT INTO t3 VALUES ( 'dd', 33 );
SELECT * FROM
(SELECT name, n as s1_n, 1 as s1_1 FROM t1) as s1
NATURAL INNER JOIN
(SELECT name, n as s2_n, 2 as s2_2 FROM t2) as s2
NATURAL INNER JOIN
(SELECT name, n as s3_n, 3 as s3_2 FROM t3) s3;
CREATE TABLE numrange_test (nr NUMRANGE);
INSERT INTO numrange_test VALUES('[,)');
INSERT INTO numrange_test VALUES('[3,]');
INSERT INTO numrange_test VALUES('[, 5)');
INSERT INTO numrange_test VALUES(numrange(1.1, 2.2));
INSERT INTO numrange_test VALUES('empty');
INSERT INTO numrange_test VALUES(numrange(1.7, 1.7, '[]'));
create table numrange_test2(nr numrange);
INSERT INTO numrange_test2 VALUES('[, 5)');
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2));
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2));
INSERT INTO numrange_test2 VALUES(numrange(1.1, 2.2,'()'));
INSERT INTO numrange_test2 VALUES('empty');
set enable_nestloop=t;
set enable_hashjoin=f;
set enable_mergejoin=f;
select * from numrange_test natural join numrange_test2 order by nr;
DROP TABLE atest1, atest2, t1, t2, t3, numrange_test, numrange_test2;
set default_table_access_method to default;

View File

@ -91,3 +91,40 @@ UNION
SET client_min_messages TO WARNING;
DROP SCHEMA columnar_join CASCADE;
--
-- https://github.com/citusdata/citus/issues/5258
--
set default_table_access_method to columnar;
CREATE TABLE atest1 ( a int, b text );
CREATE TABLE atest2 (col1 varchar(10), col2 boolean);
INSERT INTO atest1 VALUES (1, 'one');
SELECT * FROM atest1; -- ok
SELECT * FROM atest2; -- ok
INSERT INTO atest1 VALUES (2, 'two'); -- ok
INSERT INTO atest1 SELECT 1, b FROM atest1; -- ok
SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) );
DROP TABLE atest1;
DROP TABLE atest2;
set default_table_access_method to default;
create temp table t1 (f1 numeric(14,0), f2 varchar(30)) USING columnar;
select * from
(select distinct f1, f2, (select f2 from t1 x where x.f1 = up.f1) as fs
from t1 up) ss
group by f1,f2,fs;
drop table t1;
CREATE TABLE tbl1(c0 int4range) USING COLUMNAR;
CREATE TABLE tbl2(c0 int4range);
INSERT INTO tbl1(c0) VALUES('[0,1]'::int4range);
INSERT INTO tbl1(c0) VALUES('[0,1]'::int4range);
SELECT tbl1.c0 FROM tbl1 JOIN tbl2 ON tbl1.c0=tbl2.c0 WHERE tbl2.c0<=tbl2.c0 ISNULL;
DROP TABLE tbl1;
DROP TABLE tbl2;

View File

@ -272,7 +272,6 @@ REINDEX TABLE dist_part_table;
-- but we support REINDEXing partitions
REINDEX TABLE dist_part_table_1;
-- test if we error with CTEs with search clauses
CREATE TABLE graph0(f INT, t INT, label TEXT);
SELECT create_distributed_table('graph0', 'f');
@ -337,5 +336,35 @@ SELECT * FROM (
SELECT * FROM search_graph ORDER BY seq
) as foo;
--
-- https://github.com/citusdata/citus/issues/5258
--
CREATE TABLE nummultirange_test (nmr NUMMULTIRANGE) USING columnar;
INSERT INTO nummultirange_test VALUES('{}');
INSERT INTO nummultirange_test VALUES('{[,)}');
INSERT INTO nummultirange_test VALUES('{[3,]}');
INSERT INTO nummultirange_test VALUES('{[, 5)}');
INSERT INTO nummultirange_test VALUES(nummultirange());
INSERT INTO nummultirange_test VALUES(nummultirange(variadic '{}'::numrange[]));
INSERT INTO nummultirange_test VALUES(nummultirange(numrange(1.1, 2.2)));
INSERT INTO nummultirange_test VALUES('{empty}');
INSERT INTO nummultirange_test VALUES(nummultirange(numrange(1.7, 1.7, '[]'), numrange(1.7, 1.9)));
INSERT INTO nummultirange_test VALUES(nummultirange(numrange(1.7, 1.7, '[]'), numrange(1.9, 2.1)));
create table nummultirange_test2(nmr nummultirange) USING columnar;
INSERT INTO nummultirange_test2 VALUES('{[, 5)}');
INSERT INTO nummultirange_test2 VALUES(nummultirange(numrange(1.1, 2.2)));
INSERT INTO nummultirange_test2 VALUES(nummultirange(numrange(1.1, 2.2)));
INSERT INTO nummultirange_test2 VALUES(nummultirange(numrange(1.1, 2.2,'()')));
INSERT INTO nummultirange_test2 VALUES('{}');
select * from nummultirange_test2 where nmr = '{}';
select * from nummultirange_test2 where nmr = nummultirange(numrange(1.1, 2.2));
select * from nummultirange_test2 where nmr = nummultirange(numrange(1.1, 2.3));
set enable_nestloop=t;
set enable_hashjoin=f;
set enable_mergejoin=f;
select * from nummultirange_test natural join nummultirange_test2 order by nmr;
set client_min_messages to error;
drop schema pg14 cascade;