During das partition range pruning during execution, type protection of virtual generated columns is required.
This commit is contained in:
		| @ -2479,7 +2479,8 @@ int ObTableScanOp::construct_partition_range(ObArenaAllocator &allocator, | ||||
|                                                     range_key_count, | ||||
|                                                     scan_range.table_id_, | ||||
|                                                     eval_ctx_, | ||||
|                                                     part_range))) { | ||||
|                                                     part_range, | ||||
|                                                     allocator))) { | ||||
|           LOG_WARN("get partition real range failed", K(ret)); | ||||
|         } | ||||
|         LOG_DEBUG("part range info", K(part_range), K(can_prune), K(ret)); | ||||
|  | ||||
| @ -2761,6 +2761,26 @@ int ObSQLUtils::get_partition_range(ObObj *start_row_key, | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| bool ObSQLUtils::part_expr_has_virtual_column(const ObExpr *part_expr) | ||||
| { | ||||
|   bool has_virtual_column = false; | ||||
|   if (part_expr == NULL) { | ||||
|     // do nothing. | ||||
|   } else if (part_expr->type_ == T_REF_COLUMN || part_expr->type_ == T_FUN_SYS_PART_HASH) { | ||||
|     // do nothing. column or oracle mode hash. | ||||
|   } else if (part_expr->type_ == T_OP_ROW) { | ||||
|     for (int64_t i = 0; i < part_expr->arg_cnt_ && !has_virtual_column; i++) { | ||||
|       if (part_expr->args_[i]->type_ != T_REF_COLUMN) { | ||||
|         has_virtual_column = true; | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     has_virtual_column = true; | ||||
|   } | ||||
|  | ||||
|   return has_virtual_column; | ||||
| } | ||||
|  | ||||
| int ObSQLUtils::get_partition_range(ObObj *start_row_key, | ||||
|                                     ObObj *end_row_key, | ||||
|                                     ObObj *function_obj, | ||||
| @ -2769,56 +2789,183 @@ int ObSQLUtils::get_partition_range(ObObj *start_row_key, | ||||
|                                     int64_t range_key_count, | ||||
|                                     uint64_t table_id, | ||||
|                                     ObEvalCtx &eval_ctx, | ||||
|                                     common::ObNewRange &part_range) | ||||
|                                     common::ObNewRange &part_range, | ||||
|                                     ObArenaAllocator &allocator) | ||||
| { | ||||
| 	int ret = OB_SUCCESS; | ||||
|   if (part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_RANGE_COLUMNS || | ||||
|       part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_LIST_COLUMNS || | ||||
|       OB_ISNULL(part_expr)) { | ||||
|     part_range.table_id_ = table_id; | ||||
|     part_range.start_key_.assign(start_row_key, range_key_count); | ||||
|     part_range.end_key_.assign(end_row_key, range_key_count); | ||||
|     part_range.border_flag_.set_inclusive_start(); | ||||
|     part_range.border_flag_.set_inclusive_end(); | ||||
|     if (part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_HASH) { | ||||
|       // hash partition and part_expr.is_empty(), should not reach here | ||||
|       LOG_TRACE("get empty part_expr"); | ||||
|       ObNewRow start_row; | ||||
|       start_row.cells_ = start_row_key; | ||||
|       start_row.count_ = range_key_count; | ||||
|       ObNewRow end_row; | ||||
|       end_row.cells_ = end_row_key; | ||||
|       end_row.count_ = range_key_count; | ||||
|       if (OB_FAIL(ObSQLUtils::revise_hash_part_object(start_row_key[0], start_row, true, part_type))) { | ||||
|         LOG_WARN("failed to revise hash part object", K(ret)); | ||||
|       } else if (OB_FAIL(ObSQLUtils::revise_hash_part_object(end_row_key[0], end_row, true, part_type))) { | ||||
|         LOG_WARN("failed to revise hash part object", K(ret)); | ||||
|       } else { /*do nothing*/ } | ||||
|     } | ||||
|   } else { | ||||
|     LOG_TRACE("get non empty part_expr"); | ||||
|     ObNewRow dummy_row; | ||||
|     ObDatum *datum = NULL; | ||||
|     if (OB_FAIL(part_expr->eval(eval_ctx, datum))) { | ||||
|       LOG_WARN("failed to calc expr", K(ret)); | ||||
|     } else if (OB_FAIL(datum->to_obj(*function_obj, | ||||
|                                      part_expr->obj_meta_, | ||||
|                                      part_expr->obj_datum_map_))) { | ||||
|       LOG_WARN("convert datum to obj failed", K(ret)); | ||||
|     } else if (FALSE_IT(dummy_row.cells_ = function_obj)) { | ||||
|     } else if (FALSE_IT(dummy_row.count_ = 1)) { | ||||
|     } else if (part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_HASH && | ||||
|         OB_FAIL(ObSQLUtils::revise_hash_part_object(*function_obj, dummy_row, false, part_type))) { | ||||
|       LOG_WARN("failed to revise hash partition object", K(ret)); | ||||
|   int ret = OB_SUCCESS; | ||||
|   bool has_virtual_column = part_expr_has_virtual_column(part_expr); | ||||
|   // If there is a virtual generated column in part_expr, this logic cannot be used | ||||
|   if (!has_virtual_column) { | ||||
|     // opt logic. no need evalute. | ||||
|     if ((part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_RANGE_COLUMNS || | ||||
|         part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_LIST_COLUMNS)) { | ||||
|       if (OB_FAIL(get_range_for_vector( | ||||
|                                     start_row_key, | ||||
|                                     end_row_key, | ||||
|                                     range_key_count, | ||||
|                                     table_id, | ||||
|                                     part_range))) { | ||||
|         LOG_WARN("get partition range in opt failed", K(ret)); | ||||
|       } | ||||
|       LOG_DEBUG("opt logic", K(part_range), KPC(part_expr)); | ||||
|     } else { | ||||
|       part_range.table_id_ = table_id; | ||||
|       part_range.start_key_.assign(function_obj, 1); | ||||
|       part_range.end_key_.assign(function_obj, 1); | ||||
|       part_range.border_flag_.set_inclusive_start(); | ||||
|       part_range.border_flag_.set_inclusive_end(); | ||||
|       // part expr only have one column. | ||||
|       if (OB_FAIL(get_range_for_scalar( | ||||
|                                     start_row_key, | ||||
|                                     end_row_key, | ||||
|                                     function_obj, | ||||
|                                     part_type, | ||||
|                                     part_expr, | ||||
|                                     range_key_count, | ||||
|                                     table_id, | ||||
|                                     eval_ctx, | ||||
|                                     part_range, | ||||
|                                     allocator))) { | ||||
|         LOG_WARN("get partition range in part expr for scalar failed", K(ret)); | ||||
|       } | ||||
|     } | ||||
|   // conclude virtual generated column & part expr not NULL | ||||
|   } else { | ||||
|     if (OB_FAIL(get_range_for_scalar( | ||||
|                                     start_row_key, | ||||
|                                     end_row_key, | ||||
|                                     function_obj, | ||||
|                                     part_type, | ||||
|                                     part_expr, | ||||
|                                     range_key_count, | ||||
|                                     table_id, | ||||
|                                     eval_ctx, | ||||
|                                     part_range, | ||||
|                                     allocator))) { | ||||
|       LOG_WARN("get partition range in part expr for scalar failed", K(ret)); | ||||
|     } | ||||
|   } | ||||
| 	return ret; | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| int ObSQLUtils::get_range_for_scalar(ObObj *start_row_key, | ||||
|                                     ObObj *end_row_key, | ||||
|                                     ObObj *function_obj, | ||||
|                                     const share::schema::ObPartitionFuncType part_type, | ||||
|                                     const ObExpr *part_expr, | ||||
|                                     int64_t range_key_count, | ||||
|                                     uint64_t table_id, | ||||
|                                     ObEvalCtx &eval_ctx, | ||||
|                                     common::ObNewRange &part_range, | ||||
|                                     ObArenaAllocator &allocator) | ||||
| { | ||||
|   int ret = OB_SUCCESS; | ||||
|   ObObj *tmp_start_row_key = NULL; | ||||
|   ObObj *tmp_end_row_key = NULL; | ||||
|   int64_t count = 0; | ||||
|   // only range column & list column | ||||
|   // hash column mode type is T_FUN_SYS_PART_HASH | ||||
|   if (part_expr->type_ == T_OP_ROW) { | ||||
|     count = range_key_count; | ||||
|     if (OB_ISNULL(tmp_start_row_key = static_cast<ObObj*>(allocator.alloc( | ||||
|       sizeof(ObObj) * range_key_count)))) { | ||||
|       ret = OB_ALLOCATE_MEMORY_FAILED; | ||||
|       LOG_WARN("allocate memory for start_obj failed", K(ret)); | ||||
|     } else if (OB_ISNULL(tmp_end_row_key = static_cast<ObObj*>(allocator.alloc( | ||||
|       sizeof(ObObj) * range_key_count)))) { | ||||
|       ret = OB_ALLOCATE_MEMORY_FAILED; | ||||
|       LOG_WARN("allocate memory for start_obj failed", K(ret)); | ||||
|     } else { | ||||
|       for (int64_t i = 0; i < part_expr->arg_cnt_ && OB_SUCC(ret); i++) { | ||||
|         if (part_expr->args_[i]->type_ == T_REF_COLUMN) { | ||||
|           tmp_start_row_key[i] = start_row_key[i]; | ||||
|           tmp_end_row_key[i] = end_row_key[i]; | ||||
|         } else { | ||||
|           ObExpr *part_expr_arg = NULL; | ||||
|           part_expr_arg = part_expr->args_[i]; | ||||
|         // virtual generated column scene | ||||
|           if (OB_FAIL(get_partition_range_common( | ||||
|                                     function_obj, | ||||
|                                     part_type, | ||||
|                                     part_expr_arg, | ||||
|                                     eval_ctx))) { | ||||
|             LOG_WARN("get partition range common failed", K(ret)); | ||||
|           } else { | ||||
|             tmp_start_row_key[i] = *function_obj; | ||||
|             tmp_end_row_key[i] = *function_obj; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   // one column or hash columns oracle mode. | ||||
|   } else { | ||||
|     count = 1; | ||||
|     if (OB_ISNULL(tmp_start_row_key = static_cast<ObObj*>(allocator.alloc( | ||||
|       sizeof(ObObj) * 1)))) { | ||||
|       ret = OB_ALLOCATE_MEMORY_FAILED; | ||||
|       LOG_WARN("allocate memory for start_obj failed", K(ret)); | ||||
|     } else if (OB_ISNULL(tmp_end_row_key = static_cast<ObObj*>(allocator.alloc( | ||||
|       sizeof(ObObj) * 1)))) { | ||||
|       ret = OB_ALLOCATE_MEMORY_FAILED; | ||||
|       LOG_WARN("allocate memory for start_obj failed", K(ret)); | ||||
|     } else if (OB_FAIL(get_partition_range_common( | ||||
|                                     function_obj, | ||||
|                                     part_type, | ||||
|                                     part_expr, | ||||
|                                     eval_ctx))) { | ||||
|       LOG_WARN("get partition range common failed", K(ret)); | ||||
|     } else { | ||||
|       tmp_start_row_key[0] = *function_obj; | ||||
|       tmp_end_row_key[0] = *function_obj; | ||||
|     } | ||||
|   } | ||||
|   if (OB_SUCC(ret)) { | ||||
|     part_range.table_id_ = table_id; | ||||
|     part_range.start_key_.assign(tmp_start_row_key, count); | ||||
|     part_range.end_key_.assign(tmp_end_row_key, count); | ||||
|     part_range.border_flag_.set_inclusive_start(); | ||||
|     part_range.border_flag_.set_inclusive_end(); | ||||
|   } | ||||
|   LOG_DEBUG("get partition range", K(ret), K(part_range), KPC(part_expr), K(count)); | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| int ObSQLUtils::get_range_for_vector(ObObj *start_row_key, | ||||
|                                     ObObj *end_row_key, | ||||
|                                     int64_t range_key_count, | ||||
|                                     uint64_t table_id, | ||||
|                                     common::ObNewRange &part_range) | ||||
| { | ||||
|   int ret = OB_SUCCESS; | ||||
|   part_range.table_id_ = table_id; | ||||
|   part_range.start_key_.assign(start_row_key, range_key_count); | ||||
|   part_range.end_key_.assign(end_row_key, range_key_count); | ||||
|   part_range.border_flag_.set_inclusive_start(); | ||||
|   part_range.border_flag_.set_inclusive_end(); | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| int ObSQLUtils::get_partition_range_common( | ||||
|                                     ObObj *function_obj, | ||||
|                                     const share::schema::ObPartitionFuncType part_type, | ||||
|                                     const ObExpr *part_expr, | ||||
|                                     ObEvalCtx &eval_ctx) | ||||
| { | ||||
|   int ret = OB_SUCCESS; | ||||
|   ObNewRow dummy_row; | ||||
|   ObDatum *datum = NULL; | ||||
|   if (OB_FAIL(part_expr->eval(eval_ctx, datum))) { | ||||
|     LOG_WARN("failed to calc expr", K(ret)); | ||||
|   } else if (OB_FAIL(datum->to_obj(*function_obj, | ||||
|                                   part_expr->obj_meta_, | ||||
|                                   part_expr->obj_datum_map_))) { | ||||
|     LOG_WARN("convert datum to obj failed", K(ret)); | ||||
|   } else if (FALSE_IT(dummy_row.cells_ = function_obj)) { | ||||
|   } else if (FALSE_IT(dummy_row.count_ = 1)) { | ||||
|   } else if (part_type == share::schema::ObPartitionFuncType::PARTITION_FUNC_TYPE_HASH && | ||||
|       OB_FAIL(ObSQLUtils::revise_hash_part_object(*function_obj, dummy_row, false, part_type))) { | ||||
|     LOG_WARN("failed to revise hash partition object", K(ret)); | ||||
|   } | ||||
|   LOG_DEBUG("get_partition_range_common", K(ret), KPC(part_expr)); | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| int ObSQLUtils::revise_hash_part_object(common::ObObj &obj, | ||||
|  | ||||
| @ -485,7 +485,8 @@ public: | ||||
|                                  int64_t range_key_count, | ||||
|                                  uint64_t table_id, | ||||
|                                  ObEvalCtx &eval_ctx, | ||||
|                                  common::ObNewRange &partition_range); | ||||
|                                  common::ObNewRange &partition_range, | ||||
|                                  ObArenaAllocator &allocator); | ||||
|  | ||||
|   static int revise_hash_part_object(common::ObObj &obj, | ||||
|                                      const ObNewRow &row, | ||||
| @ -698,6 +699,28 @@ public: | ||||
|                               const bool check_for_path_char, const int64_t max_ident_len); | ||||
| private: | ||||
|   static bool check_mysql50_prefix(common::ObString &db_name); | ||||
|   static bool part_expr_has_virtual_column(const ObExpr *part_expr); | ||||
|   static int get_range_for_vector( | ||||
|                                   ObObj *start_row_key, | ||||
|                                   ObObj *end_row_key, | ||||
|                                   int64_t range_key_count, | ||||
|                                   uint64_t table_id, | ||||
|                                   common::ObNewRange &part_range); | ||||
|   static int get_partition_range_common( | ||||
|                                     ObObj *function_obj, | ||||
|                                     const share::schema::ObPartitionFuncType part_type, | ||||
|                                     const ObExpr *part_expr, | ||||
|                                     ObEvalCtx &eval_ctx); | ||||
|   static int get_range_for_scalar(ObObj *start_row_key, | ||||
|                                   ObObj *end_row_key, | ||||
|                                   ObObj *function_obj, | ||||
|                                   const share::schema::ObPartitionFuncType part_type, | ||||
|                                   const ObExpr *part_expr, | ||||
|                                   int64_t range_key_count, | ||||
|                                   uint64_t table_id, | ||||
|                                   ObEvalCtx &eval_ctx, | ||||
|                                   common::ObNewRange &part_range, | ||||
|                                   ObArenaAllocator &allocator); | ||||
|   struct SessionInfoCtx | ||||
|   { | ||||
|     common::ObCollationType collation_type_; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 yaojing624
					yaojing624