Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CBRD-25708] Enable partition pruning when the partition key is a function expression and the WHERE clause uses the original column #5682

Draft
wants to merge 15 commits into
base: feature/partition-table
Choose a base branch
from
Draft
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
289 changes: 288 additions & 1 deletion src/query/partition.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ static MATCH_STATUS partition_match_key_range (PRUNING_CONTEXT * pinfo, const KE
PRUNING_BITSET * pruned);
static bool partition_do_regu_variables_match (PRUNING_CONTEXT * pinfo, const REGU_VARIABLE * left,
const REGU_VARIABLE * right);
static bool partition_do_regu_variables_contain (PRUNING_CONTEXT * pinfo, const REGU_VARIABLE * left,
const REGU_VARIABLE * right);
static MATCH_STATUS partition_prune (PRUNING_CONTEXT * pinfo, const REGU_VARIABLE * arg, const PRUNING_OP op,
PRUNING_BITSET * pruned);
static MATCH_STATUS partition_prune_db_val (PRUNING_CONTEXT * pinfo, const DB_VALUE * val, const PRUNING_OP op,
Expand Down Expand Up @@ -167,6 +169,11 @@ static int partition_attrinfo_get_key (THREAD_ENTRY * thread_p, PRUNING_CONTEXT
/* misc pruning functions */
static bool partition_decrement_value (DB_VALUE * val);

static void partition_cache_dbvalp (REGU_VARIABLE * var, DB_VALUE * val);
static bool partition_supports_pruning_op_for_function (const PRUNING_OP op, const REGU_VARIABLE * part_expr);
static MATCH_STATUS partition_prune_arith (PRUNING_CONTEXT * pinfo, const REGU_VARIABLE * left,
const REGU_VARIABLE * right, REGU_VARIABLE * part_expr, const PRUNING_OP op,
PRUNING_BITSET * pruned);

/* PRUNING_BITSET manipulation functions */

Expand Down Expand Up @@ -1339,6 +1346,55 @@ partition_prune_range (PRUNING_CONTEXT * pinfo, const DB_VALUE * val, const PRUN
int rmin = DB_UNK, rmax = DB_UNK;
MATCH_STATUS status;

if (db_value_type_is_collection (val))
{
PRUNING_BITSET new_pruned;
DB_COLLECTION *values = NULL;
DB_VALUE col;
int size, j;

values = db_get_set (val);
size = db_set_size (values);
if (size < 0)
{
pinfo->error_code = ER_FAILED;
status = MATCH_NOT_FOUND;
goto cleanup;
}

for (j = 0; j < size; j++)
{
if (db_set_get (values, j, &col) != NO_ERROR)
{
pinfo->error_code = ER_FAILED;
status = MATCH_NOT_FOUND;
goto cleanup;
}

pruningset_init (&new_pruned, PARTITIONS_COUNT (pinfo));
status = partition_prune_range (pinfo, &col, op, &new_pruned);
if (j > 0)
{
if (op == PO_EQ)
{
pruningset_intersect (pruned, &new_pruned);
}
else
{
pruningset_union (pruned, &new_pruned);
}
}
else
{
pruningset_copy (pruned, &new_pruned);
}

pr_clear_value (&col);
}

goto cleanup;
}

db_make_null (&min);
db_make_null (&max);

Expand Down Expand Up @@ -1394,6 +1450,7 @@ partition_prune_range (PRUNING_CONTEXT * pinfo, const DB_VALUE * val, const PRUN
status = MATCH_OK;
switch (op)
{
case PO_IN:
case PO_EQ:
/* Filter is part_expr = value. Find the *only* partition for which min <= value < max */
if ((rmin == DB_EQ || rmin == DB_LT) && rmax == DB_LT)
Expand Down Expand Up @@ -1668,6 +1725,14 @@ partition_is_reguvar_const (const REGU_VARIABLE * regu_var)
/* either all arguments are constants of this is an expression with no arguments */
return true;
}
case TYPE_ATTR_ID:
{
if (regu_var->value.attr_descr.cache_dbvalp == NULL)
{
return false;
}
return true;
}
default:
return false;
}
Expand Down Expand Up @@ -1910,7 +1975,6 @@ partition_match_pred_expr (PRUNING_CONTEXT * pinfo, const PRED_EXPR * pr, PRUNIN
/* see if part_expr matches right or left */
REGU_VARIABLE *left, *right;
PRUNING_OP op;

left = pr->pe.m_eval_term.et.et_comp.lhs;
right = pr->pe.m_eval_term.et.et_comp.rhs;
op = partition_rel_op_to_pruning_op (pr->pe.m_eval_term.et.et_comp.rel_op);
Expand All @@ -1924,6 +1988,17 @@ partition_match_pred_expr (PRUNING_CONTEXT * pinfo, const PRED_EXPR * pr, PRUNIN
{
status = partition_prune (pinfo, left, op, pruned);
}
else if (partition_supports_pruning_op_for_function (op, part_expr))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

파티션 키가 아닌 컬럼을 포함한 집합을 조건절에서 비교하는 경우, 파티션 프루닝이 불가능한 문제가 있습니다.

예:

drop table if exists t1;
create table t1(c1 int, c2 int) partition by range(c1) (
    partition p1 values less than (10),
    partition p2 values less than (20),
    partition p3 values less than (30),
    partition p4 values less than (40)
);

insert into t1 values (3, 1), (6, 2), (9, 3), (12, 4), (15, 5), (18, 6), (21, 7), (24, 8), (27, 9), (30, 10);

/* c1에 해당하는 5, 10이 상수 값임에도, 파티션 프루닝 불가능 */
select /*+ recompile */ * from t1 where (c1, c2) in ((5, 1),(10, 2));

{
if (partition_do_regu_variables_contain (pinfo, left, part_expr))
{
status = partition_prune_arith (pinfo, left, right, part_expr, op, pruned);
}
else if (partition_do_regu_variables_contain (pinfo, right, part_expr))
{
status = partition_prune_arith (pinfo, right, left, part_expr, op, pruned);
}
}
break;
}

Expand Down Expand Up @@ -1951,6 +2026,13 @@ partition_match_pred_expr (PRUNING_CONTEXT * pinfo, const PRED_EXPR * pr, PRUNIN
{
status = partition_prune (pinfo, list, op, pruned);
}
else if (partition_supports_pruning_op_for_function (op, part_expr))
Hamkua marked this conversation as resolved.
Show resolved Hide resolved
{
if (partition_do_regu_variables_contain (pinfo, regu, part_expr))
{
status = partition_prune_arith (pinfo, regu, list, part_expr, op, pruned);
}
}
}
break;

Expand All @@ -1971,6 +2053,181 @@ partition_match_pred_expr (PRUNING_CONTEXT * pinfo, const PRED_EXPR * pr, PRUNIN
return status;
}

static MATCH_STATUS
partition_prune_arith (PRUNING_CONTEXT * pinfo, const REGU_VARIABLE * left, const REGU_VARIABLE * right,
REGU_VARIABLE * part_expr, const PRUNING_OP op, PRUNING_BITSET * pruned)
{
MATCH_STATUS status = MATCH_NOT_FOUND;
DB_VALUE val, casted_val;
DB_COLLECTION *collection = NULL;
DB_COLLECTION *new_collection = NULL;
DB_VALUE old_collection_val, new_collection_val, part_key_val;
TP_DOMAIN_STATUS dom_status;
bool is_value;

db_make_null (&val);
db_make_null (&casted_val);
db_make_null (&old_collection_val);
db_make_null (&new_collection_val);
db_make_null (&part_key_val);

if (partition_get_value_from_regu_var (pinfo, right, &val, &is_value) == NO_ERROR)
{
int size = 0;

if (db_value_type_is_collection (&val))
{
collection = db_get_collection (&val);
new_collection = db_col_copy (collection);
// new_collection = db_col_create (type, size, NULL);

if (new_collection == NULL)
{
goto cleanup;
}

size = db_col_size (collection);
for (int i = 0; i < size; i++)
{
if (db_col_get (collection, i, &old_collection_val) != NO_ERROR)
{
goto cleanup;
}

if (TP_DOMAIN_TYPE (left->domain) != DB_VALUE_TYPE (&old_collection_val))
{
dom_status = tp_value_cast (&old_collection_val, &casted_val, left->domain, false);

if (dom_status != DOMAIN_COMPATIBLE)
{
(void) tp_domain_status_er_set (dom_status, ARG_FILE_LINE, &old_collection_val, left->domain);

pinfo->error_code = ER_FAILED;
goto cleanup;
}

// TODO: need to inspect collection's data type
partition_cache_dbvalp (part_expr, &casted_val);
}
else
{
partition_cache_dbvalp (part_expr, &old_collection_val);
}

if (partition_get_value_from_regu_var (pinfo, part_expr, &part_key_val, &is_value) == NO_ERROR)
{
if (is_value)
{
db_col_put (new_collection, i, &part_key_val);
}
}
}

if (db_make_collection (&new_collection_val, new_collection) != NO_ERROR)
{
goto cleanup;
}

status = partition_prune_db_val (pinfo, &new_collection_val, op, pruned);
}
else
{
if (TP_DOMAIN_TYPE (left->domain) != DB_VALUE_TYPE (&val))
{
dom_status = tp_value_cast (&val, &casted_val, left->domain, false);

if (dom_status != DOMAIN_COMPATIBLE)
{
(void) tp_domain_status_er_set (dom_status, ARG_FILE_LINE, &val, left->domain);

pinfo->error_code = ER_FAILED;
goto cleanup;
}

partition_cache_dbvalp (part_expr, &casted_val);
}
else
{
partition_cache_dbvalp (part_expr, &val);
}
}

status = partition_prune (pinfo, part_expr, op, pruned);
}

cleanup:
partition_cache_dbvalp (part_expr, NULL);
if (new_collection != NULL)
{
db_col_free (new_collection);
}
pr_clear_value (&old_collection_val);
pr_clear_value (&new_collection_val);
pr_clear_value (&part_key_val);
pr_clear_value (&casted_val);
pr_clear_value (&val);

return status;
}

static bool
partition_supports_pruning_op_for_function (const PRUNING_OP op, const REGU_VARIABLE * part_expr)
{
OPERATOR_TYPE opcode;

if (part_expr->type != TYPE_INARITH)
{
return false;
}

opcode = part_expr->value.arithptr->opcode;

switch (op)
{
case PO_LT:
case PO_LE:
case PO_GT:
case PO_GE:
switch (opcode)
{
case T_YEAR:
case T_TODAYS:
case T_UNIX_TIMESTAMP:
return true;
default:
return false;
}
case PO_EQ:
case PO_NE:
case PO_IN:
case PO_NOT_IN:
case PO_IS_NULL:
return true;
default:
return false;
}

}

static bool
partition_do_regu_variables_contain (PRUNING_CONTEXT * pinfo, const REGU_VARIABLE * left, const REGU_VARIABLE * right)
{
if (left == NULL || right == NULL)
{
return left == right;
}

if (left->type == TYPE_ATTR_ID && right->type == TYPE_INARITH)
{
if (left->value.attr_descr.id == pinfo->attr_id)
{
return true;
}
}

return false;
}

/*
* partition_match_key_range () - perform pruning using a key_range
* return : pruned list
Expand Down Expand Up @@ -2575,6 +2832,36 @@ partition_set_cache_info_for_expr (REGU_VARIABLE * var, ATTR_ID attr_id, HEAP_CA
}
}

static void
partition_cache_dbvalp (REGU_VARIABLE * var, DB_VALUE * val)
{
assert (var != NULL);
switch (var->type)
{
case TYPE_ATTR_ID:
var->value.attr_descr.cache_dbvalp = val;
break;

case TYPE_INARITH:
if (var->value.arithptr->leftptr != NULL)
{
partition_cache_dbvalp (var->value.arithptr->leftptr, val);
}

if (var->value.arithptr->rightptr != NULL)
{
partition_cache_dbvalp (var->value.arithptr->rightptr, val);
}

if (var->value.arithptr->thirdptr != NULL)
{
partition_cache_dbvalp (var->value.arithptr->thirdptr, val);
}
default:
break;
}
}

/*
* partition_get_attribute_id () - get the id of the attribute of the
* partition expression
Expand Down
Loading