Skip to content

Commit a682742

Browse files
committed
half open ranges
1 parent fc9d807 commit a682742

File tree

9 files changed

+126
-67
lines changed

9 files changed

+126
-67
lines changed

expected/pathman_calamity.out

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -238,22 +238,6 @@ EXPLAIN (COSTS OFF) SELECT * FROM calamity.part_ok; /* check that pathman is ena
238238
-> Seq Scan on part_ok_3
239239
(5 rows)
240240

241-
ALTER TABLE calamity.wrong_partition
242-
ADD CONSTRAINT pathman_wrong_partition_1_check
243-
CHECK (val < 10); /* wrong constraint */
244-
SELECT add_to_pathman_config('calamity.part_test', 'val', '10');
245-
ERROR: Wrong constraint format for RANGE partition "wrong_partition"
246-
EXPLAIN (COSTS OFF) SELECT * FROM calamity.part_ok; /* check that pathman is enabled */
247-
QUERY PLAN
248-
-----------------------------
249-
Append
250-
-> Seq Scan on part_ok_0
251-
-> Seq Scan on part_ok_1
252-
-> Seq Scan on part_ok_2
253-
-> Seq Scan on part_ok_3
254-
(5 rows)
255-
256-
ALTER TABLE calamity.wrong_partition DROP CONSTRAINT pathman_wrong_partition_1_check;
257241
ALTER TABLE calamity.wrong_partition
258242
ADD CONSTRAINT pathman_wrong_partition_1_check
259243
CHECK (val = 1 OR val = 2); /* wrong constraint */

sql/pathman_calamity.sql

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,6 @@ EXPLAIN (COSTS OFF) SELECT * FROM calamity.part_ok; /* check that pathman is ena
8585
SELECT add_to_pathman_config('calamity.part_test', 'val', '10');
8686
EXPLAIN (COSTS OFF) SELECT * FROM calamity.part_ok; /* check that pathman is enabled */
8787

88-
ALTER TABLE calamity.wrong_partition
89-
ADD CONSTRAINT pathman_wrong_partition_1_check
90-
CHECK (val < 10); /* wrong constraint */
91-
SELECT add_to_pathman_config('calamity.part_test', 'val', '10');
92-
EXPLAIN (COSTS OFF) SELECT * FROM calamity.part_ok; /* check that pathman is enabled */
93-
ALTER TABLE calamity.wrong_partition DROP CONSTRAINT pathman_wrong_partition_1_check;
94-
9588
ALTER TABLE calamity.wrong_partition
9689
ADD CONSTRAINT pathman_wrong_partition_1_check
9790
CHECK (val = 1 OR val = 2); /* wrong constraint */

src/init.c

Lines changed: 70 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ static int cmp_range_entries(const void *p1, const void *p2, void *arg);
7575

7676
static bool validate_range_constraint(const Expr *expr,
7777
const PartRelationInfo *prel,
78-
Datum *min,
79-
Datum *max);
78+
Datum *lower, Datum *upper,
79+
bool *lower_null, bool *upper_null);
8080

8181
static bool validate_hash_constraint(const Expr *expr,
8282
const PartRelationInfo *prel,
@@ -375,14 +375,18 @@ fill_prel_with_partitions(const Oid *partitions,
375375

376376
case PT_RANGE:
377377
{
378-
Datum range_min, range_max;
378+
Datum lower, upper;
379+
bool lower_null, upper_null;
379380

380381
if (validate_range_constraint(con_expr, prel,
381-
&range_min, &range_max))
382+
&lower, &upper,
383+
&lower_null, &upper_null))
382384
{
383-
prel->ranges[i].child_oid = partitions[i];
384-
prel->ranges[i].min = range_min;
385-
prel->ranges[i].max = range_max;
385+
prel->ranges[i].child_oid = partitions[i];
386+
prel->ranges[i].min = lower;
387+
prel->ranges[i].max = upper;
388+
prel->ranges[i].infinite_min = lower_null;
389+
prel->ranges[i].infinite_max = upper_null;
386390
}
387391
else
388392
{
@@ -864,61 +868,91 @@ cmp_range_entries(const void *p1, const void *p2, void *arg)
864868

865869
Oid cmp_proc_oid = *(Oid *) arg;
866870

871+
/* If range is half open */
872+
if (v1->infinite_min)
873+
if (v2->infinite_min)
874+
return Int32GetDatum(0);
875+
return Int32GetDatum(-1);
876+
877+
/* Else if range is closed */
867878
return OidFunctionCall2(cmp_proc_oid, v1->min, v2->min);
868879
}
869880

870881
/*
871-
* Validates range constraint. It MUST have this exact format:
882+
* Validates range constraint. It MUST have one of the following formats:
872883
*
873884
* VARIABLE >= CONST AND VARIABLE < CONST
885+
* VARIABLE >= CONST
886+
* VARIABLE < CONST
874887
*
875-
* Writes 'min' & 'max' values on success.
888+
* Writes 'lower' & 'upper' and 'lower_null' & 'upper_null' values on success.
876889
*/
877890
static bool
878891
validate_range_constraint(const Expr *expr,
879892
const PartRelationInfo *prel,
880-
Datum *min,
881-
Datum *max)
893+
Datum *lower, Datum *upper,
894+
bool *lower_null, bool *upper_null)
882895
{
883896
const TypeCacheEntry *tce;
884-
const BoolExpr *boolexpr = (const BoolExpr *) expr;
885897
const OpExpr *opexpr;
886898
int strategy;
887899

888-
if (!expr)
889-
return false;
900+
/* Validates a single expression of kind VAR >= CONST or VAR < CONST */
901+
#define validate_range_expr(expr) \
902+
{ \
903+
Datum val; \
904+
opexpr = (OpExpr *) (expr); \
905+
strategy = get_op_opfamily_strategy(opexpr->opno, tce->btree_opf); \
906+
\
907+
/* Get const value */ \
908+
if (!read_opexpr_const(opexpr, prel, &val)) \
909+
return false; \
910+
\
911+
/* Set min or max depending on operator */ \
912+
switch (strategy) \
913+
{ \
914+
case BTGreaterEqualStrategyNumber: \
915+
*lower_null = false; \
916+
*lower = val; \
917+
break; \
918+
case BTLessStrategyNumber: \
919+
*upper_null = false; \
920+
*upper = val; \
921+
break; \
922+
default: \
923+
return false; \
924+
} \
925+
}
890926

891-
/* it should be an AND operator on top */
892-
if (!and_clause((Node *) expr))
927+
if (!expr)
893928
return false;
894-
929+
*lower_null = *upper_null = false;
895930
tce = lookup_type_cache(prel->atttype, TYPECACHE_BTREE_OPFAMILY);
896931

897-
/* check that left operand is >= operator */
898-
opexpr = (OpExpr *) linitial(boolexpr->args);
899-
strategy = get_op_opfamily_strategy(opexpr->opno, tce->btree_opf);
900-
901-
if (strategy == BTGreaterEqualStrategyNumber)
932+
/* It could be either AND operator on top or just an OpExpr */
933+
if (and_clause((Node *) expr))
902934
{
903-
if (!read_opexpr_const(opexpr, prel, min))
904-
return false;
905-
}
906-
else
907-
return false;
935+
const BoolExpr *boolexpr = (const BoolExpr *) expr;
936+
ListCell *lc;
937+
938+
foreach (lc, boolexpr->args)
939+
{
940+
Node *arg = lfirst(lc);
908941

909-
/* check that right operand is < operator */
910-
opexpr = (OpExpr *) lsecond(boolexpr->args);
911-
strategy = get_op_opfamily_strategy(opexpr->opno, tce->btree_opf);
942+
if(!IsA(arg, OpExpr))
943+
return false;
912944

913-
if (strategy == BTLessStrategyNumber)
945+
validate_range_expr(arg);
946+
}
947+
return true;
948+
}
949+
else if(IsA(expr, OpExpr))
914950
{
915-
if (!read_opexpr_const(opexpr, prel, max))
916-
return false;
951+
validate_range_expr(expr);
952+
return true;
917953
}
918-
else
919-
return false;
920954

921-
return true;
955+
return false;
922956
}
923957

924958
/*

src/partition_creation.c

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -834,11 +834,29 @@ build_range_check_constraint(Oid child_relid,
834834
return range_constr;
835835
}
836836

837+
// static int16_t
838+
// cmp_boundaries(FmgrInfo cmp_func, Datum s1, Datum s2, bool s1_infinite, bool s2_infinite)
839+
// {
840+
// if (s1_infinite && s2_infinite)
841+
// elog(ERROR,
842+
// "two half open ranges are overlap");
843+
844+
// if (s1_infinite)
845+
// return -1;
846+
847+
// if (s2_infinite)
848+
// return 1;
849+
850+
// return DatumGetInt16(FunctionCall2(&cmp_func, start_value, ranges[i].max));
851+
// }
852+
837853
/* Check if range overlaps with any partitions */
838854
bool
839855
check_range_available(Oid parent_relid,
840856
Datum start_value,
841857
Datum end_value,
858+
bool infinite_start,
859+
bool infinite_end,
842860
Oid value_type,
843861
bool raise_error)
844862
{
@@ -864,8 +882,32 @@ check_range_available(Oid parent_relid,
864882
ranges = PrelGetRangesArray(prel);
865883
for (i = 0; i < PrelChildrenCount(prel); i++)
866884
{
867-
int c1 = FunctionCall2(&cmp_func, start_value, ranges[i].max),
868-
c2 = FunctionCall2(&cmp_func, end_value, ranges[i].min);
885+
// int c1 = cmp_boundaries(cmp_func, start_value, ranges[i].max, infinite_start, ranges[i].infinite_max);
886+
// int c2 = cmp_boundaries(cmp_func, end_value, ranges[i].min, infinite_end, ranges[i].infinite_min);
887+
888+
/* If both ranges are half open then they are obviously overlap */
889+
// if (infinite_start && ranges[i].infinite_max)
890+
// return false;
891+
// if (infinite_end && ranges[i].infinite_min)
892+
// return false;
893+
894+
// int c1 = FunctionCall2(&cmp_func, start_value, ranges[i].max),
895+
// c2 = FunctionCall2(&cmp_func, end_value, ranges[i].min);
896+
int c1, c2;
897+
898+
/*
899+
* If the range we're checking starts with minus infinity or current
900+
* range is ends in plus infinity then the left boundary of the first
901+
* one is on the left
902+
*/
903+
c1 = (infinite_start || ranges[i].infinite_max) ?
904+
-1 : FunctionCall2(&cmp_func, start_value, ranges[i].max);
905+
/*
906+
* Similary check the right boundary of first range is on the right
907+
* of the beginning of second one
908+
*/
909+
c2 = (infinite_end || ranges[i].infinite_min) ?
910+
-1 : FunctionCall2(&cmp_func, end_value, ranges[i].max);
869911

870912
/* There's someone! */
871913
if (c1 < 0 && c2 > 0)

src/partition_creation.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ Node * build_raw_range_check_tree(char *attname,
3535
Datum end_value,
3636
Oid value_type);
3737

38-
bool check_range_available(Oid partition_relid,
38+
bool check_range_available(Oid parent_relid,
3939
Datum start_value,
4040
Datum end_value,
41+
bool infinite_start,
42+
bool infinite_end,
4143
Oid value_type,
4244
bool raise_error);
4345

src/pg_pathman.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,10 @@ select_range_partitions(const Datum value,
446446
Assert(cmp_func);
447447

448448
/* Corner cases */
449-
cmp_min = FunctionCall2(cmp_func, value, ranges[startidx].min),
450-
cmp_max = FunctionCall2(cmp_func, value, ranges[endidx].max);
449+
cmp_min = ranges[startidx].infinite_min ?
450+
1 : DatumGetInt32(FunctionCall2(cmp_func, value, ranges[startidx].min));
451+
cmp_max = ranges[endidx].infinite_max ?
452+
-1 : DatumGetInt32(FunctionCall2(cmp_func, value, ranges[endidx].max));
451453

452454
if ((cmp_min <= 0 && strategy == BTLessStrategyNumber) ||
453455
(cmp_min < 0 && (strategy == BTLessEqualStrategyNumber ||

src/pl_range_funcs.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,15 @@ check_range_available_pl(PG_FUNCTION_ARGS)
166166

167167
Datum start_value = PG_GETARG_DATUM(1),
168168
end_value = PG_GETARG_DATUM(2);
169+
bool start_null = PG_ARGISNULL(1),
170+
end_null = PG_ARGISNULL(2);
169171
Oid value_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
170172

171173
/* Raise ERROR if range overlaps with any partition */
172174
check_range_available(parent_relid,
173175
start_value,
174176
end_value,
177+
start_null, end_null,
175178
value_type,
176179
true);
177180

src/rangeset.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ typedef struct {
2828
uint32 upper; /* lossy + upper_bound */
2929
} IndexRange;
3030

31-
3231
/* Convenience macros for make_irange(...) */
3332
#define IR_LOSSY true
3433
#define IR_COMPLETE false
@@ -43,7 +42,6 @@ typedef struct {
4342
#define irange_lower(irange) ( (uint32) (irange.lower & IRANGE_BONDARY_MASK) )
4443
#define irange_upper(irange) ( (uint32) (irange.upper & IRANGE_BONDARY_MASK) )
4544

46-
4745
#define lfirst_irange(lc) ( *(IndexRange *) lfirst(lc) )
4846
#define lappend_irange(list, irange) ( lappend((list), alloc_irange(irange)) )
4947
#define lcons_irange(irange, list) ( lcons(alloc_irange(irange), (list)) )

src/relation_info.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ typedef enum
3333
typedef struct
3434
{
3535
Oid child_oid;
36-
3736
Datum min,
3837
max;
38+
bool infinite_min,
39+
infinite_max;
3940
} RangeEntry;
4041

4142
/*

0 commit comments

Comments
 (0)