patch 4.0
This commit is contained in:
@ -15,25 +15,73 @@
|
||||
|
||||
#include "sql/engine/expr/ob_expr_operator.h"
|
||||
|
||||
namespace oceanbase {
|
||||
namespace sql {
|
||||
class ObExprLike : public ObFuncExprOperator {
|
||||
class ObExprLikeContext : public ObExprOperatorCtx {
|
||||
namespace oceanbase
|
||||
{
|
||||
namespace sql
|
||||
{
|
||||
enum INSTR_MODE
|
||||
{
|
||||
START_WITH_PERCENT_SIGN = 0, //"%%a%b",etc
|
||||
START_END_WITH_PERCENT_SIGN = 1, //"%abc%%dd%",etc
|
||||
END_WITH_PERCENT_SIGN = 2,//"aa%%%%%%",etc
|
||||
MIDDLE_PERCENT_SIGN = 3, //"ab%cde",etc
|
||||
ALL_PERCENT_SIGN = 4, //"%%",etc
|
||||
INVALID_INSTR_MODE = 5
|
||||
};
|
||||
|
||||
class ObExprLike : public ObFuncExprOperator
|
||||
{
|
||||
struct InstrInfo
|
||||
{
|
||||
InstrInfo() :
|
||||
allocator_(NULL),
|
||||
instr_mode_(INVALID_INSTR_MODE),
|
||||
instr_starts_(NULL),
|
||||
instr_lengths_(NULL),
|
||||
instr_total_length_(0),
|
||||
instr_cnt_(0),
|
||||
instr_info_buf_size_(0),
|
||||
instr_buf_(NULL),
|
||||
instr_buf_length_(0)
|
||||
{ }
|
||||
|
||||
int record_pattern(char *&pattern_buf, const common::ObString &pattern);
|
||||
OB_INLINE void set_allocator(common::ObIAllocator &allocator) { allocator_ = &allocator; }
|
||||
int add_instr_info(const char *start, const uint32_t length);
|
||||
bool empty() const { return 0 == instr_cnt_; }
|
||||
void reuse()
|
||||
{
|
||||
instr_mode_ = INVALID_INSTR_MODE;
|
||||
instr_total_length_ = 0;
|
||||
instr_cnt_ = 0;
|
||||
}
|
||||
TO_STRING_KV(K_(instr_mode), K_(instr_total_length), K_(instr_cnt),
|
||||
K(static_cast<void *>(instr_buf_)),
|
||||
K(common::ObArrayWrap<uint32_t>(instr_lengths_, instr_cnt_)));
|
||||
|
||||
common::ObIAllocator *allocator_;
|
||||
INSTR_MODE instr_mode_;
|
||||
|
||||
// for pattern '%abc%ef%efga%1234', instr_cnt_ is 4;
|
||||
// instr_start_ record address of 'abc', 'ef', 'efga' and '1234';
|
||||
// instr_lengths_ is [3, 2, 4, 4].
|
||||
const char **instr_starts_;
|
||||
uint32_t *instr_lengths_;
|
||||
uint32_t instr_total_length_;
|
||||
uint32_t instr_cnt_;
|
||||
// current buf size of instr_starts_ and instr_lengths_.
|
||||
uint32_t instr_info_buf_size_;
|
||||
|
||||
char *instr_buf_;
|
||||
uint32_t instr_buf_length_;
|
||||
};
|
||||
class ObExprLikeContext : public ObExprOperatorCtx
|
||||
{
|
||||
public:
|
||||
enum INSTR_MODE {
|
||||
START_WITH_PERCENT_SIGN = 0, //"%%a",etc
|
||||
START_END_WITH_PERCENT_SIGN = 1, //"%abc%%",etc
|
||||
END_WITH_PERCENT_SIGN = 2, //"aa%%%%%%",etc
|
||||
INVALID_INSTR_MODE = 3
|
||||
};
|
||||
// member functions
|
||||
//member functions
|
||||
ObExprLikeContext()
|
||||
: ObExprOperatorCtx(),
|
||||
instr_mode_(INVALID_INSTR_MODE),
|
||||
instr_start_(NULL),
|
||||
instr_length_(0),
|
||||
instr_buf_(NULL),
|
||||
instr_buf_length_(0),
|
||||
instr_info_(),
|
||||
is_analyzed_(false),
|
||||
is_checked_(false),
|
||||
last_pattern_(NULL),
|
||||
@ -44,141 +92,146 @@ class ObExprLike : public ObFuncExprOperator {
|
||||
escape_buf_len_(0),
|
||||
same_as_last(false)
|
||||
{}
|
||||
OB_INLINE void reset()
|
||||
{
|
||||
instr_mode_ = INVALID_INSTR_MODE;
|
||||
instr_start_ = NULL;
|
||||
instr_length_ = 0;
|
||||
is_analyzed_ = false;
|
||||
is_checked_ = false;
|
||||
OB_INLINE bool is_analyzed() const {return is_analyzed_;}
|
||||
OB_INLINE void set_analyzed() {is_analyzed_ = true;}
|
||||
OB_INLINE bool is_instr_mode() const {
|
||||
return instr_info_.instr_mode_ >= 0 && instr_info_.instr_mode_ < INVALID_INSTR_MODE;
|
||||
}
|
||||
OB_INLINE bool is_analyzed() const
|
||||
{
|
||||
return is_analyzed_;
|
||||
}
|
||||
OB_INLINE void set_analyzed()
|
||||
{
|
||||
is_analyzed_ = true;
|
||||
}
|
||||
OB_INLINE bool is_instr_mode() const
|
||||
{
|
||||
return instr_mode_ >= 0 && instr_mode_ < INVALID_INSTR_MODE;
|
||||
}
|
||||
OB_INLINE void set_checked()
|
||||
{
|
||||
is_checked_ = true;
|
||||
}
|
||||
OB_INLINE bool is_checked() const
|
||||
{
|
||||
return is_checked_;
|
||||
}
|
||||
TO_STRING_KV(K_(instr_mode), K_(instr_length), K_(is_analyzed));
|
||||
// data members
|
||||
INSTR_MODE instr_mode_;
|
||||
const char* instr_start_;
|
||||
uint32_t instr_length_;
|
||||
char* instr_buf_;
|
||||
uint32_t instr_buf_length_;
|
||||
OB_INLINE void set_checked() { is_checked_ = true; }
|
||||
OB_INLINE bool is_checked() const { return is_checked_; }
|
||||
OB_INLINE INSTR_MODE get_instr_mode() { return instr_info_.instr_mode_; }
|
||||
OB_INLINE void set_instr_mode(INSTR_MODE mode) { instr_info_.instr_mode_ = mode; }
|
||||
TO_STRING_KV(K_(instr_info), K_(is_analyzed));
|
||||
InstrInfo instr_info_;
|
||||
bool is_analyzed_;
|
||||
bool is_checked_;
|
||||
char* last_pattern_;
|
||||
// record last pattern and escape.
|
||||
char *last_pattern_;
|
||||
uint32_t last_pattern_len_;
|
||||
uint32_t pattern_buf_len_;
|
||||
char* last_escape_;
|
||||
char *last_escape_;
|
||||
uint32_t last_escape_len_;
|
||||
uint32_t escape_buf_len_;
|
||||
bool same_as_last;
|
||||
};
|
||||
OB_UNIS_VERSION_V(1);
|
||||
|
||||
public:
|
||||
explicit ObExprLike(common::ObIAllocator& alloc);
|
||||
explicit ObExprLike(common::ObIAllocator &alloc);
|
||||
virtual ~ObExprLike();
|
||||
virtual int calc_result_type3(ObExprResType& type, ObExprResType& type1, ObExprResType& type2, ObExprResType& type3,
|
||||
common::ObExprTypeCtx& type_ctx) const override;
|
||||
virtual int calc_result3(common::ObObj& result, const common::ObObj& obj, const common::ObObj& pattern,
|
||||
const common::ObObj& escape, common::ObExprCtx& expr_ctx) const override;
|
||||
static int calc(common::ObObj& result, common::ObCollationType coll_type, const common::ObObj& obj,
|
||||
const common::ObObj& pattern, const common::ObObj& escape, common::ObExprCtx& expr_ctx,
|
||||
const bool is_going_optimization, const uint64_t like_id, const bool check_optimization);
|
||||
virtual int calc_result_type3(ObExprResType &type,
|
||||
ObExprResType &type1,
|
||||
ObExprResType &type2,
|
||||
ObExprResType &type3,
|
||||
common::ObExprTypeCtx &type_ctx) const;
|
||||
template <bool NullCheck, bool UseInstrMode, INSTR_MODE InstrMode>
|
||||
static int match_text_batch(BATCH_EVAL_FUNC_ARG_DECL,
|
||||
const common::ObCollationType coll_type,
|
||||
const int32_t escape_wc,
|
||||
const common::ObString &pattern_val,
|
||||
const InstrInfo instr_info);
|
||||
template <bool percent_sign_start, bool percent_sign_end>
|
||||
static int64_t match_with_instr_mode(const common::ObString &text_val,
|
||||
const InstrInfo instr_info);
|
||||
template <typename T>
|
||||
static int calc_with_non_instr_mode(T& result, const common::ObCollationType coll_type,
|
||||
const common::ObCollationType escape_coll, const common::ObString& text_val, const common::ObString& pattern_val,
|
||||
const common::ObString& escape_val);
|
||||
int assign(const ObExprOperator& other) override;
|
||||
OB_INLINE bool is_pattern_literal() const
|
||||
{
|
||||
return is_pattern_literal_;
|
||||
}
|
||||
OB_INLINE void set_pattern_is_literal(bool b)
|
||||
{
|
||||
is_pattern_literal_ = b;
|
||||
}
|
||||
OB_INLINE bool is_text_literal() const
|
||||
{
|
||||
return is_text_literal_;
|
||||
}
|
||||
OB_INLINE void set_text_is_literal(bool b)
|
||||
{
|
||||
is_text_literal_ = b;
|
||||
}
|
||||
OB_INLINE bool is_escape_literal() const
|
||||
{
|
||||
return is_escape_literal_;
|
||||
}
|
||||
OB_INLINE void set_escape_is_literal(bool b)
|
||||
{
|
||||
is_escape_literal_ = b;
|
||||
}
|
||||
virtual int cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const override;
|
||||
virtual bool need_rt_ctx() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static int like_varchar(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum);
|
||||
static int calc_with_non_instr_mode(T &result,
|
||||
const common::ObCollationType coll_type,
|
||||
const common::ObCollationType escape_coll,
|
||||
const common::ObString &text_val,
|
||||
const common::ObString &pattern_val,
|
||||
const common::ObString &escape_val);
|
||||
int assign(const ObExprOperator &other);
|
||||
OB_INLINE bool is_pattern_literal() const {return is_pattern_literal_;}
|
||||
OB_INLINE void set_pattern_is_literal(bool b) {is_pattern_literal_ = b;}
|
||||
OB_INLINE bool is_text_literal() const {return is_text_literal_;}
|
||||
OB_INLINE void set_text_is_literal(bool b) {is_text_literal_ = b;}
|
||||
OB_INLINE bool is_escape_literal() const {return is_escape_literal_;}
|
||||
OB_INLINE void set_escape_is_literal(bool b) {is_escape_literal_ = b;}
|
||||
virtual int cg_expr(ObExprCGCtx &op_cg_ctx,
|
||||
const ObRawExpr &raw_expr, ObExpr &rt_expr) const override;
|
||||
virtual bool need_rt_ctx() const override { return true; }
|
||||
|
||||
static int like_varchar(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum);
|
||||
static int eval_like_expr_batch_only_text_vectorized(BATCH_EVAL_FUNC_ARG_DECL);
|
||||
private:
|
||||
enum STATE {
|
||||
INIT = 0,
|
||||
PERCENT = 1, //"%", "%%", "%%%",etc
|
||||
PERCENT_NONPERCENT = 2, //"%a", "%%a" "%%ab",etc
|
||||
NONPERCENT_PERCENT = 3, //"a%" "a%%" "aa%" "aa%%",etc
|
||||
NONPERCENT = 4, //"a" "aa" "aaa",etc
|
||||
PERCENT_NONPERCENT_PENCENT = 5, //"%a%" "%%aa%",etc
|
||||
END = 6
|
||||
};
|
||||
static int set_instr_info(common::ObIAllocator* exec_allocator, const common::ObCollationType cs_type,
|
||||
const common::ObString& text, const common::ObString& pattern, const common::ObString& escape,
|
||||
const common::ObCollationType escape_coll, ObExprLikeContext& like_ctx);
|
||||
static int is_escape(
|
||||
const common::ObCollationType cs_type, const char* buf_start, int32_t char_len, int32_t escape_wc, bool& res);
|
||||
static int calc_escape_wc(
|
||||
const common::ObCollationType escape_coll, const common::ObString& escape, int32_t& escape_wc);
|
||||
static void state_trans_with_percent_sign(STATE& current_state);
|
||||
static void state_trans_with_nonpercent_char(STATE& current_state);
|
||||
static int set_instr_info(common::ObIAllocator *exec_allocator,
|
||||
const common::ObCollationType cs_type,
|
||||
const common::ObString &pattern,
|
||||
const common::ObString &escape,
|
||||
const common::ObCollationType escape_coll,
|
||||
ObExprLikeContext &like_ctx);
|
||||
static int is_escape(const common::ObCollationType cs_type,
|
||||
const char *buf_start,
|
||||
int32_t char_len,
|
||||
int32_t escape_wc,
|
||||
bool &res);
|
||||
static int calc_escape_wc(const common::ObCollationType escape_coll,
|
||||
const common::ObString &escape,
|
||||
int32_t &escape_wc);
|
||||
template <typename T>
|
||||
inline static int calc_with_instr_mode(T& result, const common::ObCollationType cs_type, const common::ObString& text,
|
||||
const ObExprLikeContext& like_ctx);
|
||||
template <typename T>
|
||||
static int check_pattern_valid(const T& pattern, const T& escape, const common::ObCollationType escape_coll,
|
||||
common::ObCollationType coll_type, ObExecContext* exec_ctx, const uint64_t like_id, const bool check_optimization,
|
||||
bool is_static_engine);
|
||||
OB_INLINE static void record_last_check(ObExprLikeContext& like_ctx, const common::ObString pattern_val,
|
||||
const common::ObString escape_val, common::ObIAllocator* buf_alloc, bool is_static_engine);
|
||||
OB_INLINE static bool checked_already(const ObExprLikeContext& like_ctx, bool null_pattern,
|
||||
const common::ObString pattern_val, bool null_escape, const common::ObString escape_val, bool is_static_engine);
|
||||
inline static int calc_with_instr_mode(T &result,
|
||||
const common::ObCollationType cs_type,
|
||||
const common::ObString &text,
|
||||
const ObExprLikeContext &like_ctx);
|
||||
template <bool is_static_engine, typename T>
|
||||
static int check_pattern_valid(const T &pattern, const T &escape,
|
||||
const common::ObCollationType escape_coll,
|
||||
common::ObCollationType coll_type,
|
||||
ObExecContext *exec_ctx, const uint64_t like_id,
|
||||
const bool check_optimization);
|
||||
template <bool is_static_engine>
|
||||
OB_INLINE static void record_last_check(ObExprLikeContext &like_ctx,
|
||||
const common::ObString pattern_val,
|
||||
const common::ObString escape_val,
|
||||
common::ObIAllocator *buf_alloc);
|
||||
template <bool is_static_engine>
|
||||
OB_INLINE static bool checked_already(const ObExprLikeContext &like_ctx, bool null_pattern,
|
||||
const common::ObString pattern_val, bool null_escape,
|
||||
const common::ObString escape_val);
|
||||
DISALLOW_COPY_AND_ASSIGN(ObExprLike);
|
||||
|
||||
private:
|
||||
// we may perform optimization via instr only when it holds that
|
||||
// is_text_literal_ == false and is_pattern_literal_ == true and is_escape_literal_ == true
|
||||
//we may perform optimization via instr only when it holds that
|
||||
//is_text_literal_ == false and is_pattern_literal_ == true and is_escape_literal_ == true
|
||||
bool is_pattern_literal_;
|
||||
bool is_text_literal_;
|
||||
bool is_escape_literal_;
|
||||
int16_t like_id_;
|
||||
};
|
||||
|
||||
} // namespace sql
|
||||
} // namespace oceanbase
|
||||
template <typename T>
|
||||
int ObExprLike::calc_with_non_instr_mode(T &result,
|
||||
const ObCollationType coll_type,
|
||||
const ObCollationType escape_coll,
|
||||
const ObString &text_val,
|
||||
const ObString &pattern_val,
|
||||
const ObString &escape_val)
|
||||
{
|
||||
// convert escape char
|
||||
// escape use its own collation,
|
||||
// @see http://k3.alibaba-inc.com/issue/6594393?versionId=1043693&companyId=0&toPage=1
|
||||
// try this query in MySQL:
|
||||
// mysql> select 'a%' like 'A2%' ESCAPE X'32', X'32';
|
||||
// +------------------------------+-------+
|
||||
// | 'a%' like 'A2%' ESCAPE X'32' | X'32' |
|
||||
// +------------------------------+-------+
|
||||
// | 1 | 2 |
|
||||
// +------------------------------+-------+
|
||||
int ret = OB_SUCCESS;
|
||||
int32_t escape_wc = 0;
|
||||
if (OB_FAIL(calc_escape_wc(escape_coll, escape_val, escape_wc))) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
SQL_LOG(WARN, "failed to get the wc of escape", K(ret), K(escape_val), K(escape_coll), K(escape_wc));
|
||||
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "ESCAPE");
|
||||
} else if (text_val.length() <= 0 && pattern_val.length() <= 0) {
|
||||
// empty string
|
||||
result.set_int(1);
|
||||
} else {
|
||||
bool b = ObCharset::wildcmp(coll_type, text_val, pattern_val, escape_wc,
|
||||
static_cast<int32_t>('_'), static_cast<int32_t>('%'));
|
||||
result.set_int(static_cast<int64_t>(b));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* OCEANBASE_SQL_ENGINE_EXPR_LIKE_ */
|
||||
|
||||
Reference in New Issue
Block a user