@@ -59,8 +59,10 @@ typedef struct
5959typedef struct
6060{
6161const 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 */
394399context .prel = prel ;
400+ context .hasLeast = false;
401+ context .hasGreatest = false;
395402wrap = walk_expr_tree (expr ,& context );
403+ finish_least_greatest (wrap ,& context );
396404ranges = 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
458466if (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
468477if (prel -> parttype == PT_RANGE )
469478{
@@ -503,16 +512,18 @@ pathman_set_rel_pathlist_hook(PlannerInfo *root, RelOptInfo *rel, Index rti, Ran
503512ranges = 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;
506518wrappers = NIL ;
507519foreach (lc ,rel -> baserestrictinfo )
508520{
509521WrapperNode * wrap ;
510- WalkerContext context ;
511-
512- RestrictInfo * rinfo = (RestrictInfo * )lfirst (lc );
522+ RestrictInfo * rinfo = (RestrictInfo * )lfirst (lc );
513523
514- context .prel = prel ;
515524wrap = walk_expr_tree (rinfo -> clause ,& context );
525+ if (!lc -> next )
526+ finish_least_greatest (wrap ,& context );
516527wrappers = lappend (wrappers ,wrap );
517528ranges = 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,
10181097switch (prel -> parttype )
10191098{
10201099case 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{
10231128int_value = DatumGetInt32 (c -> constvalue );
10241129key .hash = make_hash (prel ,int_value );
@@ -1309,9 +1414,10 @@ handle_boolexpr(const BoolExpr *expr, WalkerContext *context)
13091414
13101415arg = walk_expr_tree ((Expr * )lfirst (lc ),context );
13111416result -> args = lappend (result -> args ,arg );
1312- switch (expr -> boolop )
1417+ switch (expr -> boolop )
13131418{
13141419case OR_EXPR :
1420+ finish_least_greatest (arg ,context );
13151421result -> rangeset = irange_list_union (result -> rangeset ,arg -> rangeset );
13161422break ;
13171423case AND_EXPR :