311 lines
12 KiB
C++
311 lines
12 KiB
C++
/**
|
|
* Copyright (c) 2021 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v2 for more details.
|
|
* This file contains implementation for lob_access_utils.
|
|
*/
|
|
|
|
#ifndef OCEANBASE_SHARE_OB_LOB_ACCESS_UTILS_
|
|
#define OCEANBASE_SHARE_OB_LOB_ACCESS_UTILS_
|
|
|
|
#include "share/ob_errno.h"
|
|
#include "common/object/ob_object.h"
|
|
#include "common/object/ob_obj_type.h"
|
|
#include "sql/session/ob_basic_session_info.h"
|
|
#include "storage/lob/ob_lob_manager.h"
|
|
|
|
namespace oceanbase
|
|
{
|
|
namespace common
|
|
{
|
|
// 1. This function is used to control plan generation or lob output when execution.
|
|
// 2. Should not use it this to judge whether the inputs having or not having lob header!
|
|
// Because both format may exist in one executing routing
|
|
OB_INLINE bool ob_enable_lob_locator_v2()
|
|
{
|
|
const uint64_t ob_cluster_ver = GET_MIN_CLUSTER_VERSION();
|
|
bool bret = ob_cluster_ver > CLUSTER_VERSION_4_0_0_0;
|
|
return bret;
|
|
}
|
|
|
|
OB_INLINE bool ob_enable_datum_cast_debug_log()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Notice: cannot support obobj funcs/compare (in lib dir)
|
|
enum ObTextStringIterState
|
|
{
|
|
TEXTSTRING_ITER_INVALID = 0,
|
|
TEXTSTRING_ITER_INIT = 1,
|
|
TEXTSTRING_ITER_NEXT = 2,
|
|
TEXTSTRING_ITER_END = 3
|
|
};
|
|
|
|
// iterator context for lob type access
|
|
struct ObLobTextIterCtx
|
|
{
|
|
static const uint32_t OB_LOB_ITER_DEFAULT_BUFFER_LEN = 2 * 1024 * 1024; // 2M bytes
|
|
|
|
ObLobTextIterCtx(ObLobLocatorV2 &locator, const sql::ObBasicSessionInfo *session,
|
|
ObIAllocator *allocator = NULL, uint32_t buffer_len = OB_LOB_ITER_DEFAULT_BUFFER_LEN) :
|
|
alloc_(allocator), session_(session), buff_(NULL), buff_byte_len_(buffer_len), start_offset_(0),
|
|
total_access_len_(0), total_byte_len_(0), content_byte_len_(0), content_len_(0),
|
|
reserved_byte_len_(0), reserved_len_(0), accessed_byte_len_(0), accessed_len_(0),
|
|
last_accessed_byte_len_(0), last_accessed_len_(0), iter_count_(0), is_cloned_temporary_(false),
|
|
is_backward_(false), locator_(locator), lob_query_iter_(NULL)
|
|
{}
|
|
|
|
TO_STRING_KV(KP_(alloc), KP_(session), KP_(buff), K_(buff_byte_len), K_(start_offset), K_(total_access_len),
|
|
K_(content_byte_len), K_(content_len), K_(reserved_byte_len), K_(reserved_len),
|
|
K_(accessed_byte_len), K_(accessed_len),
|
|
K_(last_accessed_byte_len), K_(last_accessed_len), K_(iter_count),
|
|
K_(is_cloned_temporary), K_(is_backward), K_(locator), KP_(lob_query_iter));
|
|
|
|
void init(bool is_clone = false);
|
|
void reuse(); // reuse this ctx for access the same lob again
|
|
OB_INLINE void unset_clone() { is_cloned_temporary_ = false; }
|
|
|
|
// member variables
|
|
ObIAllocator *alloc_;
|
|
const sql::ObBasicSessionInfo *session_;
|
|
char *buff_; // buffer for reading next block;
|
|
uint32_t buff_byte_len_; // buffer byte length, set to default size if user input is too small
|
|
uint64_t start_offset_; // lob start access offset only used when first calling get next block
|
|
int64_t total_access_len_; // total char length for reading, will access full lob if it is 0
|
|
int64_t total_byte_len_;
|
|
|
|
// avaliable content length start from buff_;
|
|
uint32_t content_byte_len_; // content byte length
|
|
uint32_t content_len_; // content char length
|
|
|
|
// reserved len from buff_, when calling get next block, tail of last content will be reserved
|
|
// in buff to reserved_byte_len, new content will be put from buff + reserved_byte_len_ to end of buffer
|
|
uint32_t reserved_byte_len_; // reserved byte length from header
|
|
uint32_t reserved_len_; // reserved char length from header
|
|
|
|
// accessed total len by get next row
|
|
uint32_t accessed_byte_len_; // total accessed byte_len_
|
|
uint32_t accessed_len_; // total accessed char_len_
|
|
|
|
// accessed total len by get next row last time
|
|
uint32_t last_accessed_byte_len_; // total accessed byte length before current get next block
|
|
uint32_t last_accessed_len_; // total accessed char length before current get next block
|
|
uint32_t iter_count_;
|
|
|
|
bool is_cloned_temporary_; // locator_ is a cloned local temporary lob
|
|
bool is_backward_;
|
|
|
|
ObLobLocatorV2 locator_;
|
|
ObLobQueryIter *lob_query_iter_;
|
|
};
|
|
|
|
// wrapper class to handle string/text type input
|
|
class ObTextStringIter
|
|
{
|
|
public:
|
|
static const uint32_t DEAFULT_LOB_PREFIX_CHAR_LEN = 1000;
|
|
static const uint32_t MAX_CHAR_MULTIPLIER = 4;
|
|
ObTextStringIter(ObObjType type, ObCollationType cs_type, const ObString &datum_str,
|
|
bool has_lob_header) :
|
|
type_(type), cs_type_(cs_type), is_init_(false), is_lob_(false), is_outrow_(false),
|
|
has_lob_header_(has_lob_header), state_(TEXTSTRING_ITER_INVALID), datum_str_(datum_str),
|
|
err_ret_(OB_SUCCESS)
|
|
{
|
|
if (is_lob_storage(type)) {
|
|
validate_has_lob_header(has_lob_header_);
|
|
}
|
|
}
|
|
|
|
ObTextStringIter(const ObObj &obj) :
|
|
type_(obj.get_type()), cs_type_(obj.get_collation_type()), is_init_(false), is_lob_(false),
|
|
is_outrow_(false), has_lob_header_(obj.has_lob_header()), state_(TEXTSTRING_ITER_INVALID),
|
|
datum_str_(obj.get_string()), err_ret_(OB_SUCCESS)
|
|
{
|
|
if (is_lob_storage(obj.get_type())) {
|
|
validate_has_lob_header(has_lob_header_);
|
|
}
|
|
}
|
|
~ObTextStringIter();
|
|
|
|
TO_STRING_KV(K_(type), K_(cs_type), K_(is_init), K_(is_lob), K_(is_outrow),
|
|
K_(state), K(datum_str_), KP_(ctx), K_(err_ret));
|
|
|
|
int init(uint32_t buffer_len,
|
|
const sql::ObBasicSessionInfo *session = NULL,
|
|
ObIAllocator *allocator = NULL,
|
|
bool clone_remote = false);
|
|
|
|
ObTextStringIterState get_next_block(ObString &str);
|
|
|
|
int get_current_block(ObString &str);
|
|
|
|
int get_full_data(ObString &data_str, ObIAllocator *allocator = nullptr);
|
|
|
|
int get_inrow_or_outrow_prefix_data(ObString &data_str,
|
|
uint32_t prefix_char_len = DEAFULT_LOB_PREFIX_CHAR_LEN);
|
|
|
|
void reset();
|
|
void set_start_offset(uint64_t offset);
|
|
|
|
void set_access_len(int64_t char_len); // total read len of outrow lob
|
|
void set_reserved_len(uint32_t reserved_len);
|
|
void set_reserved_byte_len(uint32_t reserved_byte_len);
|
|
void reset_reserve_len();
|
|
void set_backward();
|
|
void set_forward();
|
|
|
|
uint64_t get_start_offset();
|
|
uint32_t get_last_accessed_len();
|
|
uint32_t get_last_accessed_byte_len();
|
|
uint32_t get_accessed_len();
|
|
uint32_t get_accessed_byte_len();
|
|
int get_inner_ret() { return err_ret_; }
|
|
bool is_outrow_lob() { return is_outrow_; };
|
|
int get_byte_len(int64_t &byte_len);
|
|
int get_char_len(int64_t &char_length);
|
|
uint32_t get_iter_count();
|
|
uint32_t get_reserved_char_len();
|
|
uint32_t get_reserved_byte_len();
|
|
static int append_outrow_lob_fulldata(ObObj &obj,
|
|
const sql::ObBasicSessionInfo *session,
|
|
ObIAllocator &allocator);
|
|
static int convert_outrow_lob_to_inrow_templob(const ObObj &in_obj,
|
|
ObObj &out_obj,
|
|
const sql::ObBasicSessionInfo *session,
|
|
ObIAllocator *allocator,
|
|
bool allow_persist_inrow = false,
|
|
bool need_deep_copy = false);
|
|
|
|
private:
|
|
int get_outrow_lob_full_data(ObIAllocator *allocator = nullptr);
|
|
int get_first_block(ObString &str);
|
|
int get_next_block_inner(ObString &str);
|
|
int get_outrow_prefix_data(uint32_t prefix_char_len);
|
|
int reserve_data();
|
|
int reserve_byte_data();
|
|
OB_INLINE bool is_valid_for_config()
|
|
{
|
|
return (is_init_ && is_outrow_ && has_lob_header_
|
|
&& state_ == TEXTSTRING_ITER_INIT && OB_NOT_NULL(ctx_));
|
|
}
|
|
private:
|
|
ObObjType type_;
|
|
ObCollationType cs_type_;
|
|
uint32_t is_init_ : 1;
|
|
uint32_t is_lob_ : 1;
|
|
uint32_t is_outrow_ : 1;
|
|
uint32_t has_lob_header_ : 1;// 4.0 lob compatibility
|
|
uint32_t reserved : 28;
|
|
ObTextStringIterState state_;
|
|
const ObString datum_str_;
|
|
ObLobTextIterCtx *ctx_;
|
|
int err_ret_;
|
|
};
|
|
|
|
// wrapper class to handle templob output(including string types)
|
|
class ObTextStringResult
|
|
{
|
|
public:
|
|
ObTextStringResult(const ObObjType type, bool has_lob_header, ObIAllocator *allocator) :
|
|
type_(type), buffer_(NULL), buff_len_(0), pos_(0), is_outrow_templob_(false),
|
|
has_lob_header_(has_lob_header), is_init_(false), alloc_(allocator)
|
|
{
|
|
if (is_lob_storage(type)) {
|
|
validate_has_lob_header(has_lob_header_);
|
|
}
|
|
}
|
|
~ObTextStringResult(){};
|
|
|
|
TO_STRING_KV(K_(type), KP_(buffer), K_(buff_len), K_(pos), K_(is_outrow_templob),
|
|
K_(has_lob_header), K_(is_init), KP_(alloc));
|
|
|
|
static const uint32_t MAX_TMP_LOB_HEADER_LEN = 1 * 1024;
|
|
|
|
// create resource by expr.datum_.type_ and has_lob_header_
|
|
// inrow lobs: create medmory buffer with expr.get_str_res_mem, or allocator in cast params;
|
|
// outrow lobs: create memory for locator, and tmp file for outrow data (not implemented)
|
|
// support user assigned allocator
|
|
// Notice:
|
|
// 1. all lobs created by this class should be temp lobs
|
|
// 2. if has_lob_header_ is false, the text result should be 4.0 compatible
|
|
int init(const int64_t res_len, ObIAllocator *allocator = NULL);
|
|
|
|
// copy existent loc to result
|
|
int copy(const ObLobLocatorV2 *loc);
|
|
|
|
// append (copy) result to buffer(file), change pos_
|
|
int append(const char *buffer, int64_t len);
|
|
OB_INLINE int append(const ObString &str)
|
|
{
|
|
return append(str.ptr(), str.length());
|
|
}
|
|
|
|
// overwrite exist result buffer(file), not change pos_
|
|
int write(const char *buffer, int64_t pos, int64_t len);
|
|
|
|
// overwrite exist result buffer(file), not change pos_
|
|
int fill(int64_t pos, int c, int64_t len);
|
|
|
|
// move pos_ to pos_ + offset
|
|
int lseek(int64_t offset, int state);
|
|
|
|
// expose buffer for user function, lseek should be called after write
|
|
int get_reserved_buffer(char *&empty_start, int64_t &empty_len);
|
|
|
|
bool is_init() { return is_init_; };
|
|
|
|
OB_INLINE void get_result_buffer(ObString &buf_str) { buf_str.assign(buffer_, pos_); }
|
|
OB_INLINE void set_has_lob_header(bool has_header) { has_lob_header_ = has_header; }
|
|
OB_INLINE bool has_lob_header() { return (is_lob_storage(type_)) && has_lob_header_; }
|
|
static int ob_convert_obj_temporay_lob(ObObj &obj, ObIAllocator &allocator);
|
|
static int ob_convert_datum_temporay_lob(ObDatum &datum,
|
|
const ObObjMeta &in_obj_meta,
|
|
const ObObjMeta &out_obj_meta,
|
|
ObIAllocator &allocator);
|
|
|
|
protected:
|
|
int calc_buffer_len(const int64_t res_len);
|
|
int fill_temp_lob_header(const int64_t res_len);
|
|
|
|
protected:
|
|
const ObObjType type_;
|
|
char *buffer_;
|
|
int64_t buff_len_;
|
|
int64_t pos_;
|
|
bool is_outrow_templob_;
|
|
bool has_lob_header_;
|
|
bool is_init_;
|
|
ObIAllocator *alloc_;
|
|
};
|
|
|
|
OB_INLINE bool ob_is_empty_lob(ObObjType type, const ObDatum &datum, bool has_lob_header)
|
|
{
|
|
bool bret = false;
|
|
if (common::ob_is_text_tc(type)) {
|
|
common::ObLobLocatorV2 loc(datum.get_string(), has_lob_header);
|
|
bret = loc.is_empty_lob();
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
OB_INLINE bool ob_is_empty_lob(const ObObj &obj)
|
|
{
|
|
bool bret = false;
|
|
if (common::ob_is_text_tc(obj.get_type())) {
|
|
common::ObLobLocatorV2 loc(obj.get_string(), obj.has_lob_header());
|
|
bret = loc.is_empty_lob();
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
} // end namespace common
|
|
} // end namespace oceanbase
|
|
|
|
#endif // OCEANBASE_SHARE_OB_LOB_ACCESS_UTILS_
|