Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 86fba28

Browse files
committed
Fix list partition constraints for partition keys of array type.
The old code generated always generated a constraint of the form col = ANY(ARRAY[val1, val2, ...]), but that's invalid when col is an array type. Instead, generate col = val when there's only one value, col = val1 OR col = val2 OR ... when there are multiple values and col is of array type, and the old form when there are multiple values and col is not of an array type. As a side benefit, this makes constraint exclusion able to prune a list partition declared to accept a single Boolean value, which didn't work before. Amit Langote, reviewed by Etsuro Fujita Discussion: http://postgr.es/m/97267195-e235-89d1-a41a-c110198dfce9@lab.ntt.co.jp
1 parent 167a22b commit 86fba28

File tree

4 files changed

+90
-36
lines changed

4 files changed

+90
-36
lines changed

src/backend/catalog/partition.c

Lines changed: 66 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,18 +1249,60 @@ make_partition_op_expr(PartitionKey key, int keynum,
12491249
{
12501250
case PARTITION_STRATEGY_LIST:
12511251
{
1252-
ScalarArrayOpExpr *saopexpr;
1253-
1254-
/* Build leftop = ANY (rightop) */
1255-
saopexpr = makeNode(ScalarArrayOpExpr);
1256-
saopexpr->opno = operoid;
1257-
saopexpr->opfuncid = get_opcode(operoid);
1258-
saopexpr->useOr = true;
1259-
saopexpr->inputcollid = key->partcollation[keynum];
1260-
saopexpr->args = list_make2(arg1, arg2);
1261-
saopexpr->location = -1;
1262-
1263-
result = (Expr *) saopexpr;
1252+
List *elems = (List *) arg2;
1253+
int nelems = list_length(elems);
1254+
1255+
Assert(nelems >= 1);
1256+
Assert(keynum == 0);
1257+
1258+
if (nelems > 1 &&
1259+
!type_is_array(key->parttypid[keynum]))
1260+
{
1261+
ArrayExpr *arrexpr;
1262+
ScalarArrayOpExpr *saopexpr;
1263+
1264+
/* Construct an ArrayExpr for the right-hand inputs */
1265+
arrexpr = makeNode(ArrayExpr);
1266+
arrexpr->array_typeid =
1267+
get_array_type(key->parttypid[keynum]);
1268+
arrexpr->array_collid = key->parttypcoll[keynum];
1269+
arrexpr->element_typeid = key->parttypid[keynum];
1270+
arrexpr->elements = elems;
1271+
arrexpr->multidims = false;
1272+
arrexpr->location = -1;
1273+
1274+
/* Build leftop = ANY (rightop) */
1275+
saopexpr = makeNode(ScalarArrayOpExpr);
1276+
saopexpr->opno = operoid;
1277+
saopexpr->opfuncid = get_opcode(operoid);
1278+
saopexpr->useOr = true;
1279+
saopexpr->inputcollid = key->partcollation[keynum];
1280+
saopexpr->args = list_make2(arg1, arrexpr);
1281+
saopexpr->location = -1;
1282+
1283+
result = (Expr *) saopexpr;
1284+
}
1285+
else
1286+
{
1287+
List *elemops = NIL;
1288+
ListCell *lc;
1289+
1290+
foreach (lc, elems)
1291+
{
1292+
Expr *elem = lfirst(lc),
1293+
*elemop;
1294+
1295+
elemop = make_opclause(operoid,
1296+
BOOLOID,
1297+
false,
1298+
arg1, elem,
1299+
InvalidOid,
1300+
key->partcollation[keynum]);
1301+
elemops = lappend(elemops, elemop);
1302+
}
1303+
1304+
result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops);
1305+
}
12641306
break;
12651307
}
12661308

@@ -1292,11 +1334,10 @@ get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
12921334
{
12931335
List *result;
12941336
Expr *keyCol;
1295-
ArrayExpr *arr;
12961337
Expr *opexpr;
12971338
NullTest *nulltest;
12981339
ListCell *cell;
1299-
List *arrelems = NIL;
1340+
List *elems = NIL;
13001341
bool list_has_null = false;
13011342

13021343
/*
@@ -1324,29 +1365,24 @@ get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
13241365
if (val->constisnull)
13251366
list_has_null = true;
13261367
else
1327-
arrelems = lappend(arrelems, copyObject(val));
1368+
elems = lappend(elems, copyObject(val));
13281369
}
13291370

1330-
if (arrelems)
1371+
if (elems)
13311372
{
1332-
/* Construct an ArrayExpr for the non-null partition values */
1333-
arr = makeNode(ArrayExpr);
1334-
arr->array_typeid = !type_is_array(key->parttypid[0])
1335-
? get_array_type(key->parttypid[0])
1336-
: key->parttypid[0];
1337-
arr->array_collid = key->parttypcoll[0];
1338-
arr->element_typeid = key->parttypid[0];
1339-
arr->elements = arrelems;
1340-
arr->multidims = false;
1341-
arr->location = -1;
1342-
1343-
/* Generate the main expression, i.e., keyCol = ANY (arr) */
1373+
/*
1374+
* Generate the operator expression from the non-null partition
1375+
* values.
1376+
*/
13441377
opexpr = make_partition_op_expr(key, 0, BTEqualStrategyNumber,
1345-
keyCol, (Expr *) arr);
1378+
keyCol, (Expr *) elems);
13461379
}
13471380
else
13481381
{
1349-
/* If there are no partition values, we don't need an = ANY expr */
1382+
/*
1383+
* If there are no partition values, we don't need an operator
1384+
* expression.
1385+
*/
13501386
opexpr = NULL;
13511387
}
13521388

src/test/regress/expected/create_table.out

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10);
655655
a | text | | | | extended | |
656656
b | integer | | not null | 1 | plain | |
657657
Partition of: parted FOR VALUES IN ('b')
658-
Partition constraint: ((a IS NOT NULL) AND (a = ANY (ARRAY['b'::text])))
658+
Partition constraint: ((a IS NOT NULL) AND (a = 'b'::text))
659659
Check constraints:
660660
"check_a" CHECK (length(a) > 0)
661661
"part_b_b_check" CHECK (b >= 0)
@@ -668,7 +668,7 @@ Check constraints:
668668
a | text | | | | extended | |
669669
b | integer | | not null | 0 | plain | |
670670
Partition of: parted FOR VALUES IN ('c')
671-
Partition constraint: ((a IS NOT NULL) AND (a = ANY (ARRAY['c'::text])))
671+
Partition constraint: ((a IS NOT NULL) AND (a = 'c'::text))
672672
Partition key: RANGE (b)
673673
Check constraints:
674674
"check_a" CHECK (length(a) > 0)
@@ -682,7 +682,7 @@ Partitions: part_c_1_10 FOR VALUES FROM (1) TO (10)
682682
a | text | | | | extended | |
683683
b | integer | | not null | 0 | plain | |
684684
Partition of: part_c FOR VALUES FROM (1) TO (10)
685-
Partition constraint: ((a IS NOT NULL) AND (a = ANY (ARRAY['c'::text])) AND (b IS NOT NULL) AND (b >= 1) AND (b < 10))
685+
Partition constraint: ((a IS NOT NULL) AND (a = 'c'::text) AND (b IS NOT NULL) AND (b >= 1) AND (b < 10))
686686
Check constraints:
687687
"check_a" CHECK (length(a) > 0)
688688

@@ -770,3 +770,15 @@ SELECT obj_description('parted_col_comment'::regclass);
770770
Partition key: LIST (a)
771771

772772
DROP TABLE parted_col_comment;
773+
-- list partitioning on array type column
774+
CREATE TABLE arrlp (a int[]) PARTITION BY LIST (a);
775+
CREATE TABLE arrlp12 PARTITION OF arrlp FOR VALUES IN ('{1}', '{2}');
776+
\d+ arrlp12
777+
Table "public.arrlp12"
778+
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
779+
--------+-----------+-----------+----------+---------+----------+--------------+-------------
780+
a | integer[] | | | | extended | |
781+
Partition of: arrlp FOR VALUES IN ('{1}', '{2}')
782+
Partition constraint: ((a IS NOT NULL) AND (((a)::anyarray OPERATOR(pg_catalog.=) '{1}'::integer[]) OR ((a)::anyarray OPERATOR(pg_catalog.=) '{2}'::integer[])))
783+
784+
DROP TABLE arrlp;

src/test/regress/expected/foreign_data.out

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,7 +1847,7 @@ Partitions: pt2_1 FOR VALUES IN (1)
18471847
c2 | text | | | | | extended | |
18481848
c3 | date | | | | | plain | |
18491849
Partition of: pt2 FOR VALUES IN (1)
1850-
Partition constraint: ((c1 IS NOT NULL) AND (c1 = ANY (ARRAY[1])))
1850+
Partition constraint: ((c1 IS NOT NULL) AND (c1 = 1))
18511851
Server: s0
18521852
FDW options: (delimiter ',', quote '"', "be quoted" 'value')
18531853

@@ -1918,7 +1918,7 @@ Partitions: pt2_1 FOR VALUES IN (1)
19181918
c2 | text | | | | | extended | |
19191919
c3 | date | | | | | plain | |
19201920
Partition of: pt2 FOR VALUES IN (1)
1921-
Partition constraint: ((c1 IS NOT NULL) AND (c1 = ANY (ARRAY[1])))
1921+
Partition constraint: ((c1 IS NOT NULL) AND (c1 = 1))
19221922
Server: s0
19231923
FDW options: (delimiter ',', quote '"', "be quoted" 'value')
19241924

@@ -1946,7 +1946,7 @@ Partitions: pt2_1 FOR VALUES IN (1)
19461946
c2 | text | | | | | extended | |
19471947
c3 | date | | not null | | | plain | |
19481948
Partition of: pt2 FOR VALUES IN (1)
1949-
Partition constraint: ((c1 IS NOT NULL) AND (c1 = ANY (ARRAY[1])))
1949+
Partition constraint: ((c1 IS NOT NULL) AND (c1 = 1))
19501950
Check constraints:
19511951
"p21chk" CHECK (c2 <> ''::text)
19521952
Server: s0

src/test/regress/sql/create_table.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,3 +642,9 @@ COMMENT ON COLUMN parted_col_comment.a IS 'Partition key';
642642
SELECT obj_description('parted_col_comment'::regclass);
643643
\d+ parted_col_comment
644644
DROP TABLE parted_col_comment;
645+
646+
-- list partitioning on array type column
647+
CREATE TABLE arrlp (a int[]) PARTITION BY LIST (a);
648+
CREATE TABLE arrlp12 PARTITION OF arrlp FOR VALUES IN ('{1}', '{2}');
649+
\d+ arrlp12
650+
DROP TABLE arrlp;

0 commit comments

Comments
 (0)