@@ -59,8 +59,10 @@ typedef struct
5959typedef struct
6060{
6161 const PartRelationInfo * prel ;
62- Datum least ;
63- Datum greatest ;
62+ bool hasLeast ,
63+ hasGreatest ;
64+ Datum least ,
65+ greatest ;
6466} WalkerContext ;
6567
6668bool pg_pathman_enable ;
@@ -94,6 +96,9 @@ bool inheritance_disabled;
9496
9597/* Expression tree handlers */
9698static WrapperNode * walk_expr_tree (Expr * expr , WalkerContext * context );
99+ static void finish_least_greatest (WrapperNode * wrap , WalkerContext * context );
100+ static Datum increase_hashable_value (const PartRelationInfo * prel , Datum value );
101+ static Datum decrease_hashable_value (const PartRelationInfo * prel , Datum value );
97102static int make_hash (const PartRelationInfo * prel , int value );
98103static void handle_binary_opexpr (WalkerContext * context , WrapperNode * result , const Var * v , const Const * c );
99104static WrapperNode * handle_opexpr (const OpExpr * expr , WalkerContext * context );
@@ -392,7 +397,10 @@ handle_modification_query(Query *parse)
392397
393398 /* Parse syntax tree and extract partition ranges */
394399 context .prel = prel ;
400+ context .hasLeast = false;
401+ context .hasGreatest = false;
395402 wrap = walk_expr_tree (expr , & context );
403+ finish_least_greatest (wrap , & context );
396404 ranges = irange_list_intersect (ranges , wrap -> rangeset );
397405
398406 /* If only one partition is affected then substitute parent table with partition */
@@ -457,13 +465,14 @@ pathman_set_rel_pathlist_hook(PlannerInfo *root, RelOptInfo *rel, Index rti, Ran
457465
458466 if (prel != NULL && found )
459467 {
460- ListCell * lc ;
461- int i ;
462- Oid * dsm_arr ;
463- List * ranges ,
464- * wrappers ;
465- PathKey * pathkeyAsc = NULL ,
466- * pathkeyDesc = NULL ;
468+ ListCell * lc ;
469+ int i ;
470+ Oid * dsm_arr ;
471+ List * ranges ,
472+ * wrappers ;
473+ PathKey * pathkeyAsc = NULL ,
474+ * pathkeyDesc = NULL ;
475+ WalkerContext context ;
467476
468477 if (prel -> parttype == PT_RANGE )
469478 {
@@ -503,16 +512,18 @@ pathman_set_rel_pathlist_hook(PlannerInfo *root, RelOptInfo *rel, Index rti, Ran
503512 ranges = list_make1_int (make_irange (0 , prel -> children_count - 1 , false));
504513
505514 /* Make wrappers over restrictions and collect final rangeset */
515+ context .prel = prel ;
516+ context .hasLeast = false;
517+ context .hasGreatest = false;
506518 wrappers = NIL ;
507519 foreach (lc , rel -> baserestrictinfo )
508520 {
509521 WrapperNode * wrap ;
510- WalkerContext context ;
511-
512- RestrictInfo * rinfo = (RestrictInfo * ) lfirst (lc );
522+ RestrictInfo * rinfo = (RestrictInfo * ) lfirst (lc );
513523
514- context .prel = prel ;
515524 wrap = walk_expr_tree (rinfo -> clause , & context );
525+ if (!lc -> next )
526+ finish_least_greatest (wrap , & context );
516527 wrappers = lappend (wrappers , wrap );
517528 ranges = irange_list_intersect (ranges , wrap -> rangeset );
518529 }
@@ -984,6 +995,74 @@ walk_expr_tree(Expr *expr, WalkerContext *context)
984995 }
985996}
986997
998+ static void
999+ finish_least_greatest (WrapperNode * wrap , WalkerContext * context )
1000+ {
1001+ if (context -> hasLeast && context -> hasGreatest )
1002+ {
1003+ switch (context -> prel -> atttype )
1004+ {
1005+ case INT4OID :
1006+ {
1007+ int least = DatumGetInt32 (context -> least ),
1008+ greatest = DatumGetInt32 (context -> greatest );
1009+ List * rangeset = NIL ;
1010+
1011+ if (greatest - least + 1 < context -> prel -> children_count )
1012+ {
1013+ int value ,
1014+ hash ;
1015+ for (value = least ; value <= greatest ; value ++ )
1016+ {
1017+ hash = make_hash (context -> prel , value );
1018+ rangeset = irange_list_union (rangeset ,
1019+ list_make1_irange (make_irange (hash , hash , true)));
1020+ }
1021+ }
1022+ wrap -> rangeset = irange_list_intersect (wrap -> rangeset ,
1023+ rangeset );
1024+ }
1025+ break ;
1026+ default :
1027+ elog (ERROR , "Invalid datatype: %u" , context -> prel -> atttype );
1028+ }
1029+ }
1030+ context -> hasLeast = false;
1031+ context -> hasGreatest = false;
1032+ }
1033+
1034+ /*
1035+ * Increase value of hash partitioned column.
1036+ */
1037+ static Datum
1038+ increase_hashable_value (const PartRelationInfo * prel , Datum value )
1039+ {
1040+ switch (prel -> atttype )
1041+ {
1042+ case INT4OID :
1043+ return Int32GetDatum (DatumGetInt32 (value ) + 1 );
1044+ default :
1045+ elog (ERROR , "Invalid datatype: %u" , prel -> atttype );
1046+ return (Datum )0 ;
1047+ }
1048+ }
1049+
1050+ /*
1051+ * Decrease value of hash partitioned column.
1052+ */
1053+ static Datum
1054+ decrease_hashable_value (const PartRelationInfo * prel , Datum value )
1055+ {
1056+ switch (prel -> atttype )
1057+ {
1058+ case INT4OID :
1059+ return Int32GetDatum (DatumGetInt32 (value ) - 1 );
1060+ default :
1061+ elog (ERROR , "Invalid datatype: %u" , prel -> atttype );
1062+ return (Datum )0 ;
1063+ }
1064+ }
1065+
9871066/*
9881067 * This function determines which partitions should appear in query plan
9891068 */
@@ -1018,7 +1097,33 @@ handle_binary_opexpr(WalkerContext *context, WrapperNode *result,
10181097 switch (prel -> parttype )
10191098 {
10201099 case PT_HASH :
1021- if (strategy == BTEqualStrategyNumber )
1100+ if (strategy == BTLessStrategyNumber ||
1101+ strategy == BTLessEqualStrategyNumber )
1102+ {
1103+ Datum value = c -> constvalue ;
1104+
1105+ if (strategy == BTLessStrategyNumber )
1106+ value = decrease_hashable_value (prel , value );
1107+ if (!context -> hasGreatest || DatumGetInt32 (FunctionCall2 (& cmp_func , value , context -> greatest )) < 0 )
1108+ {
1109+ context -> greatest = value ;
1110+ context -> hasGreatest = true;
1111+ }
1112+ }
1113+ else if (strategy == BTGreaterStrategyNumber ||
1114+ strategy == BTGreaterEqualStrategyNumber )
1115+ {
1116+ Datum value = c -> constvalue ;
1117+
1118+ if (strategy == BTGreaterStrategyNumber )
1119+ value = increase_hashable_value (prel , value );
1120+ if (!context -> hasLeast || DatumGetInt32 (FunctionCall2 (& cmp_func , value , context -> least )) > 0 )
1121+ {
1122+ context -> least = value ;
1123+ context -> hasLeast = true;
1124+ }
1125+ }
1126+ else if (strategy == BTEqualStrategyNumber )
10221127 {
10231128 int_value = DatumGetInt32 (c -> constvalue );
10241129 key .hash = make_hash (prel , int_value );
@@ -1309,9 +1414,10 @@ handle_boolexpr(const BoolExpr *expr, WalkerContext *context)
13091414
13101415 arg = walk_expr_tree ((Expr * )lfirst (lc ), context );
13111416 result -> args = lappend (result -> args , arg );
1312- switch (expr -> boolop )
1417+ switch (expr -> boolop )
13131418 {
13141419 case OR_EXPR :
1420+ finish_least_greatest (arg , context );
13151421 result -> rangeset = irange_list_union (result -> rangeset , arg -> rangeset );
13161422 break ;
13171423 case AND_EXPR :
0 commit comments