@@ -1296,23 +1296,22 @@ make_partition_op_expr(PartitionKey key, int keynum,
1296
1296
/*
1297
1297
* get_qual_for_list
1298
1298
*
1299
- * Returns a list of expressions to use as a list partition's constraint.
1299
+ * Returns an implicit-AND list of expressions to use as a list partition's
1300
+ * constraint, given the partition key and bound structures.
1300
1301
*/
1301
1302
static List *
1302
1303
get_qual_for_list (PartitionKey key , PartitionBoundSpec * spec )
1303
1304
{
1304
1305
List * result ;
1306
+ Expr * keyCol ;
1305
1307
ArrayExpr * arr ;
1306
1308
Expr * opexpr ;
1307
- ListCell * cell ,
1308
- * prev ,
1309
- * next ;
1310
- Expr * keyCol ;
1309
+ NullTest * nulltest ;
1310
+ ListCell * cell ;
1311
+ List * arrelems = NIL ;
1311
1312
bool list_has_null = false;
1312
- NullTest * nulltest1 = NULL ,
1313
- * nulltest2 = NULL ;
1314
1313
1315
- /* Left operand is either a simple Var or arbitrary expression */
1314
+ /* Construct Var or expression representing the partition column */
1316
1315
if (key -> partattrs [0 ] != 0 )
1317
1316
keyCol = (Expr * ) makeVar (1 ,
1318
1317
key -> partattrs [0 ],
@@ -1323,74 +1322,62 @@ get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
1323
1322
else
1324
1323
keyCol = (Expr * ) copyObject (linitial (key -> partexprs ));
1325
1324
1326
- /*
1327
- * We must remove any NULL value in the list; we handle it separately
1328
- * below.
1329
- */
1330
- prev = NULL ;
1331
- for (cell = list_head (spec -> listdatums ); cell ; cell = next )
1325
+ /* Create list of Consts for the allowed values, excluding any nulls */
1326
+ foreach (cell , spec -> listdatums )
1332
1327
{
1333
1328
Const * val = castNode (Const , lfirst (cell ));
1334
1329
1335
- next = lnext (cell );
1336
-
1337
1330
if (val -> constisnull )
1338
- {
1339
1331
list_has_null = true;
1340
- spec -> listdatums = list_delete_cell (spec -> listdatums ,
1341
- cell , prev );
1342
- }
1343
1332
else
1344
- prev = cell ;
1333
+ arrelems = lappend ( arrelems , copyObject ( val )) ;
1345
1334
}
1346
1335
1347
- if (!list_has_null )
1348
- {
1349
- /*
1350
- * Gin up a col IS NOT NULL test that will be AND'd with other
1351
- * expressions
1352
- */
1353
- nulltest1 = makeNode (NullTest );
1354
- nulltest1 -> arg = keyCol ;
1355
- nulltest1 -> nulltesttype = IS_NOT_NULL ;
1356
- nulltest1 -> argisrow = false;
1357
- nulltest1 -> location = -1 ;
1358
- }
1359
- else
1360
- {
1361
- /*
1362
- * Gin up a col IS NULL test that will be OR'd with other expressions
1363
- */
1364
- nulltest2 = makeNode (NullTest );
1365
- nulltest2 -> arg = keyCol ;
1366
- nulltest2 -> nulltesttype = IS_NULL ;
1367
- nulltest2 -> argisrow = false;
1368
- nulltest2 -> location = -1 ;
1369
- }
1370
-
1371
- /* Right operand is an ArrayExpr containing this partition's values */
1336
+ /* Construct an ArrayExpr for the non-null partition values */
1372
1337
arr = makeNode (ArrayExpr );
1373
1338
arr -> array_typeid = !type_is_array (key -> parttypid [0 ])
1374
1339
? get_array_type (key -> parttypid [0 ])
1375
1340
: key -> parttypid [0 ];
1376
1341
arr -> array_collid = key -> parttypcoll [0 ];
1377
1342
arr -> element_typeid = key -> parttypid [0 ];
1378
- arr -> elements = spec -> listdatums ;
1343
+ arr -> elements = arrelems ;
1379
1344
arr -> multidims = false;
1380
1345
arr -> location = -1 ;
1381
1346
1382
1347
/* Generate the main expression, i.e., keyCol = ANY (arr) */
1383
1348
opexpr = make_partition_op_expr (key , 0 , BTEqualStrategyNumber ,
1384
1349
keyCol , (Expr * ) arr );
1385
1350
1386
- if (nulltest1 )
1387
- result = list_make2 (nulltest1 , opexpr );
1351
+ if (!list_has_null )
1352
+ {
1353
+ /*
1354
+ * Gin up a "col IS NOT NULL" test that will be AND'd with the main
1355
+ * expression. This might seem redundant, but the partition routing
1356
+ * machinery needs it.
1357
+ */
1358
+ nulltest = makeNode (NullTest );
1359
+ nulltest -> arg = keyCol ;
1360
+ nulltest -> nulltesttype = IS_NOT_NULL ;
1361
+ nulltest -> argisrow = false;
1362
+ nulltest -> location = -1 ;
1363
+
1364
+ result = list_make2 (nulltest , opexpr );
1365
+ }
1388
1366
else
1389
1367
{
1368
+ /*
1369
+ * Gin up a "col IS NULL" test that will be OR'd with the main
1370
+ * expression.
1371
+ */
1390
1372
Expr * or ;
1391
1373
1392
- Assert (nulltest2 != NULL );
1393
- or = makeBoolExpr (OR_EXPR , list_make2 (nulltest2 , opexpr ), -1 );
1374
+ nulltest = makeNode (NullTest );
1375
+ nulltest -> arg = keyCol ;
1376
+ nulltest -> nulltesttype = IS_NULL ;
1377
+ nulltest -> argisrow = false;
1378
+ nulltest -> location = -1 ;
1379
+
1380
+ or = makeBoolExpr (OR_EXPR , list_make2 (nulltest , opexpr ), -1 );
1394
1381
result = list_make1 (or );
1395
1382
}
1396
1383
@@ -1401,8 +1388,16 @@ get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
1401
1388
* get_range_key_properties
1402
1389
* Returns range partition key information for a given column
1403
1390
*
1404
- * On return, *partexprs_item points to the cell containing the next
1405
- * expression in the key->partexprs list, or NULL.
1391
+ * This is a subroutine for get_qual_for_range, and its API is pretty
1392
+ * specialized to that caller.
1393
+ *
1394
+ * Constructs an Expr for the key column (returned in *keyCol) and Consts
1395
+ * for the lower and upper range limits (returned in *lower_val and
1396
+ * *upper_val). For UNBOUNDED limits, NULL is returned instead of a Const.
1397
+ * All of these structures are freshly palloc'd.
1398
+ *
1399
+ * *partexprs_item points to the cell containing the next expression in
1400
+ * the key->partexprs list, or NULL. It may be advanced upon return.
1406
1401
*/
1407
1402
static void
1408
1403
get_range_key_properties (PartitionKey key , int keynum ,
@@ -1412,7 +1407,7 @@ get_range_key_properties(PartitionKey key, int keynum,
1412
1407
Expr * * keyCol ,
1413
1408
Const * * lower_val , Const * * upper_val )
1414
1409
{
1415
- /* Partition key expression for this column */
1410
+ /* Get partition key expression for this column */
1416
1411
if (key -> partattrs [keynum ] != 0 )
1417
1412
{
1418
1413
* keyCol = (Expr * ) makeVar (1 ,
@@ -1424,27 +1419,29 @@ get_range_key_properties(PartitionKey key, int keynum,
1424
1419
}
1425
1420
else
1426
1421
{
1422
+ if (* partexprs_item == NULL )
1423
+ elog (ERROR , "wrong number of partition key expressions" );
1427
1424
* keyCol = copyObject (lfirst (* partexprs_item ));
1428
1425
* partexprs_item = lnext (* partexprs_item );
1429
1426
}
1430
1427
1428
+ /* Get appropriate Const nodes for the bounds */
1431
1429
if (!ldatum -> infinite )
1432
- * lower_val = castNode (Const , ldatum -> value );
1430
+ * lower_val = castNode (Const , copyObject ( ldatum -> value ) );
1433
1431
else
1434
1432
* lower_val = NULL ;
1435
1433
1436
1434
if (!udatum -> infinite )
1437
- * upper_val = castNode (Const , udatum -> value );
1435
+ * upper_val = castNode (Const , copyObject ( udatum -> value ) );
1438
1436
else
1439
1437
* upper_val = NULL ;
1440
1438
}
1441
1439
1442
1440
/*
1443
1441
* get_qual_for_range
1444
1442
*
1445
- * Get a list of expressions to use as a range partition's constraint.
1446
- * If there are multiple expressions, they are to be considered implicitly
1447
- * ANDed.
1443
+ * Returns an implicit-AND list of expressions to use as a range partition's
1444
+ * constraint, given the partition key and bound structures.
1448
1445
*
1449
1446
* For a multi-column range partition key, say (a, b, c), with (al, bl, cl)
1450
1447
* as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
@@ -1480,9 +1477,8 @@ get_range_key_properties(PartitionKey key, int keynum,
1480
1477
* does not really have a constraint, except the IS NOT NULL constraint for
1481
1478
* partition keys.
1482
1479
*
1483
- * If we end up with an empty result list, we append return a single-member
1484
- * list containing a constant-true expression in that case, because callers
1485
- * expect a non-empty list.
1480
+ * If we end up with an empty result list, we return a single-member list
1481
+ * containing a constant TRUE, because callers expect a non-empty list.
1486
1482
*/
1487
1483
static List *
1488
1484
get_qual_for_range (PartitionKey key , PartitionBoundSpec * spec )
@@ -1573,7 +1569,7 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
1573
1569
/*
1574
1570
* Since get_range_key_properties() modifies partexprs_item, and we
1575
1571
* might need to start over from the previous expression in the later
1576
- * part of this functiom , save away the current value.
1572
+ * part of this function , save away the current value.
1577
1573
*/
1578
1574
partexprs_item_saved = partexprs_item ;
1579
1575
@@ -1638,6 +1634,7 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
1638
1634
List * lower_or_arm_args = NIL ,
1639
1635
* upper_or_arm_args = NIL ;
1640
1636
1637
+ /* Restart scan of columns from the i'th one */
1641
1638
j = i ;
1642
1639
partexprs_item = partexprs_item_saved ;
1643
1640
@@ -1702,7 +1699,6 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
1702
1699
strategy ,
1703
1700
keyCol ,
1704
1701
(Expr * ) upper_val ));
1705
-
1706
1702
}
1707
1703
1708
1704
/*
@@ -1759,7 +1755,7 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
1759
1755
: linitial (upper_or_arms ));
1760
1756
1761
1757
/* As noted above, caller expects the list to be non-empty. */
1762
- if (result == NULL )
1758
+ if (result == NIL )
1763
1759
result = list_make1 (makeBoolConst (true, false));
1764
1760
1765
1761
return result ;
0 commit comments