Skip to content

Commit 17d7029

Browse files
committed
refactoring & fixes in function handle_arrexpr(), moved static inline functions to rangeset.h
1 parent 48afabd commit 17d7029

File tree

3 files changed

+233
-103
lines changed

3 files changed

+233
-103
lines changed

src/include/rangeset.h

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,30 @@ irange_cmp_lossiness(IndexRange a, IndexRange b)
129129
}
130130

131131

132-
/* Various traits */
133-
bool iranges_intersect(IndexRange a, IndexRange b);
134-
bool iranges_adjoin(IndexRange a, IndexRange b);
135-
bool irange_eq_bounds(IndexRange a, IndexRange b);
132+
/* Check if two ranges intersect */
133+
static inline bool
134+
iranges_intersect(IndexRange a, IndexRange b)
135+
{
136+
return (irange_lower(a) <= irange_upper(b)) &&
137+
(irange_lower(b) <= irange_upper(a));
138+
}
139+
140+
/* Check if two ranges adjoin */
141+
static inline bool
142+
iranges_adjoin(IndexRange a, IndexRange b)
143+
{
144+
return (irange_upper(a) == irb_pred(irange_lower(b))) ||
145+
(irange_upper(b) == irb_pred(irange_lower(a)));
146+
}
147+
148+
/* Check if two ranges cover the same area */
149+
static inline bool
150+
irange_eq_bounds(IndexRange a, IndexRange b)
151+
{
152+
return (irange_lower(a) == irange_lower(b)) &&
153+
(irange_upper(a) == irange_upper(b));
154+
}
155+
136156

137157
/* Basic operations on IndexRanges */
138158
IndexRange irange_union_simple(IndexRange a, IndexRange b);
@@ -141,6 +161,7 @@ IndexRange irange_intersection_simple(IndexRange a, IndexRange b);
141161
/* Operations on Lists of IndexRanges */
142162
List *irange_list_union(List *a, List *b);
143163
List *irange_list_intersection(List *a, List *b);
164+
List *irange_list_set_lossiness(List *ranges, bool lossy);
144165

145166
/* Utility functions */
146167
int irange_list_length(List *rangeset);

src/pg_pathman.c

Lines changed: 185 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ static void
720720
handle_const(const Const *c,
721721
const int strategy,
722722
const WalkerContext *context,
723-
WrapperNode *result) /* ret value #1 */
723+
WrapperNode *result) /* ret value #1 */
724724
{
725725
const PartRelationInfo *prel = context->prel;
726726

@@ -838,16 +838,103 @@ handle_const(const Const *c,
838838
result->paramsel = estimate_paramsel_using_prel(prel, strategy);
839839
}
840840

841+
/* Array handler */
842+
static void
843+
handle_array(ArrayType *array,
844+
const int strategy,
845+
const bool use_or,
846+
const WalkerContext *context,
847+
WrapperNode *result) /* ret value #1 */
848+
{
849+
const PartRelationInfo *prel = context->prel;
850+
851+
/* Elements of the array */
852+
Datum *elem_values;
853+
bool *elem_isnull;
854+
int elem_count;
855+
856+
/* Element's properties */
857+
Oid elem_type;
858+
int16 elem_len;
859+
bool elem_byval;
860+
char elem_align;
861+
862+
/* Check if we can work with this strategy */
863+
if (strategy == 0)
864+
goto handle_array_return;
865+
866+
/* Get element's properties */
867+
elem_type = ARR_ELEMTYPE(array);
868+
get_typlenbyvalalign(elem_type, &elem_len, &elem_byval, &elem_align);
869+
870+
/* Extract values from the array */
871+
deconstruct_array(array, elem_type, elem_len, elem_byval, elem_align,
872+
&elem_values, &elem_isnull, &elem_count);
873+
874+
/* Handle non-null Const arrays */
875+
if (elem_count > 0)
876+
{
877+
List *ranges;
878+
int i;
879+
880+
/* Set default ranges for OR | AND */
881+
ranges = use_or ? NIL : list_make1_irange_full(prel, IR_COMPLETE);
882+
883+
/* Select partitions using values */
884+
for (i = 0; i < elem_count; i++)
885+
{
886+
WrapperNode wrap;
887+
Const c;
888+
889+
NodeSetTag(&c, T_Const);
890+
c.consttype = elem_type;
891+
c.consttypmod = -1;
892+
c.constcollid = InvalidOid;
893+
c.constlen = datumGetSize(elem_values[i],
894+
elem_byval,
895+
elem_len);
896+
c.constvalue = elem_values[i];
897+
c.constisnull = elem_isnull[i];
898+
c.constbyval = elem_byval;
899+
c.location = -1;
900+
901+
handle_const(&c, strategy, context, &wrap);
902+
903+
/* Should we use OR | AND? */
904+
ranges = use_or ?
905+
irange_list_union(ranges, wrap.rangeset) :
906+
irange_list_intersection(ranges, wrap.rangeset);
907+
908+
result->paramsel = Max(result->paramsel, wrap.paramsel);
909+
}
910+
911+
/* Free resources */
912+
pfree(elem_values);
913+
pfree(elem_isnull);
914+
915+
/* Save rangeset */
916+
result->rangeset = ranges;
917+
918+
return; /* done, exit */
919+
}
920+
921+
handle_array_return:
922+
result->rangeset = list_make1_irange_full(prel, IR_LOSSY);
923+
result->paramsel = estimate_paramsel_using_prel(prel, strategy);
924+
}
925+
841926
/* Boolean expression handler */
842927
static void
843928
handle_boolexpr(const BoolExpr *expr,
844929
const WalkerContext *context,
845-
WrapperNode *result)
930+
WrapperNode *result) /* ret value #1 */
846931
{
847-
ListCell *lc;
848-
const PartRelationInfo *prel = context->prel;
932+
const PartRelationInfo *prel = context->prel;
933+
ListCell *lc;
849934

935+
/* Save expression */
850936
result->orig = (const Node *) expr;
937+
851938
result->args = NIL;
852939
result->paramsel = 1.0;
853940

@@ -858,22 +945,22 @@ handle_boolexpr(const BoolExpr *expr,
858945

859946
foreach (lc, expr->args)
860947
{
861-
WrapperNode *arg_result;
948+
WrapperNode *wrap;
862949

863-
arg_result = walk_expr_tree((Expr *) lfirst(lc), context);
864-
result->args = lappend(result->args, arg_result);
950+
wrap = walk_expr_tree((Expr *) lfirst(lc), context);
951+
result->args = lappend(result->args, wrap);
865952

866953
switch (expr->boolop)
867954
{
868955
case OR_EXPR:
869956
result->rangeset = irange_list_union(result->rangeset,
870-
arg_result->rangeset);
957+
wrap->rangeset);
871958
break;
872959

873960
case AND_EXPR:
874961
result->rangeset = irange_list_intersection(result->rangeset,
875-
arg_result->rangeset);
876-
result->paramsel *= arg_result->paramsel;
962+
wrap->rangeset);
963+
result->paramsel *= wrap->paramsel;
877964
break;
878965

879966
default:
@@ -901,107 +988,131 @@ handle_boolexpr(const BoolExpr *expr,
901988
static void
902989
handle_arrexpr(const ScalarArrayOpExpr *expr,
903990
const WalkerContext *context,
904-
WrapperNode *result)
991+
WrapperNode *result) /* ret value #1 */
905992
{
906-
Node *exprnode = (Node *) linitial(expr->args);
907-
Node *arraynode = (Node *) lsecond(expr->args);
993+
Node *part_expr = (Node *) linitial(expr->args);
994+
Node *array = (Node *) lsecond(expr->args);
908995
const PartRelationInfo *prel = context->prel;
909996
TypeCacheEntry *tce;
910997
int strategy;
911998

912-
result->orig = (const Node *) expr;
913-
914999
tce = lookup_type_cache(prel->ev_type, TYPECACHE_BTREE_OPFAMILY);
9151000
strategy = get_op_opfamily_strategy(expr->opno, tce->btree_opf);
9161001

917-
if (!match_expr_to_operand(context->prel_expr, exprnode))
1002+
/* Check if expression tree is a partitioning expression */
1003+
if (!match_expr_to_operand(context->prel_expr, part_expr))
9181004
goto handle_arrexpr_return;
9191005

920-
/* Handle non-null Const arrays */
921-
if (arraynode && IsA(arraynode, Const) && !((Const *) arraynode)->constisnull)
922-
{
923-
ArrayType *arrayval;
924-
925-
int16 elemlen;
926-
bool elembyval;
927-
char elemalign;
1006+
/* Check if we can work with this strategy */
1007+
if (strategy == 0)
1008+
goto handle_arrexpr_return;
9281009

929-
int num_elems;
1010+
/* Examine the array node */
1011+
switch (nodeTag(array))
1012+
{
1013+
case T_Const:
1014+
{
1015+
Const *c = (Const *) array;
9301016

931-
Datum *elem_values;
932-
bool *elem_isnull;
1017+
/* Array is NULL */
1018+
if (c->constisnull)
1019+
goto handle_arrexpr_return;
9331020

934-
WalkerContext nested_wcxt;
935-
List *ranges;
936-
int i;
1021+
/* Examine array */
1022+
handle_array(DatumGetArrayTypeP(c->constvalue),
1023+
strategy, expr->useOr, context, result);
9371024

938-
/* Extract values from array */
939-
arrayval = DatumGetArrayTypeP(((Const *) arraynode)->constvalue);
1025+
/* Save expression */
1026+
result->orig = (const Node *) expr;
9401027

941-
get_typlenbyvalalign(ARR_ELEMTYPE(arrayval),
942-
&elemlen, &elembyval, &elemalign);
1028+
return; /* done, exit */
1029+
}
9431030

944-
deconstruct_array(arrayval,
945-
ARR_ELEMTYPE(arrayval),
946-
elemlen, elembyval, elemalign,
947-
&elem_values, &elem_isnull, &num_elems);
1031+
case T_ArrayExpr:
1032+
{
1033+
ArrayExpr *arr_expr = (ArrayExpr *) array;
1034+
Oid elem_type = arr_expr->element_typeid;
1035+
bool array_has_params = false;
1036+
List *ranges;
1037+
ListCell *lc;
9481038

949-
/* Copy WalkerContext */
950-
memcpy((void *) &nested_wcxt,
951-
(const void *) context,
952-
sizeof(WalkerContext));
1039+
/* Set default ranges for OR | AND */
1040+
ranges = expr->useOr ? NIL : list_make1_irange_full(prel, IR_COMPLETE);
9531041

954-
/* Set default ranges for OR | AND */
955-
ranges = expr->useOr ? NIL : list_make1_irange_full(prel, IR_COMPLETE);
1042+
/* Walk trough elements list */
1043+
foreach (lc, arr_expr->elements)
1044+
{
1045+
Node *elem = lfirst(lc);
1046+
WrapperNode wrap;
9561047

957-
/* Select partitions using values */
958-
for (i = 0; i < num_elems; i++)
959-
{
960-
WrapperNode sub_result;
961-
Const c;
1048+
/* Stop if ALL + quals evaluate to NIL */
1049+
if (!expr->useOr && ranges == NIL)
1050+
break;
9621051

963-
NodeSetTag(&c, T_Const);
964-
c.consttype = ARR_ELEMTYPE(arrayval);
965-
c.consttypmod = -1;
966-
c.constcollid = InvalidOid;
967-
c.constlen = datumGetSize(elem_values[i],
968-
elembyval,
969-
elemlen);
970-
c.constvalue = elem_values[i];
971-
c.constisnull = elem_isnull[i];
972-
c.constbyval = elembyval;
973-
c.location = -1;
1052+
/* Is this a const value? */
1053+
if (IsConstValue(elem, context))
1054+
{
1055+
Const *c = ExtractConst(elem, context);
1056+
1057+
/* Is this an array?.. */
1058+
if (c->consttype != elem_type)
1059+
{
1060+
/* Array is NULL */
1061+
if (c->constisnull)
1062+
goto handle_arrexpr_return;
1063+
1064+
/* Examine array */
1065+
handle_array(DatumGetArrayTypeP(c->constvalue),
1066+
strategy, expr->useOr, context, &wrap);
1067+
}
1068+
/* ... or a single element? */
1069+
else handle_const(c, strategy, context, &wrap);
1070+
1071+
/* Should we use OR | AND? */
1072+
ranges = expr->useOr ?
1073+
irange_list_union(ranges, wrap.rangeset) :
1074+
irange_list_intersection(ranges, wrap.rangeset);
1075+
}
1076+
else array_has_params = true; /* we have non-const nodes */
1077+
}
9741078

975-
handle_const(&c, strategy, &nested_wcxt, &sub_result);
1079+
/* Check for PARAM-related optimizations */
1080+
if (array_has_params)
1081+
{
1082+
/* We can't say anything if PARAMs + ANY */
1083+
if (expr->useOr)
1084+
goto handle_arrexpr_return;
9761085

977-
ranges = expr->useOr ?
978-
irange_list_union(ranges, sub_result.rangeset) :
979-
irange_list_intersection(ranges, sub_result.rangeset);
1086+
/* Recheck condition on a narrowed set of partitions */
1087+
ranges = irange_list_set_lossiness(ranges, IR_LOSSY);
1088+
}
9801089

981-
result->paramsel = Max(result->paramsel, sub_result.paramsel);
982-
}
1090+
/* Save rangeset */
1091+
result->rangeset = ranges;
9831092

984-
result->rangeset = ranges;
985-
if (num_elems == 0)
986-
result->paramsel = 0.0;
1093+
/* Save expression */
1094+
result->orig = (const Node *) expr;
9871095

988-
/* Free resources */
989-
pfree(elem_values);
990-
pfree(elem_isnull);
1096+
return; /* done, exit */
1097+
}
9911098

992-
return; /* done, exit */
1099+
default:
1100+
break;
9931101
}
9941102

9951103
handle_arrexpr_return:
9961104
result->rangeset = list_make1_irange_full(prel, IR_LOSSY);
9971105
result->paramsel = estimate_paramsel_using_prel(prel, strategy);
1106+
1107+
/* Save expression */
1108+
result->orig = (const Node *) expr;
9981109
}
9991110

10001111
/* Operator expression handler */
10011112
static void
10021113
handle_opexpr(const OpExpr *expr,
10031114
const WalkerContext *context,
1004-
WrapperNode *result)
1115+
WrapperNode *result) /* ret value #1 */
10051116
{
10061117
Node *param;
10071118
const PartRelationInfo *prel = context->prel;

0 commit comments

Comments
 (0)