diff --git a/src/query/partition.c b/src/query/partition.c index c104bd0256..77758cc221 100644 --- a/src/query/partition.c +++ b/src/query/partition.c @@ -35,6 +35,7 @@ #include "xasl.h" #include "xasl_predicate.hpp" #include "xasl_unpack_info.hpp" +#include "set_object.h" // XXX: SHOULD BE THE LAST INCLUDE HEADER #include "memory_wrapper.hpp" @@ -137,6 +138,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, @@ -167,6 +170,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 */ @@ -1339,6 +1347,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); @@ -1394,6 +1451,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) @@ -1668,6 +1726,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; } @@ -1910,13 +1976,50 @@ 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; + REGU_VARIABLE *seq_var; + REGU_VARIABLE_LIST seq_list; 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); status = MATCH_NOT_FOUND; - if (partition_do_regu_variables_match (pinfo, left, part_expr)) + + /* TODO: This is a temporary implementation for sequence handling. */ + if ((left->type == TYPE_FUNC || right->type == TYPE_FUNC) && part_expr->type == TYPE_ATTR_ID) + { + if ((left->type == TYPE_FUNC && left->value.funcp->ftype == F_SEQUENCE) || + (right->type == TYPE_FUNC && right->value.funcp->ftype == F_SEQUENCE)) + { + seq_var = (left->type == TYPE_FUNC) ? left : right; + seq_list = seq_var->value.funcp->operand; + int i = 0; + + while (seq_list != NULL) + { + // TODO: Need to verify if the value is constant + seq_var = &seq_list->value; + if (seq_var->value.attr_descr.id == part_expr->value.attr_descr.id) + { + break; + } + i++; + seq_list = seq_list->next; + } + + if (seq_list == NULL) + { + /* Attribute not found in sequence */ + // pinfo->error_code = ER_FAILED; + status = MATCH_NOT_FOUND; + break; + } + + DB_VALUE *val = (left->type == TYPE_FUNC) ? &right->value.dbval : &left->value.dbval; + status = partition_prune_db_val (pinfo, val->data.set->set->array[i], op, pruned); + } + } + else if (partition_do_regu_variables_match (pinfo, left, part_expr)) { status = partition_prune (pinfo, right, op, pruned); } @@ -1924,6 +2027,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)) + { + 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; } @@ -1951,6 +2065,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)) + { + if (partition_do_regu_variables_contain (pinfo, regu, part_expr)) + { + status = partition_prune_arith (pinfo, regu, list, part_expr, op, pruned); + } + } } break; @@ -1971,6 +2092,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 @@ -2575,6 +2871,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