diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_packet_list.h b/deps/oblib/src/rpc/obrpc/ob_rpc_packet_list.h index 9706fb15a360af1d9122052240da55f8af3d848a..877137ec587eafd7dda8ed32dfbe96753f4dd2b0 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_packet_list.h +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_packet_list.h @@ -578,6 +578,7 @@ PCODE_DEF(OB_TABLE_API_LOGIN, 0x1101) PCODE_DEF(OB_TABLE_API_EXECUTE, 0x1102) PCODE_DEF(OB_TABLE_API_BATCH_EXECUTE, 0x1103) PCODE_DEF(OB_TABLE_API_EXECUTE_QUERY, 0x1104) +PCODE_DEF(OB_TABLE_API_QUERY_AND_MUTATE, 0x1105) // Event Job API PCODE_DEF(OB_RUN_EVENT_JOB, 0x1201) diff --git a/src/observer/CMakeLists.txt b/src/observer/CMakeLists.txt index 47f87f93cfcc88d497c6b5f72d32b20e1be9c9b2..e8e789da9e1a8d01e8ca01713b6bfc28930f422a 100644 --- a/src/observer/CMakeLists.txt +++ b/src/observer/CMakeLists.txt @@ -255,8 +255,17 @@ ob_set_subtarget(ob_server table table/ob_table_rpc_processor.cpp table/ob_table_service.cpp table/ob_table_api_row_iterator.cpp + table/ob_table_query_and_mutate_processor.cpp + table/ob_htable_filter_operator.cpp + table/ob_htable_filter_parser.cpp + table/ob_htable_utils.cpp + table/ob_htable_filters.cpp + table/htable_filter_tab.cxx + table/htable_filter_lex.cxx ) +set_source_files_properties(table/htable_filter_lex.cxx PROPERTIES COMPILE_FLAGS -Wno-null-conversion) + ob_server_add_pchs(observer ob_server_struct.h ob_uniq_task_queue.h diff --git a/src/observer/ob_srv_xlator_partition.cpp b/src/observer/ob_srv_xlator_partition.cpp index 84fa54e2bb8b2f5759e6c86fd0b7aaa780873e86..85bb7d8547c2afb828784270005863edae017031 100644 --- a/src/observer/ob_srv_xlator_partition.cpp +++ b/src/observer/ob_srv_xlator_partition.cpp @@ -41,6 +41,7 @@ #include "observer/table/ob_table_execute_processor.h" #include "observer/table/ob_table_batch_execute_processor.h" #include "observer/table/ob_table_query_processor.h" +#include "observer/table/ob_table_query_and_mutate_processor.h" using namespace oceanbase; using namespace oceanbase::observer; @@ -136,6 +137,7 @@ void oceanbase::observer::init_srv_xlator_for_others(ObSrvRpcXlator* xlator) RPC_PROCESSOR(ObTableApiExecuteP, gctx_); RPC_PROCESSOR(ObTableBatchExecuteP, gctx_); RPC_PROCESSOR(ObTableQueryP, gctx_); + RPC_PROCESSOR(ObTableQueryAndMutateP, gctx_); // HA GTS RPC_PROCESSOR(ObHaGtsPingRequestP, gctx_); diff --git a/src/observer/table/gen_htable_parser.sh b/src/observer/table/gen_htable_parser.sh new file mode 100755 index 0000000000000000000000000000000000000000..88163a664063a86792ff2f0207860bbc55482174 --- /dev/null +++ b/src/observer/table/gen_htable_parser.sh @@ -0,0 +1,11 @@ +#!/bin/bash +export PATH=/usr/local/bin:$PATH +# generate sql_parser +bison -v -Werror --defines=../../../src/observer/table/htable_filter_tab.hxx --output=../../../src/observer/table/htable_filter_tab.cxx ../../../src/observer/table/htable_filter_tab.yxx + +if [ $? -ne 0 ] +then + echo yacc error[$?], abort. + exit 1 +fi +flex --header-file="../../../src/observer/table/htable_filter_lex.hxx" --outfile="../../../src/observer/table/htable_filter_lex.cxx" ../../../src/observer/table/htable_filter_lex.lxx diff --git a/src/observer/table/htable_filter_lex.cxx b/src/observer/table/htable_filter_lex.cxx new file mode 100644 index 0000000000000000000000000000000000000000..47250b9844e0dc19308bfb8d0f24e1cb4f6d3858 --- /dev/null +++ b/src/observer/table/htable_filter_lex.cxx @@ -0,0 +1,2275 @@ +#line 2 "../../../src/observer/table/htable_filter_lex.cxx" +#line 7 "../../../src/observer/table/htable_filter_lex.lxx" +#define USING_LOG_PREFIX SERVER +#include "observer/table/ob_htable_filter_parser.h" +#include "observer/table/ob_htable_filters.h" +#include "observer/table/htable_filter_tab.hxx" +using namespace oceanbase::common; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" + + + +#line 14 "../../../src/observer/table/htable_filter_lex.cxx" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE ob_hfilter_restart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE ob_hfilter_lex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via ob_hfilter_restart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void ob_hfilter_restart (FILE *input_file ,yyscan_t yyscanner ); +void ob_hfilter__switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE ob_hfilter__create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void ob_hfilter__delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void ob_hfilter__flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void ob_hfilter_push_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void ob_hfilter_pop_buffer_state (yyscan_t yyscanner ); + +static void ob_hfilter_ensure_buffer_stack (yyscan_t yyscanner ); +static void ob_hfilter__load_buffer_state (yyscan_t yyscanner ); +static void ob_hfilter__init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER ob_hfilter__flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE ob_hfilter__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE ob_hfilter__scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE ob_hfilter__scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *ob_hfilter_alloc (yy_size_t ,yyscan_t yyscanner ); +void *ob_hfilter_realloc (void *,yy_size_t ,yyscan_t yyscanner ); +void ob_hfilter_free (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer ob_hfilter__create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + ob_hfilter_ensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + ob_hfilter__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + ob_hfilter_ensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + ob_hfilter__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define ob_hfilter_wrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 30 +#define YY_END_OF_BUFFER 31 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[170] = + { 0, + 0, 0, 0, 0, 31, 29, 28, 28, 29, 15, + 27, 14, 10, 5, 8, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 16, 18, 6, + 14, 9, 7, 0, 0, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 16, 17, + 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 12, 0, 0, 0, 0, 13, + 11, 0, 0, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 20, 0, 0, 26, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 25, 24, 0, 0, 0, 22, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 1, 1, 1, 1, 1, 5, 6, + 6, 1, 1, 6, 1, 1, 1, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 1, 1, 8, + 9, 10, 1, 1, 11, 1, 12, 13, 14, 15, + 16, 17, 18, 1, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 1, 1, + 1, 1, 1, 1, 33, 1, 34, 1, 35, 36, + + 37, 38, 39, 40, 41, 1, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[56] = + { 0, + 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[172] = + { 0, + 0, 0, 327, 326, 330, 333, 333, 333, 320, 333, + 333, 321, 299, 333, 298, 34, 40, 47, 36, 34, + 50, 33, 41, 47, 41, 57, 52, 0, 301, 333, + 298, 333, 333, 57, 57, 52, 53, 271, 333, 58, + 61, 66, 47, 80, 85, 75, 85, 88, 0, 333, + 333, 95, 79, 82, 87, 97, 97, 93, 99, 99, + 92, 103, 89, 99, 101, 100, 108, 99, 109, 130, + 131, 132, 131, 333, 333, 138, 139, 143, 133, 333, + 333, 138, 125, 143, 139, 146, 146, 333, 140, 151, + 144, 150, 148, 139, 156, 151, 157, 171, 167, 178, + + 183, 184, 176, 180, 180, 173, 189, 184, 179, 180, + 187, 180, 180, 188, 185, 184, 198, 333, 185, 201, + 188, 212, 333, 227, 224, 222, 218, 234, 230, 221, + 228, 227, 333, 222, 237, 333, 224, 223, 240, 227, + 242, 246, 243, 244, 234, 241, 244, 268, 333, 258, + 268, 269, 276, 263, 264, 278, 280, 281, 278, 271, + 272, 279, 333, 333, 272, 287, 276, 333, 333, 325, + 302 + } ; + +static yyconst flex_int16_t yy_def[172] = + { 0, + 169, 1, 170, 170, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 171, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 171, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 0, 169, + 169 + } ; + +static yyconst flex_int16_t yy_nxt[389] = + { 0, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 6, 6, 18, 6, 6, 6, 6, 6, + 6, 19, 20, 21, 22, 23, 24, 25, 6, 26, + 27, 6, 6, 16, 17, 6, 6, 18, 6, 6, + 6, 6, 6, 6, 19, 20, 21, 22, 23, 24, + 25, 6, 26, 27, 6, 34, 35, 37, 38, 39, + 40, 42, 36, 43, 44, 45, 46, 47, 48, 51, + 52, 53, 54, 56, 57, 41, 58, 59, 34, 35, + 37, 38, 39, 40, 42, 36, 43, 44, 45, 46, + 47, 48, 51, 52, 53, 54, 56, 57, 41, 58, + + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + + 167, 168, 49, 55, 31, 50, 33, 32, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 28, 28, 31, 30, 169, + 29, 29, 5, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169 + } ; + +static yyconst flex_int16_t yy_chk[389] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 16, 17, 18, 19, 20, + 21, 22, 17, 23, 24, 24, 25, 26, 27, 34, + 35, 36, 37, 40, 41, 21, 42, 43, 16, 17, + 18, 19, 20, 21, 22, 17, 23, 24, 24, 25, + 26, 27, 34, 35, 36, 37, 40, 41, 21, 42, + + 43, 44, 45, 46, 47, 48, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 44, 45, 46, 47, 48, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 76, 77, 78, 79, 82, 83, 84, 85, 86, + 87, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 70, 71, 72, 73, 76, 77, 78, 79, 82, 83, + 84, 85, 86, 87, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 119, 120, 121, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 119, 120, 121, 122, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, + 135, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146, 147, 122, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 134, 135, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, 162, 165, + + 166, 167, 171, 38, 31, 29, 15, 13, 148, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 165, 166, 167, 170, 170, 12, 9, 5, + 4, 3, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169 + } ; + +/* Table of booleans, true if rule could match eol. */ +static yyconst flex_int32_t yy_rule_can_match_eol[31] = + { 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "../../../src/observer/table/htable_filter_lex.lxx" +#define YY_NO_INPUT 1 + + +#line 604 "../../../src/observer/table/htable_filter_lex.cxx" + +#define INITIAL 0 +#define IN_STRING 1 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#define YY_EXTRA_TYPE oceanbase::table::ObHTableFilterParser * + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + YYLTYPE * yylloc_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + + # define yylloc yyg->yylloc_r + +int ob_hfilter_lex_init (yyscan_t* scanner); + +int ob_hfilter_lex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int ob_hfilter_lex_destroy (yyscan_t yyscanner ); + +int ob_hfilter_get_debug (yyscan_t yyscanner ); + +void ob_hfilter_set_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE ob_hfilter_get_extra (yyscan_t yyscanner ); + +void ob_hfilter_set_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *ob_hfilter_get_in (yyscan_t yyscanner ); + +void ob_hfilter_set_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *ob_hfilter_get_out (yyscan_t yyscanner ); + +void ob_hfilter_set_out (FILE * out_str ,yyscan_t yyscanner ); + +int ob_hfilter_get_leng (yyscan_t yyscanner ); + +char *ob_hfilter_get_text (yyscan_t yyscanner ); + +int ob_hfilter_get_lineno (yyscan_t yyscanner ); + +void ob_hfilter_set_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * ob_hfilter_get_lval (yyscan_t yyscanner ); + +void ob_hfilter_set_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + + YYLTYPE *ob_hfilter_get_lloc (yyscan_t yyscanner ); + + void ob_hfilter_set_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int ob_hfilter_wrap (yyscan_t yyscanner ); +#else +extern int ob_hfilter_wrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + unsigned n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int ob_hfilter_lex \ + (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); + +#define YY_DECL int ob_hfilter_lex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + +#line 21 "../../../src/observer/table/htable_filter_lex.lxx" + + /* rules */ +#line 845 "../../../src/observer/table/htable_filter_lex.cxx" + + yylval = yylval_param; + + yylloc = yylloc_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + ob_hfilter_ensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + ob_hfilter__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + ob_hfilter__load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 170 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 333 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 23 "../../../src/observer/table/htable_filter_lex.lxx" +{ return SKIP; } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 24 "../../../src/observer/table/htable_filter_lex.lxx" +{ return WHILE; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 25 "../../../src/observer/table/htable_filter_lex.lxx" +{ return AND; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 26 "../../../src/observer/table/htable_filter_lex.lxx" +{ return OR; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 28 "../../../src/observer/table/htable_filter_lex.lxx" +{ return EQUAL; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 29 "../../../src/observer/table/htable_filter_lex.lxx" +{ return NOT_EQUAL; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 30 "../../../src/observer/table/htable_filter_lex.lxx" +{ return GREATER_OR_EQUAL; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 31 "../../../src/observer/table/htable_filter_lex.lxx" +{ return GREATER; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 32 "../../../src/observer/table/htable_filter_lex.lxx" +{ return LESS_OR_EQUAL; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 33 "../../../src/observer/table/htable_filter_lex.lxx" +{ return LESS; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 34 "../../../src/observer/table/htable_filter_lex.lxx" +{ return NO_OP; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 36 "../../../src/observer/table/htable_filter_lex.lxx" +{ +yylval->ival = 1; +return BOOL_VALUE; +} + YY_BREAK +case 13: +YY_RULE_SETUP +#line 41 "../../../src/observer/table/htable_filter_lex.lxx" +{ +yylval->ival = 0; +return BOOL_VALUE; +} + YY_BREAK +case 14: +YY_RULE_SETUP +#line 46 "../../../src/observer/table/htable_filter_lex.lxx" +{ + errno = 0; + yylval->lval = strtoll(yytext, NULL, 10); + if (ERANGE == errno) + { + ob_hfilter_error(yylloc, yyextra, "integar value out of range"); + } + return INT_VALUE; +} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 56 "../../../src/observer/table/htable_filter_lex.lxx" +{ +BEGIN(IN_STRING); +char *buf = static_cast(yyextra->alloc(yyextra->get_input_len()+1)); +if (NULL == buf) { +yyextra->error_code_ = oceanbase::common::OB_ALLOCATE_MEMORY_FAILED; +ob_hfilter_error(yylloc, yyextra, "no memory"); +return ERROR; +} +yylval->sval.len_ = 0; +yylval->sval.str_ = buf; +} + YY_BREAK +case 16: +/* rule 16 can match eol */ +YY_RULE_SETUP +#line 67 "../../../src/observer/table/htable_filter_lex.lxx" +{ + memcpy(yylval->sval.str_+yylval->sval.len_, yytext, yyleng); + yylval->sval.len_ += yyleng; +} + YY_BREAK +case 17: +YY_RULE_SETUP +#line 71 "../../../src/observer/table/htable_filter_lex.lxx" +{ + yylval->sval.str_[yylval->sval.len_++] = '\''; +} + YY_BREAK +case 18: +YY_RULE_SETUP +#line 74 "../../../src/observer/table/htable_filter_lex.lxx" +{ + BEGIN(INITIAL); + return STRING_VALUE; +} + YY_BREAK +case YY_STATE_EOF(IN_STRING): +#line 78 "../../../src/observer/table/htable_filter_lex.lxx" +{ + ob_hfilter_error(yylloc, yyextra, "unterminated quoted string"); + return ERROR; +} + YY_BREAK +case 19: +YY_RULE_SETUP +#line 83 "../../../src/observer/table/htable_filter_lex.lxx" +{ return RowFilter; } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 84 "../../../src/observer/table/htable_filter_lex.lxx" +{ return ValueFilter; } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 85 "../../../src/observer/table/htable_filter_lex.lxx" +{ return QualifierFilter; } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 86 "../../../src/observer/table/htable_filter_lex.lxx" +{ return SingleColumnValueFilter; } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 87 "../../../src/observer/table/htable_filter_lex.lxx" +{ return PageFilter; } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 88 "../../../src/observer/table/htable_filter_lex.lxx" +{ return ColumnCountGetFilter; } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 89 "../../../src/observer/table/htable_filter_lex.lxx" +{ return CheckAndMutateFilter; } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 90 "../../../src/observer/table/htable_filter_lex.lxx" +{ return PrefixFilter; } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 92 "../../../src/observer/table/htable_filter_lex.lxx" +{ + return yytext[0]; +} + YY_BREAK +case 28: +/* rule 28 can match eol */ +YY_RULE_SETUP +#line 96 "../../../src/observer/table/htable_filter_lex.lxx" +{/*skip*/} + YY_BREAK +case YY_STATE_EOF(INITIAL): +#line 98 "../../../src/observer/table/htable_filter_lex.lxx" +{ + return END; +} + YY_BREAK +case 29: +YY_RULE_SETUP +#line 102 "../../../src/observer/table/htable_filter_lex.lxx" +{ + ob_hfilter_error(yylloc, yyextra, "mystery charactor '%c'", *yytext); + return ERROR; +} + YY_BREAK +case 30: +YY_RULE_SETUP +#line 106 "../../../src/observer/table/htable_filter_lex.lxx" +ECHO; + YY_BREAK +#line 1146 "../../../src/observer/table/htable_filter_lex.cxx" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * ob_hfilter_lex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( ob_hfilter_wrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of ob_hfilter_lex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + ob_hfilter_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + ob_hfilter_restart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) ob_hfilter_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 170 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + register char *yy_cp = yyg->yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 170 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 169); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + ob_hfilter_restart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( ob_hfilter_wrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + if ( c == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void ob_hfilter_restart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + ob_hfilter_ensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + ob_hfilter__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + ob_hfilter__init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + ob_hfilter__load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void ob_hfilter__switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * ob_hfilter_pop_buffer_state(); + * ob_hfilter_push_buffer_state(new_buffer); + */ + ob_hfilter_ensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + ob_hfilter__load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (ob_hfilter_wrap()) processing, but the only time this flag + * is looked at is after ob_hfilter_wrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void ob_hfilter__load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE ob_hfilter__create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) ob_hfilter_alloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in ob_hfilter__create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) ob_hfilter_alloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in ob_hfilter__create_buffer()" ); + + b->yy_is_our_buffer = 1; + + ob_hfilter__init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with ob_hfilter__create_buffer() + * @param yyscanner The scanner object. + */ + void ob_hfilter__delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + ob_hfilter_free((void *) b->yy_ch_buf ,yyscanner ); + + ob_hfilter_free((void *) b ,yyscanner ); +} + +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a ob_hfilter_restart() or at EOF. + */ + static void ob_hfilter__init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + ob_hfilter__flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then ob_hfilter__init_buffer was _probably_ + * called from ob_hfilter_restart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void ob_hfilter__flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + ob_hfilter__load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void ob_hfilter_push_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + ob_hfilter_ensure_buffer_stack(yyscanner); + + /* This block is copied from ob_hfilter__switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from ob_hfilter__switch_to_buffer. */ + ob_hfilter__load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void ob_hfilter_pop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + ob_hfilter__delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + ob_hfilter__load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void ob_hfilter_ensure_buffer_stack (yyscan_t yyscanner) +{ + int num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)ob_hfilter_alloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in ob_hfilter_ensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)ob_hfilter_realloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in ob_hfilter_ensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE ob_hfilter__scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) ob_hfilter_alloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in ob_hfilter__scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + ob_hfilter__switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to ob_hfilter_lex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * ob_hfilter__scan_bytes() instead. + */ +YY_BUFFER_STATE ob_hfilter__scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return ob_hfilter__scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to ob_hfilter_lex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE ob_hfilter__scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) ob_hfilter_alloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in ob_hfilter__scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = ob_hfilter__scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in ob_hfilter__scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE ob_hfilter_get_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int ob_hfilter_get_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int ob_hfilter_get_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *ob_hfilter_get_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *ob_hfilter_get_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int ob_hfilter_get_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *ob_hfilter_get_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void ob_hfilter_set_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void ob_hfilter_set_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "ob_hfilter_set_lineno called with no buffer" , yyscanner); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void ob_hfilter_set_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "ob_hfilter_set_column called with no buffer" , yyscanner); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see ob_hfilter__switch_to_buffer + */ +void ob_hfilter_set_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void ob_hfilter_set_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int ob_hfilter_get_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void ob_hfilter_set_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * ob_hfilter_get_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void ob_hfilter_set_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +YYLTYPE *ob_hfilter_get_lloc (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylloc; +} + +void ob_hfilter_set_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylloc = yylloc_param; +} + +/* User-visible API */ + +/* ob_hfilter_lex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int ob_hfilter_lex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) ob_hfilter_alloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* ob_hfilter_lex_init_extra has the same functionality as ob_hfilter_lex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to ob_hfilter_alloc in + * the yyextra field. + */ + +int ob_hfilter_lex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + ob_hfilter_set_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) ob_hfilter_alloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + ob_hfilter_set_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from ob_hfilter_lex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * ob_hfilter_lex_init() + */ + return 0; +} + +/* ob_hfilter_lex_destroy is for both reentrant and non-reentrant scanners. */ +int ob_hfilter_lex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + ob_hfilter__delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + ob_hfilter_pop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + ob_hfilter_free(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + ob_hfilter_free(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * ob_hfilter_lex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + ob_hfilter_free ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +#define YYTABLES_NAME "yytables" + +#line 106 "../../../src/observer/table/htable_filter_lex.lxx" + + + /* user code */ + +#pragma GCC diagnostic pop + diff --git a/src/observer/table/htable_filter_lex.hxx b/src/observer/table/htable_filter_lex.hxx new file mode 100644 index 0000000000000000000000000000000000000000..cdaf2a93953f0c8948a17d6c60d6ae8bca83025f --- /dev/null +++ b/src/observer/table/htable_filter_lex.hxx @@ -0,0 +1,354 @@ +#ifndef ob_hfilter_HEADER_H +#define ob_hfilter_HEADER_H 1 +#define ob_hfilter_IN_HEADER 1 + +#line 6 "../../../src/observer/table/htable_filter_lex.hxx" +#line 7 "../../../src/observer/table/htable_filter_lex.lxx" +#define USING_LOG_PREFIX SERVER +#include "observer/table/ob_htable_filter_parser.h" +#include "observer/table/ob_htable_filters.h" +#include "observer/table/htable_filter_tab.hxx" +using namespace oceanbase::common; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" + + + +#line 18 "../../../src/observer/table/htable_filter_lex.hxx" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +void ob_hfilter_restart (FILE *input_file ,yyscan_t yyscanner ); +void ob_hfilter__switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE ob_hfilter__create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void ob_hfilter__delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void ob_hfilter__flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void ob_hfilter_push_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void ob_hfilter_pop_buffer_state (yyscan_t yyscanner ); + +YY_BUFFER_STATE ob_hfilter__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE ob_hfilter__scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE ob_hfilter__scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *ob_hfilter_alloc (yy_size_t ,yyscan_t yyscanner ); +void *ob_hfilter_realloc (void *,yy_size_t ,yyscan_t yyscanner ); +void ob_hfilter_free (void * ,yyscan_t yyscanner ); + +/* Begin user sect3 */ + +#define ob_hfilter_wrap(n) 1 +#define YY_SKIP_YYWRAP + +#define yytext_ptr yytext_r + +#ifdef YY_HEADER_EXPORT_START_CONDITIONS +#define INITIAL 0 +#define IN_STRING 1 + +#endif + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#define YY_EXTRA_TYPE oceanbase::table::ObHTableFilterParser * + +int ob_hfilter_lex_init (yyscan_t* scanner); + +int ob_hfilter_lex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int ob_hfilter_lex_destroy (yyscan_t yyscanner ); + +int ob_hfilter_get_debug (yyscan_t yyscanner ); + +void ob_hfilter_set_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE ob_hfilter_get_extra (yyscan_t yyscanner ); + +void ob_hfilter_set_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *ob_hfilter_get_in (yyscan_t yyscanner ); + +void ob_hfilter_set_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *ob_hfilter_get_out (yyscan_t yyscanner ); + +void ob_hfilter_set_out (FILE * out_str ,yyscan_t yyscanner ); + +int ob_hfilter_get_leng (yyscan_t yyscanner ); + +char *ob_hfilter_get_text (yyscan_t yyscanner ); + +int ob_hfilter_get_lineno (yyscan_t yyscanner ); + +void ob_hfilter_set_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * ob_hfilter_get_lval (yyscan_t yyscanner ); + +void ob_hfilter_set_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + + YYLTYPE *ob_hfilter_get_lloc (yyscan_t yyscanner ); + + void ob_hfilter_set_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int ob_hfilter_wrap (yyscan_t yyscanner ); +#else +extern int ob_hfilter_wrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int ob_hfilter_lex \ + (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); + +#define YY_DECL int ob_hfilter_lex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +#line 106 "../../../src/observer/table/htable_filter_lex.lxx" + + +#line 353 "../../../src/observer/table/htable_filter_lex.hxx" +#undef ob_hfilter_IN_HEADER +#endif /* ob_hfilter_HEADER_H */ diff --git a/src/observer/table/htable_filter_lex.lxx b/src/observer/table/htable_filter_lex.lxx new file mode 100644 index 0000000000000000000000000000000000000000..81d98e5f0d00b75f755ecd63bb14101d51981e0f --- /dev/null +++ b/src/observer/table/htable_filter_lex.lxx @@ -0,0 +1,109 @@ +%option yylineno case-insensitive reentrant +%option bison-bridge bison-locations +%option noyyalloc noyyrealloc noyyfree noyywrap nounput noinput +%option extra-type="oceanbase::table::ObHTableFilterParser *" +%option prefix="ob_hfilter_" +%top{ +#define USING_LOG_PREFIX SERVER +#include "observer/table/ob_htable_filter_parser.h" +#include "observer/table/ob_htable_filters.h" +#include "observer/table/htable_filter_tab.hxx" +using namespace oceanbase::common; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +} +%x IN_STRING + +ID ([A-Za-z0-9$_]*) +INT [0-9]+ +SQUOTE ' + +%% + /* rules */ +SKIP { return SKIP; } +WHILE { return WHILE; } +AND { return AND; } +OR { return OR; } + +"=" { return EQUAL; } +"!=" { return NOT_EQUAL; } +">=" { return GREATER_OR_EQUAL; } +">" { return GREATER; } +"<=" { return LESS_OR_EQUAL; } +"<" { return LESS; } +NO_OP { return NO_OP; } + +TRUE { +yylval->ival = 1; +return BOOL_VALUE; +} + +FALSE { +yylval->ival = 0; +return BOOL_VALUE; +} + +{INT} { + errno = 0; + yylval->lval = strtoll(yytext, NULL, 10); + if (ERANGE == errno) + { + ob_hfilter_error(yylloc, yyextra, "integar value out of range"); + } + return INT_VALUE; +} + +{SQUOTE} { +BEGIN(IN_STRING); +char *buf = static_cast(yyextra->alloc(yyextra->get_input_len()+1)); +if (NULL == buf) { +yyextra->error_code_ = oceanbase::common::OB_ALLOCATE_MEMORY_FAILED; +ob_hfilter_error(yylloc, yyextra, "no memory"); +return ERROR; +} +yylval->sval.len_ = 0; +yylval->sval.str_ = buf; +} +[^']+ { + memcpy(yylval->sval.str_+yylval->sval.len_, yytext, yyleng); + yylval->sval.len_ += yyleng; +} +{SQUOTE}{SQUOTE} { + yylval->sval.str_[yylval->sval.len_++] = '\''; +} +{SQUOTE} { + BEGIN(INITIAL); + return STRING_VALUE; +} +<> { + ob_hfilter_error(yylloc, yyextra, "unterminated quoted string"); + return ERROR; +} + +RowFilter { return RowFilter; } +ValueFilter { return ValueFilter; } +QualifierFilter { return QualifierFilter; } +SingleColumnValueFilter { return SingleColumnValueFilter; } +PageFilter { return PageFilter; } +ColumnCountGetFilter { return ColumnCountGetFilter; } +CheckAndMutateFilter { return CheckAndMutateFilter; } +PrefixFilter { return PrefixFilter; } + +[(),] { + return yytext[0]; +} + +[ \t\r\n] {/*skip*/} + +<> { + return END; +} + +. { + ob_hfilter_error(yylloc, yyextra, "mystery charactor '%c'", *yytext); + return ERROR; +} +%% + /* user code */ + +#pragma GCC diagnostic pop diff --git a/src/observer/table/htable_filter_tab.cxx b/src/observer/table/htable_filter_tab.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3055f8e133a3f15c1083a7f031b2f5e27de5a862 --- /dev/null +++ b/src/observer/table/htable_filter_tab.cxx @@ -0,0 +1,2124 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 1 + +/* Substitute the variable and function names. */ +#define yyparse ob_hfilter_parse +#define yylex ob_hfilter_lex +#define yyerror ob_hfilter_error +#define yylval ob_hfilter_lval +#define yychar ob_hfilter_char +#define yydebug ob_hfilter_debug +#define yynerrs ob_hfilter_nerrs +#define yylloc ob_hfilter_lloc + +/* Copy the first part of user declarations. */ + +/* Line 189 of yacc.c */ +#line 10 "../../../src/observer/table/htable_filter_tab.yxx" + +#define USING_LOG_PREFIX SERVER +#include +#include "observer/table/ob_htable_filters.h" +#include "observer/table/ob_htable_filter_parser.h" +#include "observer/table/htable_filter_lex.hxx" +#define YYDEBUG 1 +#define YYLEX_PARAM (parse_ctx->scanner_) +using namespace oceanbase::table; +using namespace oceanbase::common; + + +/* Line 189 of yacc.c */ +#line 94 "../../../src/observer/table/htable_filter_tab.cxx" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 1 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + END = 0, + RowFilter = 258, + ValueFilter = 259, + QualifierFilter = 260, + SingleColumnValueFilter = 261, + PageFilter = 262, + ColumnCountGetFilter = 263, + CheckAndMutateFilter = 264, + PrefixFilter = 265, + LESS = 266, + LESS_OR_EQUAL = 267, + EQUAL = 268, + NOT_EQUAL = 269, + GREATER = 270, + GREATER_OR_EQUAL = 271, + NO_OP = 272, + BOOL_VALUE = 273, + STRING_VALUE = 274, + INT_VALUE = 275, + OR = 276, + AND = 277, + WHILE = 278, + SKIP = 279, + ERROR = 280 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 214 of yacc.c */ +#line 23 "../../../src/observer/table/htable_filter_tab.yxx" + + int32_t ival; + int64_t lval; + oceanbase::table::hfilter::CompareOperator cmp_op; + oceanbase::table::ObHTableFilterParser::SimpleString sval; + oceanbase::table::hfilter::Filter *fval; + + + +/* Line 214 of yacc.c */ +#line 166 "../../../src/observer/table/htable_filter_tab.cxx" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 264 of yacc.c */ +#line 191 "../../../src/observer/table/htable_filter_tab.cxx" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; + YYLTYPE yyls_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 26 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 80 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 29 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 8 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 27 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 84 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 280 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 26, 27, 2, 2, 28, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 6, 10, 14, 17, 20, 22, 26, + 33, 40, 47, 52, 67, 78, 83, 88, 101, 103, + 105, 107, 109, 111, 113, 115, 117, 119 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 30, 0, -1, 31, 0, -1, 31, 22, 31, -1, + 31, 21, 31, -1, 24, 31, -1, 23, 31, -1, + 32, -1, 26, 31, 27, -1, 3, 26, 35, 28, + 36, 27, -1, 5, 26, 35, 28, 36, 27, -1, + 4, 26, 35, 28, 36, 27, -1, 10, 26, 19, + 27, -1, 6, 26, 33, 28, 34, 28, 35, 28, + 36, 28, 18, 28, 18, 27, -1, 6, 26, 33, + 28, 34, 28, 35, 28, 36, 27, -1, 7, 26, + 20, 27, -1, 8, 26, 20, 27, -1, 9, 26, + 35, 28, 36, 28, 33, 28, 34, 28, 18, 27, + -1, 19, -1, 19, -1, 11, -1, 12, -1, 13, + -1, 14, -1, 15, -1, 16, -1, 17, -1, 19, + -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 51, 51, 58, 79, 100, 115, 130, 137, 139, + 161, 183, 205, 227, 255, 283, 290, 305, 331, 334, + 337, 338, 339, 340, 341, 342, 343, 346 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "\"end of file\"", "error", "$undefined", "RowFilter", "ValueFilter", + "QualifierFilter", "SingleColumnValueFilter", "PageFilter", + "ColumnCountGetFilter", "CheckAndMutateFilter", "PrefixFilter", "LESS", + "LESS_OR_EQUAL", "EQUAL", "NOT_EQUAL", "GREATER", "GREATER_OR_EQUAL", + "NO_OP", "BOOL_VALUE", "STRING_VALUE", "INT_VALUE", "OR", "AND", "WHILE", + "SKIP", "ERROR", "'('", "')'", "','", "$accept", "result_filter", + "filter", "simple_filter", "family", "qualifier", "compare_op", + "comparator", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 40, 41, 44 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 29, 30, 31, 31, 31, 31, 31, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 33, 34, + 35, 35, 35, 35, 35, 35, 35, 36 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 3, 3, 2, 2, 1, 3, 6, + 6, 6, 4, 14, 10, 4, 4, 12, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 5, 0, 1, 2, 0, 0, + 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, + 18, 0, 0, 0, 0, 0, 8, 4, 3, 0, + 0, 0, 0, 15, 16, 0, 12, 27, 0, 0, + 0, 19, 0, 0, 9, 11, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, + 0, 17, 0, 13 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 12, 13, 14, 41, 62, 37, 58 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -37 +static const yytype_int8 yypact[] = +{ + 3, -10, -9, -8, -1, 6, 7, 8, 12, 3, + 3, 3, 28, 2, -37, 30, 30, 30, 18, 29, + 32, 30, 31, -37, -37, 9, -37, -37, 3, 3, + -37, -37, -37, -37, -37, -37, -37, 20, 25, 26, + -37, 27, 33, 34, 35, 37, -37, 36, -37, 38, + 38, 38, 40, -37, -37, 38, -37, -37, 39, 41, + 42, -37, 43, 44, -37, -37, -37, 30, 18, 45, + 46, 38, 40, -24, 47, -37, 49, 52, 48, 50, + 60, -37, 53, -37 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -37, -37, 11, -37, -12, -7, -16, -36 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 38, 39, 27, 75, 76, 44, 1, 2, 3, 4, + 5, 6, 7, 8, 59, 60, 15, 16, 17, 63, + 23, 24, 25, 28, 29, 18, 9, 10, 26, 11, + 28, 29, 19, 20, 21, 73, 46, 40, 22, 47, + 48, 30, 31, 32, 33, 34, 35, 36, 49, 42, + 45, 69, 43, 50, 51, 52, 70, 57, 29, 61, + 53, 54, 0, 55, 56, 74, 64, 78, 65, 66, + 79, 67, 68, 71, 72, 77, 80, 81, 82, 0, + 83 +}; + +static const yytype_int8 yycheck[] = +{ + 16, 17, 0, 27, 28, 21, 3, 4, 5, 6, + 7, 8, 9, 10, 50, 51, 26, 26, 26, 55, + 9, 10, 11, 21, 22, 26, 23, 24, 0, 26, + 21, 22, 26, 26, 26, 71, 27, 19, 26, 28, + 29, 11, 12, 13, 14, 15, 16, 17, 28, 20, + 19, 67, 20, 28, 28, 28, 68, 19, 22, 19, + 27, 27, -1, 28, 27, 72, 27, 18, 27, 27, + 18, 28, 28, 28, 28, 28, 28, 27, 18, -1, + 27 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 4, 5, 6, 7, 8, 9, 10, 23, + 24, 26, 30, 31, 32, 26, 26, 26, 26, 26, + 26, 26, 26, 31, 31, 31, 0, 0, 21, 22, + 11, 12, 13, 14, 15, 16, 17, 35, 35, 35, + 19, 33, 20, 20, 35, 19, 27, 31, 31, 28, + 28, 28, 28, 27, 27, 28, 27, 19, 36, 36, + 36, 19, 34, 36, 27, 27, 27, 28, 28, 35, + 33, 28, 28, 36, 34, 27, 28, 28, 18, 18, + 28, 27, 18, 27 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, parse_ctx, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval, &yylloc) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, Location, parse_ctx); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, oceanbase::table::ObHTableFilterParser *parse_ctx) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parse_ctx) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + oceanbase::table::ObHTableFilterParser *parse_ctx; +#endif +{ + if (!yyvaluep) + return; + YYUSE (yylocationp); + YYUSE (parse_ctx); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, oceanbase::table::ObHTableFilterParser *parse_ctx) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, parse_ctx) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + oceanbase::table::ObHTableFilterParser *parse_ctx; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + YY_LOCATION_PRINT (yyoutput, *yylocationp); + YYFPRINTF (yyoutput, ": "); + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parse_ctx); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, oceanbase::table::ObHTableFilterParser *parse_ctx) +#else +static void +yy_reduce_print (yyvsp, yylsp, yyrule, parse_ctx) + YYSTYPE *yyvsp; + YYLTYPE *yylsp; + int yyrule; + oceanbase::table::ObHTableFilterParser *parse_ctx; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , &(yylsp[(yyi + 1) - (yynrhs)]) , parse_ctx); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, yylsp, Rule, parse_ctx); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, oceanbase::table::ObHTableFilterParser *parse_ctx) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, yylocationp, parse_ctx) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + YYLTYPE *yylocationp; + oceanbase::table::ObHTableFilterParser *parse_ctx; +#endif +{ + YYUSE (yyvaluep); + YYUSE (yylocationp); + YYUSE (parse_ctx); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (oceanbase::table::ObHTableFilterParser *parse_ctx); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (oceanbase::table::ObHTableFilterParser *parse_ctx) +#else +int +yyparse (parse_ctx) + oceanbase::table::ObHTableFilterParser *parse_ctx; +#endif +#endif +{ +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Location data for the lookahead symbol. */ +YYLTYPE yylloc; + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls; + YYLTYPE *yylsp; + + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[2]; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yyls = yylsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + yylsp = yyls; + +#if YYLTYPE_IS_TRIVIAL + /* Initialize the default location before parsing starts. */ + yylloc.first_line = yylloc.last_line = 1; + yylloc.first_column = yylloc.last_column = 1; +#endif + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + + yyls = yyls1; + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + *++yylsp = yylloc; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: + +/* Line 1455 of yacc.c */ +#line 51 "../../../src/observer/table/htable_filter_tab.yxx" + { + parse_ctx->set_result_filter((yyvsp[(1) - (2)].fval)); + YYACCEPT; + ;} + break; + + case 3: + +/* Line 1455 of yacc.c */ +#line 59 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::FilterListBase *filter_list = nullptr; + (yyval.fval) = filter_list = OB_NEWx(hfilter::FilterListAND, parse_ctx->allocator(), + hfilter::FilterListBase::Operator::MUST_PASS_ALL); + if (nullptr == (yyval.fval)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter((yyval.fval)))) { + LOG_WARN("failed to store filter", K(ret)); + } else if (OB_FAIL(filter_list->add_filter((yyvsp[(1) - (3)].fval)))) { + LOG_WARN("failed to add filter to list", K(ret)); + } else if (OB_FAIL(filter_list->add_filter((yyvsp[(3) - (3)].fval)))) { + LOG_WARN("failed to add filter to list", K(ret)); + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&((yyloc)), parse_ctx, "failed to parse FilterList with AND"); + YYABORT; + } + ;} + break; + + case 4: + +/* Line 1455 of yacc.c */ +#line 80 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::FilterListBase *filter_list = nullptr; + (yyval.fval) = filter_list = OB_NEWx(hfilter::FilterListOR, parse_ctx->allocator(), + hfilter::FilterListBase::Operator::MUST_PASS_ONE); + if (nullptr == (yyval.fval)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter((yyval.fval)))) { + LOG_WARN("failed to store filter", K(ret)); + } else if (OB_FAIL(filter_list->add_filter((yyvsp[(1) - (3)].fval)))) { + LOG_WARN("failed to add filter to list", K(ret)); + } else if (OB_FAIL(filter_list->add_filter((yyvsp[(3) - (3)].fval)))) { + LOG_WARN("failed to add filter to list", K(ret)); + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&((yyloc)), parse_ctx, "failed to parse FilterList with AND"); + YYABORT; + } + ;} + break; + + case 5: + +/* Line 1455 of yacc.c */ +#line 101 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + (yyval.fval) = OB_NEWx(hfilter::SkipFilter, parse_ctx->allocator(), (yyvsp[(2) - (2)].fval)); + if (nullptr == (yyval.fval)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter((yyval.fval)))) { + LOG_WARN("failed to store filter", K(ret)); + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&((yyloc)), parse_ctx, "failed to parse SkipFilter"); + YYABORT; + } + ;} + break; + + case 6: + +/* Line 1455 of yacc.c */ +#line 116 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + (yyval.fval) = OB_NEWx(hfilter::WhileMatchFilter, parse_ctx->allocator(), (yyvsp[(2) - (2)].fval)); + if (nullptr == (yyval.fval)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter((yyval.fval)))) { + LOG_WARN("failed to store filter", K(ret)); + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&((yyloc)), parse_ctx, "failed to parse WhileFilter"); + YYABORT; + } + ;} + break; + + case 7: + +/* Line 1455 of yacc.c */ +#line 131 "../../../src/observer/table/htable_filter_tab.yxx" + { + (yyval.fval) = (yyvsp[(1) - (1)].fval); + ;} + break; + + case 8: + +/* Line 1455 of yacc.c */ +#line 138 "../../../src/observer/table/htable_filter_tab.yxx" + { (yyval.fval) = (yyvsp[(2) - (3)].fval); ;} + break; + + case 9: + +/* Line 1455 of yacc.c */ +#line 140 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_comparator((yyvsp[(5) - (6)].sval), comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + (yyval.fval) = OB_NEWx(hfilter::RowFilter, parse_ctx->allocator(), (yyvsp[(3) - (6)].cmp_op), comparable); + if (nullptr == (yyval.fval)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(static_cast((yyval.fval))->check_arguments())) { + LOG_WARN("failed to check arguments", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter((yyval.fval)))) { + LOG_WARN("failed to store filter", K(ret)); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&((yyloc)), parse_ctx, "failed to parse RowFilter"); + YYABORT; + } + ;} + break; + + case 10: + +/* Line 1455 of yacc.c */ +#line 162 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_comparator((yyvsp[(5) - (6)].sval), comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + (yyval.fval) = OB_NEWx(hfilter::QualifierFilter, parse_ctx->allocator(), (yyvsp[(3) - (6)].cmp_op), comparable); + if (nullptr == (yyval.fval)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(static_cast((yyval.fval))->check_arguments())) { + LOG_WARN("failed to check arguments", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter((yyval.fval)))) { + LOG_WARN("failed to store filter", K(ret)); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&((yyloc)), parse_ctx, "failed to parse QualifierFilter"); + YYABORT; + } + ;} + break; + + case 11: + +/* Line 1455 of yacc.c */ +#line 184 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_comparator((yyvsp[(5) - (6)].sval), comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + (yyval.fval) = OB_NEWx(hfilter::ValueFilter, parse_ctx->allocator(), (yyvsp[(3) - (6)].cmp_op), comparable); + if (nullptr == (yyval.fval)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(static_cast((yyval.fval))->check_arguments())) { + LOG_WARN("failed to check arguments", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter((yyval.fval)))) { + LOG_WARN("failed to store filter", K(ret)); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&((yyloc)), parse_ctx, "failed to parse ValueFilter"); + YYABORT; + } + ;} + break; + + case 12: + +/* Line 1455 of yacc.c */ +#line 206 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_prefix_comparator((yyvsp[(3) - (4)].sval), comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + (yyval.fval) = OB_NEWx(hfilter::RowFilter, parse_ctx->allocator(), hfilter::CompareOperator::EQUAL, comparable); + if (nullptr == (yyval.fval)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(static_cast((yyval.fval))->check_arguments())) { + LOG_WARN("failed to check arguments", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter((yyval.fval)))) { + LOG_WARN("failed to store filter", K(ret)); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&((yyloc)), parse_ctx, "failed to parse PrefixFilter"); + YYABORT; + } + ;} + break; + + case 13: + +/* Line 1455 of yacc.c */ +#line 228 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_comparator((yyvsp[(9) - (14)].sval), comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + ObString family((yyvsp[(3) - (14)].sval).len_, (yyvsp[(3) - (14)].sval).str_); + ObString qualifier((yyvsp[(5) - (14)].sval).len_, (yyvsp[(5) - (14)].sval).str_); + bool filter_if_missing = ((yyvsp[(11) - (14)].ival) == 1); + bool latest_version_only = ((yyvsp[(13) - (14)].ival) == 1); + hfilter::SingleColumnValueFilter *filter = NULL; + (yyval.fval) = filter = OB_NEWx(hfilter::SingleColumnValueFilter, parse_ctx->allocator(), family, qualifier, (yyvsp[(7) - (14)].cmp_op), comparable); + if (nullptr == (yyval.fval)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter((yyval.fval)))) { + LOG_WARN("failed to store filter", K(ret)); + } else { + filter->set_filter_if_missing(filter_if_missing); + filter->set_latest_version_only(latest_version_only); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&((yyloc)), parse_ctx, "failed to parse SingleColumnValueFilter"); + YYABORT; + } + ;} + break; + + case 14: + +/* Line 1455 of yacc.c */ +#line 256 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_comparator((yyvsp[(9) - (10)].sval), comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + ObString family((yyvsp[(3) - (10)].sval).len_, (yyvsp[(3) - (10)].sval).str_); + ObString qualifier((yyvsp[(5) - (10)].sval).len_, (yyvsp[(5) - (10)].sval).str_); + const bool filter_if_missing = false; + const bool latest_version_only = true; + hfilter::SingleColumnValueFilter *filter = NULL; + (yyval.fval) = filter = OB_NEWx(hfilter::SingleColumnValueFilter, parse_ctx->allocator(), family, qualifier, (yyvsp[(7) - (10)].cmp_op), comparable); + if (nullptr == (yyval.fval)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter((yyval.fval)))) { + LOG_WARN("failed to store filter", K(ret)); + } else { + filter->set_filter_if_missing(filter_if_missing); + filter->set_latest_version_only(latest_version_only); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&((yyloc)), parse_ctx, "failed to parse SingleColumnValueFilter"); + YYABORT; + } + ;} + break; + + case 15: + +/* Line 1455 of yacc.c */ +#line 284 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_NOT_SUPPORTED; + UNUSED(ret); + ob_hfilter_error(&((yyloc)), parse_ctx, "PageFilter not supported"); + YYABORT; + ;} + break; + + case 16: + +/* Line 1455 of yacc.c */ +#line 291 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + (yyval.fval) = OB_NEWx(hfilter::ColumnCountGetFilter, parse_ctx->allocator(), (yyvsp[(3) - (4)].lval)); + if (nullptr == (yyval.fval)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter((yyval.fval)))) { + LOG_WARN("failed to store filter", K(ret)); + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&((yyloc)), parse_ctx, "failed to parse ColumnCountGetFilter"); + YYABORT; + } + ;} + break; + + case 17: + +/* Line 1455 of yacc.c */ +#line 306 "../../../src/observer/table/htable_filter_tab.yxx" + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_comparator((yyvsp[(5) - (12)].sval), comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + const ObString family((yyvsp[(7) - (12)].sval).len_, (yyvsp[(7) - (12)].sval).str_); + const ObString qualifier((yyvsp[(9) - (12)].sval).len_, (yyvsp[(9) - (12)].sval).str_); + const bool value_is_null = ((yyvsp[(11) - (12)].ival) == 1); + hfilter::CheckAndMutateFilter *filter = NULL; + (yyval.fval) = filter = OB_NEWx(hfilter::CheckAndMutateFilter, parse_ctx->allocator(), family, qualifier, (yyvsp[(3) - (12)].cmp_op), comparable, value_is_null); + if (nullptr == (yyval.fval)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter((yyval.fval)))) { + LOG_WARN("failed to store filter", K(ret)); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&((yyloc)), parse_ctx, "failed to parse CheckAndMutateFilter"); + YYABORT; + } + ;} + break; + + case 18: + +/* Line 1455 of yacc.c */ +#line 331 "../../../src/observer/table/htable_filter_tab.yxx" + { (yyval.sval) = (yyvsp[(1) - (1)].sval); ;} + break; + + case 19: + +/* Line 1455 of yacc.c */ +#line 334 "../../../src/observer/table/htable_filter_tab.yxx" + { (yyval.sval) = (yyvsp[(1) - (1)].sval); ;} + break; + + case 20: + +/* Line 1455 of yacc.c */ +#line 337 "../../../src/observer/table/htable_filter_tab.yxx" + { (yyval.cmp_op) = hfilter::CompareOperator::LESS; ;} + break; + + case 21: + +/* Line 1455 of yacc.c */ +#line 338 "../../../src/observer/table/htable_filter_tab.yxx" + { (yyval.cmp_op) = hfilter::CompareOperator::LESS_OR_EQUAL; ;} + break; + + case 22: + +/* Line 1455 of yacc.c */ +#line 339 "../../../src/observer/table/htable_filter_tab.yxx" + { (yyval.cmp_op) = hfilter::CompareOperator::EQUAL; ;} + break; + + case 23: + +/* Line 1455 of yacc.c */ +#line 340 "../../../src/observer/table/htable_filter_tab.yxx" + { (yyval.cmp_op) = hfilter::CompareOperator::NOT_EQUAL; ;} + break; + + case 24: + +/* Line 1455 of yacc.c */ +#line 341 "../../../src/observer/table/htable_filter_tab.yxx" + { (yyval.cmp_op) = hfilter::CompareOperator::GREATER; ;} + break; + + case 25: + +/* Line 1455 of yacc.c */ +#line 342 "../../../src/observer/table/htable_filter_tab.yxx" + { (yyval.cmp_op) = hfilter::CompareOperator::GREATER_OR_EQUAL; ;} + break; + + case 26: + +/* Line 1455 of yacc.c */ +#line 343 "../../../src/observer/table/htable_filter_tab.yxx" + { (yyval.cmp_op) = hfilter::CompareOperator::NO_OP; ;} + break; + + case 27: + +/* Line 1455 of yacc.c */ +#line 347 "../../../src/observer/table/htable_filter_tab.yxx" + { (yyval.sval) = (yyvsp[(1) - (1)].sval); ;} + break; + + + +/* Line 1455 of yacc.c */ +#line 1904 "../../../src/observer/table/htable_filter_tab.cxx" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (&yylloc, parse_ctx, YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (&yylloc, parse_ctx, yymsg); + } + else + { + yyerror (&yylloc, parse_ctx, YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + yyerror_range[0] = yylloc; + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, parse_ctx); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + yyerror_range[0] = yylsp[1-yylen]; + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[0] = *yylsp; + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yylsp, parse_ctx); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + yyerror_range[1] = yylloc; + /* Using YYLLOC is tempting, but would change the location of + the lookahead. YYLOC is available though. */ + YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); + *++yylsp = yyloc; + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (&yylloc, parse_ctx, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, parse_ctx); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yylsp, parse_ctx); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + +/* Line 1675 of yacc.c */ +#line 349 "../../../src/observer/table/htable_filter_tab.yxx" + + diff --git a/src/observer/table/htable_filter_tab.hxx b/src/observer/table/htable_filter_tab.hxx new file mode 100644 index 0000000000000000000000000000000000000000..5c05db9750fbfc00637962fe8b0ec57e4358cdba --- /dev/null +++ b/src/observer/table/htable_filter_tab.hxx @@ -0,0 +1,110 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + END = 0, + RowFilter = 258, + ValueFilter = 259, + QualifierFilter = 260, + SingleColumnValueFilter = 261, + PageFilter = 262, + ColumnCountGetFilter = 263, + CheckAndMutateFilter = 264, + PrefixFilter = 265, + LESS = 266, + LESS_OR_EQUAL = 267, + EQUAL = 268, + NOT_EQUAL = 269, + GREATER = 270, + GREATER_OR_EQUAL = 271, + NO_OP = 272, + BOOL_VALUE = 273, + STRING_VALUE = 274, + INT_VALUE = 275, + OR = 276, + AND = 277, + WHILE = 278, + SKIP = 279, + ERROR = 280 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 1676 of yacc.c */ +#line 23 "../../../src/observer/table/htable_filter_tab.yxx" + + int32_t ival; + int64_t lval; + oceanbase::table::hfilter::CompareOperator cmp_op; + oceanbase::table::ObHTableFilterParser::SimpleString sval; + oceanbase::table::hfilter::Filter *fval; + + + +/* Line 1676 of yacc.c */ +#line 88 "../../../src/observer/table/htable_filter_tab.hxx" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + + diff --git a/src/observer/table/htable_filter_tab.yxx b/src/observer/table/htable_filter_tab.yxx new file mode 100644 index 0000000000000000000000000000000000000000..09849756ecc56c4dbea1e694dfd9b5d15f42dc23 --- /dev/null +++ b/src/observer/table/htable_filter_tab.yxx @@ -0,0 +1,349 @@ +/* Location tracking. */ +%locations +/* Pure yylex. */ +%define api.pure +/* Pure yyparse. */ +%parse-param {oceanbase::table::ObHTableFilterParser *parse_ctx} +%verbose +%error-verbose +%name-prefix "ob_hfilter_" +%{ +#define USING_LOG_PREFIX SERVER +#include +#include "observer/table/ob_htable_filters.h" +#include "observer/table/ob_htable_filter_parser.h" +#include "observer/table/htable_filter_lex.hxx" +#define YYDEBUG 1 +#define YYLEX_PARAM (parse_ctx->scanner_) +using namespace oceanbase::table; +using namespace oceanbase::common; +%} +// Symbols. +%union +{ + int32_t ival; + int64_t lval; + oceanbase::table::hfilter::CompareOperator cmp_op; + oceanbase::table::ObHTableFilterParser::SimpleString sval; + oceanbase::table::hfilter::Filter *fval; +}; + +%token RowFilter ValueFilter QualifierFilter SingleColumnValueFilter PageFilter ColumnCountGetFilter +%token CheckAndMutateFilter PrefixFilter +%token LESS LESS_OR_EQUAL EQUAL NOT_EQUAL GREATER GREATER_OR_EQUAL NO_OP +%token BOOL_VALUE +%token STRING_VALUE +%token INT_VALUE + +%left OR +%left AND +%right SKIP WHILE +%token END 0 "end of file" +%token ERROR + +%type simple_filter filter result_filter +%type family qualifier comparator +%type compare_op + +%start result_filter +%% +//////////////////////////////////////////////////////////////// +result_filter: filter END { + parse_ctx->set_result_filter($1); + YYACCEPT; + } + ; + +filter: + filter AND filter %prec AND + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::FilterListBase *filter_list = nullptr; + $$ = filter_list = OB_NEWx(hfilter::FilterListAND, parse_ctx->allocator(), + hfilter::FilterListBase::Operator::MUST_PASS_ALL); + if (nullptr == $$) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter($$))) { + LOG_WARN("failed to store filter", K(ret)); + } else if (OB_FAIL(filter_list->add_filter($1))) { + LOG_WARN("failed to add filter to list", K(ret)); + } else if (OB_FAIL(filter_list->add_filter($3))) { + LOG_WARN("failed to add filter to list", K(ret)); + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&(@$), parse_ctx, "failed to parse FilterList with AND"); + YYABORT; + } + } + | filter OR filter %prec OR + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::FilterListBase *filter_list = nullptr; + $$ = filter_list = OB_NEWx(hfilter::FilterListOR, parse_ctx->allocator(), + hfilter::FilterListBase::Operator::MUST_PASS_ONE); + if (nullptr == $$) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter($$))) { + LOG_WARN("failed to store filter", K(ret)); + } else if (OB_FAIL(filter_list->add_filter($1))) { + LOG_WARN("failed to add filter to list", K(ret)); + } else if (OB_FAIL(filter_list->add_filter($3))) { + LOG_WARN("failed to add filter to list", K(ret)); + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&(@$), parse_ctx, "failed to parse FilterList with AND"); + YYABORT; + } + } + | SKIP filter %prec SKIP + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + $$ = OB_NEWx(hfilter::SkipFilter, parse_ctx->allocator(), $2); + if (nullptr == $$) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter($$))) { + LOG_WARN("failed to store filter", K(ret)); + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&(@$), parse_ctx, "failed to parse SkipFilter"); + YYABORT; + } + } + | WHILE filter %prec WHILE + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + $$ = OB_NEWx(hfilter::WhileMatchFilter, parse_ctx->allocator(), $2); + if (nullptr == $$) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter($$))) { + LOG_WARN("failed to store filter", K(ret)); + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&(@$), parse_ctx, "failed to parse WhileFilter"); + YYABORT; + } + } + | simple_filter + { + $$ = $1; + } + ; + +simple_filter: + '(' filter ')' + { $$ = $2; } + | RowFilter '(' compare_op ',' comparator ')' + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_comparator($5, comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + $$ = OB_NEWx(hfilter::RowFilter, parse_ctx->allocator(), $3, comparable); + if (nullptr == $$) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(static_cast($$)->check_arguments())) { + LOG_WARN("failed to check arguments", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter($$))) { + LOG_WARN("failed to store filter", K(ret)); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&(@$), parse_ctx, "failed to parse RowFilter"); + YYABORT; + } + } + | QualifierFilter '(' compare_op ',' comparator ')' + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_comparator($5, comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + $$ = OB_NEWx(hfilter::QualifierFilter, parse_ctx->allocator(), $3, comparable); + if (nullptr == $$) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(static_cast($$)->check_arguments())) { + LOG_WARN("failed to check arguments", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter($$))) { + LOG_WARN("failed to store filter", K(ret)); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&(@$), parse_ctx, "failed to parse QualifierFilter"); + YYABORT; + } + } + | ValueFilter '(' compare_op ',' comparator ')' + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_comparator($5, comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + $$ = OB_NEWx(hfilter::ValueFilter, parse_ctx->allocator(), $3, comparable); + if (nullptr == $$) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(static_cast($$)->check_arguments())) { + LOG_WARN("failed to check arguments", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter($$))) { + LOG_WARN("failed to store filter", K(ret)); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&(@$), parse_ctx, "failed to parse ValueFilter"); + YYABORT; + } + } + | PrefixFilter '(' STRING_VALUE ')' + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_prefix_comparator($3, comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + $$ = OB_NEWx(hfilter::RowFilter, parse_ctx->allocator(), hfilter::CompareOperator::EQUAL, comparable); + if (nullptr == $$) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(static_cast($$)->check_arguments())) { + LOG_WARN("failed to check arguments", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter($$))) { + LOG_WARN("failed to store filter", K(ret)); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&(@$), parse_ctx, "failed to parse PrefixFilter"); + YYABORT; + } + } + | SingleColumnValueFilter '(' family ',' qualifier ',' compare_op ',' comparator ',' BOOL_VALUE ',' BOOL_VALUE ')' + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_comparator($9, comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + ObString family($3.len_, $3.str_); + ObString qualifier($5.len_, $5.str_); + bool filter_if_missing = ($11 == 1); + bool latest_version_only = ($13 == 1); + hfilter::SingleColumnValueFilter *filter = NULL; + $$ = filter = OB_NEWx(hfilter::SingleColumnValueFilter, parse_ctx->allocator(), family, qualifier, $7, comparable); + if (nullptr == $$) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter($$))) { + LOG_WARN("failed to store filter", K(ret)); + } else { + filter->set_filter_if_missing(filter_if_missing); + filter->set_latest_version_only(latest_version_only); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&(@$), parse_ctx, "failed to parse SingleColumnValueFilter"); + YYABORT; + } + } + | SingleColumnValueFilter '(' family ',' qualifier ',' compare_op ',' comparator ')' + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_comparator($9, comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + ObString family($3.len_, $3.str_); + ObString qualifier($5.len_, $5.str_); + const bool filter_if_missing = false; + const bool latest_version_only = true; + hfilter::SingleColumnValueFilter *filter = NULL; + $$ = filter = OB_NEWx(hfilter::SingleColumnValueFilter, parse_ctx->allocator(), family, qualifier, $7, comparable); + if (nullptr == $$) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter($$))) { + LOG_WARN("failed to store filter", K(ret)); + } else { + filter->set_filter_if_missing(filter_if_missing); + filter->set_latest_version_only(latest_version_only); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&(@$), parse_ctx, "failed to parse SingleColumnValueFilter"); + YYABORT; + } + } + | PageFilter '(' INT_VALUE ')' + { + int &ret = parse_ctx->error_code_ = OB_NOT_SUPPORTED; + UNUSED(ret); + ob_hfilter_error(&(@$), parse_ctx, "PageFilter not supported"); + YYABORT; + } + | ColumnCountGetFilter '(' INT_VALUE ')' + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + $$ = OB_NEWx(hfilter::ColumnCountGetFilter, parse_ctx->allocator(), $3); + if (nullptr == $$) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter($$))) { + LOG_WARN("failed to store filter", K(ret)); + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&(@$), parse_ctx, "failed to parse ColumnCountGetFilter"); + YYABORT; + } + } + | CheckAndMutateFilter '(' compare_op ',' comparator ',' family ',' qualifier ',' BOOL_VALUE')' + { + int &ret = parse_ctx->error_code_ = OB_SUCCESS; + hfilter::Comparable *comparable = nullptr; + if (OB_FAIL(parse_ctx->create_comparator($5, comparable))) { + LOG_WARN("failed to create comparator", K(ret)); + } else { + const ObString family($7.len_, $7.str_); + const ObString qualifier($9.len_, $9.str_); + const bool value_is_null = ($11 == 1); + hfilter::CheckAndMutateFilter *filter = NULL; + $$ = filter = OB_NEWx(hfilter::CheckAndMutateFilter, parse_ctx->allocator(), family, qualifier, $3, comparable, value_is_null); + if (nullptr == $$) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(parse_ctx->store_filter($$))) { + LOG_WARN("failed to store filter", K(ret)); + } + } + if (OB_SUCCESS != ret) { + ob_hfilter_error(&(@$), parse_ctx, "failed to parse CheckAndMutateFilter"); + YYABORT; + } + } + ; +family: + STRING_VALUE { $$ = $1; } + ; +qualifier: + STRING_VALUE { $$ = $1; } + ; +compare_op: + LESS { $$ = hfilter::CompareOperator::LESS; } + | LESS_OR_EQUAL { $$ = hfilter::CompareOperator::LESS_OR_EQUAL; } + | EQUAL { $$ = hfilter::CompareOperator::EQUAL; } + | NOT_EQUAL { $$ = hfilter::CompareOperator::NOT_EQUAL; } + | GREATER { $$ = hfilter::CompareOperator::GREATER; } + | GREATER_OR_EQUAL { $$ = hfilter::CompareOperator::GREATER_OR_EQUAL; } + | NO_OP { $$ = hfilter::CompareOperator::NO_OP; } + ; +comparator: + STRING_VALUE + { $$ = $1; } + ; +%% diff --git a/src/observer/table/ob_htable_filter_operator.cpp b/src/observer/table/ob_htable_filter_operator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4bbfcfcd9e130e6a364e37ca8aae32f993d0ca89 --- /dev/null +++ b/src/observer/table/ob_htable_filter_operator.cpp @@ -0,0 +1,1161 @@ +/** + * 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. + */ + +#define USING_LOG_PREFIX SERVER +#include "ob_htable_filter_operator.h" +#include "ob_htable_utils.h" +#include "lib/json/ob_json.h" +#include "share/ob_errno.h" +using namespace oceanbase::common; +using namespace oceanbase::table; +using namespace oceanbase::table::hfilter; + +int ObHColumnDescriptor::from_string(const common::ObString &str) +{ + int ret = OB_SUCCESS; + ObArenaAllocator allocator; + json::Parser json_parser; + json::Value *ast = NULL; + if (str.empty()) { + // skip + } else if (OB_FAIL(json_parser.init(&allocator))) { + LOG_WARN("failed to init json parser", K(ret)); + } else if (OB_FAIL(json_parser.parse(str.ptr(), str.length(), ast))) { + LOG_WARN("failed to parse", K(ret), K(str)); + ret = OB_SUCCESS; + } else if (NULL != ast + && ast->get_type() == json::JT_OBJECT + && ast->get_object().get_size() == 1) { + json::Pair *kv = ast->get_object().get_first(); + if (NULL != kv && kv != ast->get_object().get_header()) { + if (kv->name_.case_compare("HColumnDescriptor") == 0) { + ast = kv->value_; + if (NULL != ast && ast->get_type() == json::JT_OBJECT) { + DLIST_FOREACH(elem, ast->get_object()) { + if (elem->name_.case_compare("TimeToLive") == 0) { + json::Value *ttl_val = elem->value_; + if (NULL != ttl_val && ttl_val->get_type() == json::JT_NUMBER) { + time_to_live_ = static_cast(ttl_val->get_number()); + } + } + } // end foreach + } + } + } + } + return ret; +} + +//////////////////////////////////////////////////////////////// +class ObHTableColumnTracker::ColumnCountComparator +{ +public: + bool operator()(const ColumnCount &a, const ColumnCount &b) const + { + return a.first.compare(b.first) < 0; + } +}; + +class ObHTableColumnTracker::ColumnCountReverseComparator +{ +public: + bool operator()(const ColumnCount &a, const ColumnCount &b) const + { + return a.first.compare(b.first) > 0; + } +}; + +void ObHTableColumnTracker::set_ttl(int32_t ttl_value) +{ + if (ttl_value > 0) { + int64_t now = ObTimeUtility::current_time(); + now = now / 1000; // us -> ms + oldest_stamp_ = now - (ttl_value * 1000LL); + LOG_DEBUG("[yzfdebug] set ttl", K(ttl_value), K(now), K_(oldest_stamp)); + NG_TRACE_EXT(t, OB_ID(arg1), ttl_value, OB_ID(arg2), oldest_stamp_); + } +} + +bool ObHTableColumnTracker::is_done(int64_t timestamp) const +{ + return min_versions_ <= 0 && is_expired(timestamp); +} + +//////////////////////////////////////////////////////////////// +ObHTableExplicitColumnTracker::ObHTableExplicitColumnTracker() + :columns_(), + curr_column_idx_(0), + curr_column_(NULL) +{} + +int ObHTableExplicitColumnTracker::init(const table::ObHTableFilter &htable_filter, common::ObQueryFlag::ScanOrder &scan_order) +{ + int ret = OB_SUCCESS; + max_versions_ = htable_filter.get_max_versions(); + if (ObQueryFlag::Forward == scan_order || ObQueryFlag::Reverse == scan_order){ + set_scan_order(scan_order); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("the scan order doesn't match what we support", K(ret),K(scan_order)); + } + + const ObIArray &qualifiers = htable_filter.get_columns(); + const int64_t N = qualifiers.count(); + if (OB_SUCC(ret) && N <= 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("should not use ExplicitColumnTracker", K(ret)); + } + for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) + { + if (OB_FAIL(columns_.push_back(std::make_pair(qualifiers.at(i), 0)))) { + LOG_WARN("failed to push back", K(ret)); + } + } // end for + if (OB_SUCC(ret)) { + // sort qualifiers + ColumnCount *end = &columns_.at(columns_.count() - 1); + ++end; + if (common::ObQueryFlag::Reverse == tracker_scan_order_) { + std::sort(&columns_.at(0), end, ColumnCountReverseComparator()); + } else { + std::sort(&columns_.at(0), end, ColumnCountComparator()); + } + } + + if (OB_SUCC(ret)) { + // check duplicated qualifiers + for (int64_t i = 0; OB_SUCCESS == ret && i < N - 1; ++i) + { + if (columns_.at(i).first == columns_.at(i+1).first) { + ret = OB_ERR_PARAM_DUPLICATE; + LOG_WARN("duplicated qualifiers", K(ret), "cq", columns_.at(i).first, K(i)); + } + } // end for + } + return ret; +} + +bool ObHTableExplicitColumnTracker::done() const +{ + return curr_column_idx_ >= columns_.count(); +} + +int ObHTableExplicitColumnTracker::check_column(const ObHTableCell &cell, ObHTableMatchCode &match_code) +{ + int ret = OB_SUCCESS; + int cmp_ret = 0; + do { + // No more columns left, we are done with this query + if (done()) { + match_code = ObHTableMatchCode::SEEK_NEXT_ROW; // done row + break; + } + // No more columns to match against, done with storefile + // @todo here + // Compare specific column to current column + // + if (ObQueryFlag::Reverse == tracker_scan_order_) { + cmp_ret = ObHTableUtils::compare_qualifier(curr_column_->first, cell.get_qualifier()); + } else { + cmp_ret = ObHTableUtils::compare_qualifier(cell.get_qualifier(), curr_column_->first); + } + LOG_DEBUG("[sldebug] compare qualifier res and scan order", K(tracker_scan_order_), K(cell.get_qualifier()), K(cell.get_rowkey()), K(cmp_ret), K(curr_column_idx_)); + // Column Matches. Return include code. The caller would call checkVersions + // to limit the number of versions. + if (0 == cmp_ret) { + match_code = ObHTableMatchCode::INCLUDE; + break; + } + // reset_timestamp(); + if (cmp_ret < 0) { + // The current KV is smaller than the column the ExplicitColumnTracker + // is interested in, so seek to that column of interest. + match_code = ObHTableMatchCode::SEEK_NEXT_COL; + break; + } + // The current KV is bigger than the column the ExplicitColumnTracker + // is interested in. That means there is no more data for the column + // of interest. Advance the ExplicitColumnTracker state to next + // column of interest, and check again. + if (cmp_ret > 0) { + ++curr_column_idx_; + if (done()) { + match_code = ObHTableMatchCode::SEEK_NEXT_ROW; // done row + break; + } + curr_column_ = &columns_.at(curr_column_idx_); + // continue for next column of interest + } + } while (true); + return ret; +} + +int ObHTableExplicitColumnTracker::check_versions(const ObHTableCell &cell, ObHTableMatchCode &match_code) +{ + int ret = OB_SUCCESS; + int32_t count = ++curr_column_->second; + int64_t timestamp = cell.get_timestamp(); + LOG_DEBUG("[yzfdebug] check versions", K(count), K_(max_versions), K(timestamp), + K_(min_versions), K_(oldest_stamp), "is_expired", is_expired(timestamp)); + // in reverse scan, check the cell timeout condition with ttl. Kick off the timeout cell from res. + if(ObQueryFlag::Reverse == tracker_scan_order_) { + match_code = check_version(cell.get_timestamp()); + } else { + if (count >= max_versions_ + || (is_expired(timestamp) && count >= min_versions_)) { + // Done with versions for this column + ++curr_column_idx_; + if (done()) { + match_code = ObHTableMatchCode::INCLUDE_AND_SEEK_NEXT_ROW; // done row + } else { + // We are done with current column; advance to next column + // of interest. + curr_column_ = &columns_.at(curr_column_idx_); + match_code = ObHTableMatchCode::INCLUDE_AND_SEEK_NEXT_COL; + } + } else { + match_code = ObHTableMatchCode::INCLUDE; + } + } + return ret; +} + +ObHTableMatchCode ObHTableExplicitColumnTracker::check_version(int64_t timestamp) +{ + ObHTableMatchCode match_code = ObHTableMatchCode::INCLUDE; + if (!is_expired(timestamp)) { + // keep the KV if required by minversions or it is not expired, yet + match_code = ObHTableMatchCode::INCLUDE; + } else { + match_code = ObHTableMatchCode::SEEK_NEXT_COL; + } + return match_code; +} + +// Called between every row. +void ObHTableExplicitColumnTracker::reset() +{ + curr_column_idx_ = 0; + curr_column_ = &columns_.at(curr_column_idx_); + const int64_t N = columns_.count(); + for (int64_t i = 0; i < N; ++i) + { + columns_.at(i).second = 0; + } // end for +} + +void ObHTableExplicitColumnTracker::done_with_column(const ObHTableCell &cell) +{ + while (NULL != curr_column_) { + int cmp_ret = ObHTableUtils::compare_qualifier(cell.get_qualifier(), curr_column_->first); + if (cmp_ret < 0) { + break; + } else { + ++curr_column_idx_; + if (done()) { + curr_column_ = NULL; + } else { + curr_column_ = &columns_.at(curr_column_idx_); + } + if (0 == cmp_ret) { + break; + } + } + } +} + +int ObHTableExplicitColumnTracker::get_next_column_or_row(const ObHTableCell &cell, ObHTableMatchCode &match_code) +{ + done_with_column(cell); + if (NULL == curr_column_) { + match_code = ObHTableMatchCode::SEEK_NEXT_ROW; + } else { + match_code = ObHTableMatchCode::SEEK_NEXT_COL; + } + return OB_SUCCESS; +} + +//////////////////////////////////////////////////////////////// +ObHTableWildcardColumnTracker::ObHTableWildcardColumnTracker() + :allocator_(ObModIds::TABLE_PROC), + current_qualifier_(), + current_count_(0) +{} + +int ObHTableWildcardColumnTracker::init(const table::ObHTableFilter &htable_filter, common::ObQueryFlag::ScanOrder &scan_order) +{ + int ret = OB_SUCCESS; + max_versions_ = htable_filter.get_max_versions(); + if (ObQueryFlag::Forward == scan_order || ObQueryFlag::Reverse == scan_order){ + set_scan_order(scan_order); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("the scan order doesn't match what we support", K(ret),K(scan_order)); + } + // @todo set min_versions_ and oldest_stamp_ + return ret; +} + +int ObHTableWildcardColumnTracker::check_column(const ObHTableCell &cell, ObHTableMatchCode &match_code) +{ + UNUSED(cell); + match_code = ObHTableMatchCode::INCLUDE; + return OB_SUCCESS; +} + +int ObHTableWildcardColumnTracker::reset_cell(const ObHTableCell &cell) +{ + int ret = OB_SUCCESS; + current_count_ = 0; + allocator_.reuse(); + if (OB_FAIL(ob_write_string(allocator_, cell.get_qualifier(), current_qualifier_))) { + LOG_WARN("failed to copy qualifier", K(ret)); + } + return ret; +} + +int ObHTableWildcardColumnTracker::check_versions(const ObHTableCell &cell, ObHTableMatchCode &match_code) +{ + int ret = OB_SUCCESS; + int cmp_ret; + if (current_qualifier_.empty()) { + // first iteration + ret = reset_cell(cell); + if (OB_SUCC(ret)) { + match_code = check_version(cell.get_timestamp()); + } + } else { + if (common::ObQueryFlag::Reverse == tracker_scan_order_) { + cmp_ret = ObHTableUtils::compare_qualifier(current_qualifier_, cell.get_qualifier()); + } else { + cmp_ret = ObHTableUtils::compare_qualifier(cell.get_qualifier(),current_qualifier_); + } + if (0 == cmp_ret) { + match_code = check_version(cell.get_timestamp()); + } else if (cmp_ret > 0) { + // a new qualifier + ret = reset_cell(cell); + if (OB_SUCC(ret)) { + match_code = check_version(cell.get_timestamp()); + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("cell qualifier less than current one", K(ret), K(cell), K_(current_qualifier)); + } + } + return ret; +} + +ObHTableMatchCode ObHTableWildcardColumnTracker::check_version(int64_t timestamp) +{ + ObHTableMatchCode match_code = ObHTableMatchCode::INCLUDE; + if (ObQueryFlag::Reverse == tracker_scan_order_) { + if (!is_expired(timestamp)) { + // keep the KV if required by minversions or it is not expired, yet + match_code = ObHTableMatchCode::INCLUDE; + } else { + match_code = ObHTableMatchCode::SEEK_NEXT_COL; + } + } else { + ++current_count_; + if (current_count_ > max_versions_) { + match_code = ObHTableMatchCode::SEEK_NEXT_COL; + } else if (current_count_ <= min_versions_ + || !is_expired(timestamp)) { + // keep the KV if required by minversions or it is not expired, yet + match_code = ObHTableMatchCode::INCLUDE; + } else { + match_code = ObHTableMatchCode::SEEK_NEXT_COL; + } + } + return match_code; +} + +int ObHTableWildcardColumnTracker::get_next_column_or_row(const ObHTableCell &cell, ObHTableMatchCode &match_code) +{ + UNUSED(cell); + match_code = ObHTableMatchCode::SEEK_NEXT_COL; + return OB_SUCCESS; +} + +void ObHTableWildcardColumnTracker::reset() +{ + LOG_DEBUG("[yzfdebug] reset qualifier"); + current_qualifier_.reset(); +} + +//////////////////////////////////////////////////////////////// +ObHTableScanMatcher::ObHTableScanMatcher(const table::ObHTableFilter &htable_filter, + ObHTableColumnTracker *column_tracker /*= nullptr*/) + :time_range_(-htable_filter.get_max_stamp(), -htable_filter.get_min_stamp()), + column_tracker_(column_tracker), + hfilter_(NULL), + allocator_(ObModIds::TABLE_PROC), + curr_row_() +{ +} + +int ObHTableScanMatcher::pre_check(const ObHTableCell &cell, ObHTableMatchCode &match_code, bool &need_match_column) +{ + int ret = OB_SUCCESS; + need_match_column = false; + if (is_curr_row_empty()) { + // Since the curCell is null it means we are already sure that we have moved over to the next + // row + match_code = ObHTableMatchCode::DONE; + } else if (0 != ObHTableUtils::compare_rowkey(curr_row_, cell)) { + // if row key is changed, then we know that we have moved over to the next row + // WildcardColumnTracker will come to this branch + match_code = ObHTableMatchCode::DONE; + LOG_DEBUG("[yzfdebug] row changed", K(match_code), K(cell)); + } else if (column_tracker_->done()) { + match_code = ObHTableMatchCode::SEEK_NEXT_ROW; + } + // check for early out based on timestamp alone + else if (column_tracker_->is_done(cell.get_timestamp())) { + if (OB_FAIL(column_tracker_->get_next_column_or_row(cell, match_code))) { + LOG_WARN("failed to get next column or row", K(ret), K(cell)); + } + } + // @todo check if the cell is expired by cell TTL + else + { + // continue + need_match_column = true; + } + LOG_DEBUG("[yzfdebug] pre_check", K(ret), K(match_code), K(need_match_column)); + return ret; +} + +int ObHTableScanMatcher::match_column(const ObHTableCell &cell, ObHTableMatchCode &match_code) +{ + int ret = OB_SUCCESS; + int64_t timestamp = cell.get_timestamp(); + int cmp_tr = time_range_.compare(timestamp); + LOG_DEBUG("[yzfdebug] compare time range", K(timestamp), K(cmp_tr), K_(time_range)); + // STEP 0: Check if the timestamp is in the range + // @note timestamp is negative and in the descending order! + if (cmp_tr > 0) { + match_code = ObHTableMatchCode::SKIP; + } else if (cmp_tr < 0) { + if (OB_FAIL(column_tracker_->get_next_column_or_row(cell, match_code))) { + LOG_WARN("failed to get next column or row", K(ret), K(cell)); + } + } + // STEP 1: Check if the column is part of the requested columns + else if (OB_FAIL(column_tracker_->check_column(cell, match_code))) { + LOG_WARN("failed to check column", K(ret), K(cell)); + } else if (ObHTableMatchCode::INCLUDE != match_code) { + // nothing + } else { + /* + * STEP 2: check the number of versions needed. This method call returns SKIP, SEEK_NEXT_COL, + * INCLUDE, INCLUDE_AND_SEEK_NEXT_COL, or INCLUDE_AND_SEEK_NEXT_ROW. + */ + if (OB_FAIL(column_tracker_->check_versions(cell, match_code))) { + } else { + switch(match_code) { + case ObHTableMatchCode::SKIP: + case ObHTableMatchCode::SEEK_NEXT_COL: + break; + default: { + // It means it is INCLUDE, INCLUDE_AND_SEEK_NEXT_COL or INCLUDE_AND_SEEK_NEXT_ROW. + // in reverse scan order, functions which is filter cell and merge filter return code are completed at add_same_kq_to_res function + if (ObQueryFlag::Reverse != column_tracker_->get_scan_order()){ + if (NULL != hfilter_) { + hfilter::Filter::ReturnCode filter_rc; + if (OB_FAIL(hfilter_->filter_cell(cell, filter_rc))) { + LOG_WARN("failed to filter cell", K(ret)); + } else { + ObHTableMatchCode orig_code = match_code; + match_code = merge_filter_return_code(cell, match_code, filter_rc); + LOG_DEBUG("[yzfdebug] filter cell", K(filter_rc), K(orig_code), K(match_code)); + } + } + } + break; + } + } + } + } + return ret; +} +/* + * Call this when scan has filter. Decide the desired behavior by checkVersions's MatchCode and + * filterCell's ReturnCode. Cell may be skipped by filter, so the column versions in result may be + * less than user need. It need to check versions again when filter and columnTracker both include + * the cell. + */ +ObHTableMatchCode ObHTableScanMatcher::merge_filter_return_code(const ObHTableCell &cell, + const ObHTableMatchCode match_code, hfilter::Filter::ReturnCode filter_rc) +{ + ObHTableMatchCode ret_code = ObHTableMatchCode::INCLUDE; + common::ObQueryFlag::ScanOrder scan_order = column_tracker_->get_scan_order(); + UNUSED(cell); + UNUSED(match_code); + UNUSED(filter_rc); + switch(filter_rc) { + case Filter::ReturnCode::INCLUDE: + break; + case Filter::ReturnCode::INCLUDE_AND_NEXT_COL: + if (ObQueryFlag::Reverse == scan_order) { + ret_code = ObHTableMatchCode::INCLUDE; + } else { + if (ObHTableMatchCode::INCLUDE == match_code) { + ret_code = ObHTableMatchCode::INCLUDE_AND_SEEK_NEXT_COL; + } + } + + break; + case Filter::ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW: + ret_code = ObHTableMatchCode::INCLUDE_AND_SEEK_NEXT_ROW; + break; + case Filter::ReturnCode::SKIP: + if (match_code == ObHTableMatchCode::INCLUDE) { + return ObHTableMatchCode::SKIP; + } else if (match_code == ObHTableMatchCode::INCLUDE_AND_SEEK_NEXT_COL) { + return ObHTableMatchCode::SEEK_NEXT_COL; + } else if (match_code == ObHTableMatchCode::INCLUDE_AND_SEEK_NEXT_ROW) { + return ObHTableMatchCode::SEEK_NEXT_ROW; + } + break; + case Filter::ReturnCode::NEXT_COL: + if (match_code == ObHTableMatchCode::INCLUDE + || match_code == ObHTableMatchCode::INCLUDE_AND_SEEK_NEXT_COL) { + (void)column_tracker_->get_next_column_or_row(cell, ret_code); + return ret_code; + } else if (match_code == ObHTableMatchCode::INCLUDE_AND_SEEK_NEXT_ROW) { + return ObHTableMatchCode::SEEK_NEXT_ROW; + } + break; + case Filter::ReturnCode::NEXT_ROW: + return ObHTableMatchCode::SEEK_NEXT_ROW; + case Filter::ReturnCode::SEEK_NEXT_USING_HINT: + return ObHTableMatchCode::SEEK_NEXT_USING_HINT; + default: + break; + } + // We need to make sure that the number of cells returned will not exceed max version in scan + // when the match code is INCLUDE* case. + // @todo FIXME + return ret_code; +} + +int ObHTableScanMatcher::match(const ObHTableCell &cell, ObHTableMatchCode &match_code) +{ + int ret = OB_SUCCESS; + bool need_match_column = false; + if (NULL != hfilter_ && hfilter_->filter_all_remaining()) { + match_code = ObHTableMatchCode::DONE_SCAN; + } else if (OB_FAIL(pre_check(cell, match_code, need_match_column))) { + } else if (need_match_column) { + if (OB_FAIL(match_column(cell, match_code))) { + } + } + return ret; +} + +int ObHTableScanMatcher::create_key_for_next_col(common::ObArenaAllocator &allocator, + const ObHTableCell &cell, ObHTableCell *&next_cell) +{ + int ret = OB_SUCCESS; + const ObHTableColumnTracker::ColumnCount *curr_column = column_tracker_->get_curr_column(); + if (NULL == curr_column) { + ret = ObHTableUtils::create_last_cell_on_row_col(allocator, cell, next_cell); + } else { + ret = ObHTableUtils::create_first_cell_on_row_col(allocator, cell, curr_column->first, next_cell); + } + return ret; +} + +const ObHTableCell* ObHTableScanMatcher::get_curr_row() const +{ + const ObHTableCell* p = NULL; + if (NULL != curr_row_.get_ob_row()) { + p = &curr_row_; + } + return p; +} + +int ObHTableScanMatcher::set_to_new_row(const ObHTableCell &arg_curr_row) +{ + int ret = OB_SUCCESS; + const ObHTableCellEntity &curr_row = dynamic_cast(arg_curr_row); + // deep copy curr_row + if (NULL != curr_row_.get_ob_row()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid state", K(ret)); + } else if (NULL == curr_row.get_ob_row()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("obrow is null", K(ret)); + } else { + curr_ob_row_.reset(); + allocator_.reuse(); + if (OB_FAIL(ob_write_row(allocator_, *curr_row.get_ob_row(), curr_ob_row_))) { + LOG_WARN("failed to copy row", K(ret)); + } else { + curr_row_.set_ob_row(&curr_ob_row_); + } + } + // reset tracker + if (OB_SUCC(ret)) { + column_tracker_->reset(); + } + return ret; +} + +//////////////////////////////////////////////////////////////// +ObHTableRowIterator::ObHTableRowIterator(const ObTableQuery &query) + :child_op_(NULL), + htable_filter_(query.get_htable_filter()), + hfilter_(NULL), + limit_per_row_per_cf_(htable_filter_.get_max_results_per_column_family()), + offset_per_row_per_cf_(htable_filter_.get_row_offset_per_column_family()), + max_result_size_(query.get_max_result_size()), + batch_size_(query.get_batch()), + time_to_live_(0), + curr_cell_(), + allocator_(ObModIds::TABLE_PROC), + column_tracker_(NULL), + matcher_(NULL), + column_tracker_wildcard_(), + column_tracker_explicit_(), + matcher_impl_(htable_filter_), + scan_order_(query.get_scan_order()), + cell_count_(0), + count_per_row_(0), + has_more_cells_(true) +{} + +ObHTableRowIterator::~ObHTableRowIterator() +{ +} + +int ObHTableRowIterator::next_cell() +{ + ObNewRow *ob_row = NULL; + int ret = child_op_->get_next_row(ob_row); + if (OB_SUCCESS == ret) { + curr_cell_.set_ob_row(ob_row); + LOG_DEBUG("[yzfdebug] fetch next cell", K_(curr_cell)); + } else if (OB_ITER_END == ret) { + has_more_cells_ = false; + curr_cell_.set_ob_row(NULL); + matcher_->clear_curr_row(); + LOG_DEBUG("[yzfdebug] iterator end", K_(has_more_cells)); + } + return ret; +} + +int ObHTableRowIterator::reverse_next_cell(ObIArray &same_kq_cells, ObTableQueryResult *&out_result) +{ + ObNewRow *ob_row = NULL; + int ret = child_op_->get_next_row(ob_row); + if ((ObQueryFlag::Reverse == scan_order_ && OB_ITER_END == ret) || + (ObQueryFlag::Reverse == scan_order_ && OB_SUCCESS == ret && + NULL != hfilter_ && hfilter_->filter_all_remaining())) { + ret = add_same_kq_to_res(same_kq_cells, out_result); + same_kq_cells.reset(); + has_more_cells_ = false; + curr_cell_.set_ob_row(NULL); + matcher_->clear_curr_row(); + LOG_DEBUG("[sldebug] iterator end", K_(has_more_cells)); + } else if (OB_SUCCESS == ret) { + curr_cell_.set_ob_row(ob_row); + LOG_DEBUG("[sldebug] curr cell", K_(curr_cell)); + } else if (OB_SUCCESS != ret && OB_ITER_END != ret){ + LOG_WARN("the ret doesn't match what we had been expected",K(ret)); + } + return ret; +} + +int ObHTableRowIterator::add_same_kq_to_res(ObIArray &same_kq_cells, ObTableQueryResult *&out_result) { + int ret = OB_SUCCESS; + int N = same_kq_cells.count(); + int M = htable_filter_.get_max_versions(); + int end_idx = (N - M) > 0 ? (N - M) : 0; + for (int i = N - 1; OB_SUCC(ret) && i >= end_idx; i--) { + ObNewRow &tmp = same_kq_cells.at(i); + ObHTableCellEntity tmp_cell; + tmp_cell.set_ob_row(&tmp); + + //make timestamp as positive + int64_t timestamp = 0; + if (OB_FAIL(tmp.get_cell(ObHTableConstants::COL_IDX_T).get_int(timestamp))) { + LOG_WARN("failed to get timestamp",K(ret)); + } else { + tmp.get_cell(ObHTableConstants::COL_IDX_T).set_int(-timestamp); + } + if (OB_SUCC(ret)) { + ObHTableMatchCode match_code = ObHTableMatchCode::INCLUDE; + if (NULL != hfilter_ && ObHTableMatchCode::INCLUDE == match_code) { + hfilter::Filter::ReturnCode filter_rc; + if (OB_FAIL(hfilter_->filter_cell(tmp_cell, filter_rc))) { + LOG_WARN("failed to filter cell", K(ret)); + } else { + ObHTableMatchCode orig_code = match_code; + match_code = matcher_->merge_filter_return_code(tmp_cell, match_code, filter_rc); + LOG_DEBUG("[sldebug] filter cell", K(filter_rc), K(orig_code), K(match_code)); + } + } + + if (OB_SUCC(ret) && NULL != hfilter_ && hfilter_->filter_all_remaining()) { + match_code = ObHTableMatchCode::DONE_SCAN; + has_more_cells_ = false; + } + + if (OB_SUCC(ret) && ObHTableMatchCode::INCLUDE == match_code) { + if (OB_FAIL(out_result->add_row(tmp))) { + LOG_WARN("failed to add row to result", K(ret)); + } else { + ++cell_count_; + LOG_DEBUG("reverse add cell", K_(cell_count), K(tmp), K(out_result->get_row_count())); + } + } + } + } + + return ret; +} + +int ObHTableRowIterator::get_next_result(ObTableQueryResult *&out_result) +{ + int ret = OB_SUCCESS; + out_result = &one_hbase_row_; + one_hbase_row_.reset(); + ObIArray& same_kq_cells = get_same_kq_cells(); + ObHTableMatchCode match_code = ObHTableMatchCode::DONE_SCAN; // initialize + if (ObQueryFlag::Reverse == scan_order_ && (-1 != limit_per_row_per_cf_ || 0 != offset_per_row_per_cf_)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("server don't support set limit_per_row_per_cf_ and offset_per_row_per_cf_ in reverse scan yet", + K(ret), K(scan_order_), K(limit_per_row_per_cf_), K(offset_per_row_per_cf_)); + } + if (OB_SUCC(ret) && NULL == column_tracker_) { + // first iteration + if (htable_filter_.get_columns().count() <= 0) { + column_tracker_ = &column_tracker_wildcard_; + } else { + column_tracker_ = &column_tracker_explicit_; + } + if (OB_FAIL(column_tracker_->init(htable_filter_, scan_order_))) { + LOG_WARN("failed to init column tracker", K(ret)); + } else if (time_to_live_ > 0) { + column_tracker_->set_ttl(time_to_live_); + } + } + if (OB_SUCC(ret) && NULL == matcher_) { + matcher_ = &matcher_impl_; + matcher_->init(column_tracker_, hfilter_); + } + if (OB_SUCC(ret) && NULL == curr_cell_.get_ob_row()) { + ret = next_cell(); + } + if (OB_SUCC(ret) && matcher_->is_curr_row_empty()) { + count_per_row_ = 0; + ret = matcher_->set_to_new_row(curr_cell_); + } + bool loop = true; + if (OB_SUCC(ret)) { + if (NULL == matcher_->get_curr_row()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("matcher should have valid first cell", K(ret)); + } else if (NULL != hfilter_) { + const ObHTableCell &first_cell = curr_cell_; + if (hfilter_->filter_row_key(first_cell)) { + // filter out the current row and fetch the next row + hfilter_->reset(); + LOG_DEBUG("[yzfdebug] filter_row_key skip the row", K(ret)); + //loop = false; + matcher_->clear_curr_row(); + ret = seek_or_skip_to_next_row(curr_cell_); + } + } + } + while (OB_SUCC(ret) && loop) { + match_code = ObHTableMatchCode::DONE_SCAN; // initialize + if (OB_FAIL(matcher_->match(curr_cell_, match_code))) { + LOG_WARN("failed to match cell", K(ret)); + } else { + if (NULL == curr_cell_.get_ob_row()) { + LOG_DEBUG("[yzfdebug] matcher, curr_cell=NULL ", K(match_code)); + } else { + LOG_DEBUG("[yzfdebug] matcher", K_(curr_cell), K(match_code)); + } + switch(match_code) { + case ObHTableMatchCode::INCLUDE: + case ObHTableMatchCode::INCLUDE_AND_SEEK_NEXT_ROW: + case ObHTableMatchCode::INCLUDE_AND_SEEK_NEXT_COL: + case ObHTableMatchCode::DONE_REVERSE_SCAN: + if (NULL != hfilter_) { + const ObHTableCell *new_cell = NULL; + if (OB_FAIL(hfilter_->transform_cell(curr_cell_, new_cell))) { + LOG_WARN("failed to tranform cell", K(ret)); + break; + } else { + // @todo FIXME real transform + } + } + ++count_per_row_; + // whether reach per row limit + if (limit_per_row_per_cf_ > -1/*not unlimited*/ + && count_per_row_ > (offset_per_row_per_cf_ + limit_per_row_per_cf_)) { + // do what SEEK_NEXT_ROW does. + matcher_->clear_curr_row(); + if (ObQueryFlag::Reverse == scan_order_) { + ret = add_same_kq_to_res(same_kq_cells, out_result); + same_kq_cells.reset(); + } else { + ret = seek_or_skip_to_next_row(curr_cell_); + } + loop = false; + LOG_DEBUG("[yzfdebug] reach per row limit", K(ret), K_(offset_per_row_per_cf), K_(limit_per_row_per_cf), K_(count_per_row)); + break; + } + // whether skip offset + if (count_per_row_ > offset_per_row_per_cf_) { + if(OB_SUCC(ret) && ObQueryFlag::Reverse == scan_order_) { + // reverse scan if the current cell has the same key and qualifier with the last, match_code = INCLUDE; else match_code = DONE_REVERSE_SCAN; + // INCELUDE: put current cell into result vector + // DONE_REVERSE_SCAN: end this round scan, choose cell to return + ObString pre_key; + ObString pre_qualifier; + if (OB_SUCC(ret) && same_kq_cells.count() > 0) { + if (OB_FAIL(same_kq_cells.at(same_kq_cells.count() - 1).get_cell(ObHTableConstants::COL_IDX_K).get_string(pre_key))) { + LOG_WARN("failed to get pre key!",K(ret)); + } else if (OB_FAIL(same_kq_cells.at(same_kq_cells.count() - 1).get_cell(ObHTableConstants::COL_IDX_Q).get_string(pre_qualifier))) { + LOG_WARN("failed to get pre qualifier",K(ret)); + } else { + if (OB_SUCC(ret)) { + if (pre_key != curr_cell_.get_rowkey() || pre_qualifier != curr_cell_.get_qualifier()) { + match_code = ObHTableMatchCode::DONE_REVERSE_SCAN; + } else { + match_code = ObHTableMatchCode::INCLUDE; + } + } + } + } else { + match_code = ObHTableMatchCode::INCLUDE; + } + } else { + int64_t timestamp = 0; + if (OB_FAIL(curr_cell_.get_ob_row()->get_cell(ObHTableConstants::COL_IDX_T).get_int(timestamp))) { + LOG_WARN("failed to get timestamp",K(ret)); + } else { + const_cast(curr_cell_.get_ob_row())->get_cell(ObHTableConstants::COL_IDX_T).set_int(-timestamp); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(out_result->add_row(*(curr_cell_.get_ob_row())))) { + LOG_WARN("failed to add row to result", K(ret)); + } else { + ++cell_count_; + LOG_DEBUG("[yzfdebug] add cell", K_(cell_count), K_(curr_cell), + K_(count_per_row), K_(offset_per_row_per_cf)); + } + } + } + } + if (OB_SUCC(ret)) { + if (ObHTableMatchCode::INCLUDE_AND_SEEK_NEXT_ROW == match_code) { + matcher_->clear_curr_row(); + ret = seek_or_skip_to_next_row(curr_cell_); + } else if (ObHTableMatchCode::INCLUDE_AND_SEEK_NEXT_COL == match_code) { + ret = seek_or_skip_to_next_col(curr_cell_); + } else if (ObHTableMatchCode::DONE_REVERSE_SCAN == match_code) { + ret = add_same_kq_to_res(same_kq_cells, out_result); + same_kq_cells.reset(); + ObNewRow new_row; + if (OB_SUCC(ret) && OB_FAIL(ob_write_row(allocator_, *(curr_cell_.get_ob_row()), new_row))) { + LOG_WARN("failed to copy row", K(ret)); + } else { + if (OB_FAIL(same_kq_cells.push_back(new_row))) { + LOG_DEBUG("[sldebug] get curr_cell", K(*(curr_cell_.get_ob_row())), K_(curr_cell)); + LOG_WARN("put this row failed",K(ret)); + } else if (OB_FAIL(reverse_next_cell(same_kq_cells, out_result))) { + LOG_WARN("get next cell failed in reverse scan",K(ret)); + } + } + } else { + if (ObQueryFlag::Reverse == scan_order_) { + ObNewRow new_row; + if (OB_FAIL(ob_write_row(allocator_, *(curr_cell_.get_ob_row()), new_row))) { + LOG_WARN("failed to copy row", K(ret)); + } else { + if (OB_FAIL(same_kq_cells.push_back(new_row))) { + LOG_WARN("put this row failed",K(ret)); + } else if (OB_FAIL(reverse_next_cell(same_kq_cells, out_result))) { + LOG_WARN("get next cell failed in reverse scan",K(ret)); + } + } + } else { + ret = next_cell(); + } + } + if (OB_SUCC(ret)) { + if (reach_batch_limit() || reach_size_limit()) { + loop = false; + } + } else if (OB_ITER_END == ret) { + loop = false; + } + } + break; + case ObHTableMatchCode::DONE: + // done current row + if (ObQueryFlag::Reverse == scan_order_) { + ret = add_same_kq_to_res(same_kq_cells, out_result); + same_kq_cells.reset(); + } + matcher_->clear_curr_row(); + loop = false; + break; + case ObHTableMatchCode::DONE_SCAN: + has_more_cells_ = false; + loop = false; + break; + case ObHTableMatchCode::SEEK_NEXT_ROW: + if (ObQueryFlag::Reverse == scan_order_) { + ret = reverse_next_cell(same_kq_cells, out_result); + } else { + matcher_->clear_curr_row(); + ret = seek_or_skip_to_next_row(curr_cell_); + } + break; + case ObHTableMatchCode::SEEK_NEXT_COL: + if (ObQueryFlag::Reverse == scan_order_) { + ret = reverse_next_cell(same_kq_cells, out_result); + } else { + ret = seek_or_skip_to_next_col(curr_cell_); + } + break; + case ObHTableMatchCode::SKIP: + if (ObQueryFlag::Reverse == scan_order_) { + ret = reverse_next_cell(same_kq_cells, out_result); + } else { + ret = next_cell(); + } + break; + default: + ret = OB_ERR_UNEXPECTED; + break; + } // end switch + } + if (OB_ITER_END == ret) { + ret = OB_SUCCESS; + } + } // end while + return ret; +} + +/// Seek the scanner at or after the specified KeyValue. +int ObHTableRowIterator::seek(const ObHTableCell &key) +{ + int ret = OB_SUCCESS; + int cmp_ret = 0; + while (OB_SUCC(next_cell())) + { + cmp_ret = ObHTableUtils::compare_cell(curr_cell_, key, scan_order_); + if (cmp_ret >= 0) { + LOG_DEBUG("[yzfdebug] seek to", K(key), K_(curr_cell)); + break; + } + } + return ret; +} + +int ObHTableRowIterator::seek_or_skip_to_next_row(const ObHTableCell &cell) +{ + int ret = OB_SUCCESS; + ObHTableCell* next_cell = NULL; + if (OB_FAIL(ObHTableUtils::create_last_cell_on_row(allocator_, cell, next_cell))) { + LOG_WARN("failed to create last cell", K(ret)); + } else { + ret = seek(*next_cell); + next_cell->~ObHTableCell(); + allocator_.reuse(); + } + return ret; +} + +int ObHTableRowIterator::seek_or_skip_to_next_col(const ObHTableCell &cell) +{ + int ret = OB_SUCCESS; + ObHTableCell* next_cell = NULL; + if (OB_FAIL(matcher_->create_key_for_next_col(allocator_, cell, next_cell))) { + LOG_WARN("failed to create next cell", K(ret)); + } else { + ret = seek(*next_cell); + next_cell->~ObHTableCell(); + allocator_.reuse(); + } + return ret; +} + +bool ObHTableRowIterator::reach_batch_limit() const +{ + // @todo currently not supported + return false; +} + +bool ObHTableRowIterator::reach_size_limit() const +{ + // @todo + return false; +} + +void ObHTableRowIterator::set_hfilter(table::hfilter::Filter *hfilter) +{ + hfilter_ = hfilter; + if (nullptr != matcher_) { + matcher_->set_hfilter(hfilter); + } +} + +void ObHTableRowIterator::set_ttl(int32_t ttl_value) +{ + time_to_live_ = ttl_value; +} + +//////////////////////////////////////////////////////////////// +ObHTableFilterOperator::ObHTableFilterOperator(const ObTableQuery &query, + table::ObTableQueryResult &one_result) + :query_(query), + row_iterator_(query), + one_result_(one_result), + hfilter_(NULL), + batch_size_(query.get_batch()), + max_result_size_(std::min(query.get_max_result_size(), + static_cast(common::OB_MAX_PACKET_BUFFER_LENGTH-1024))), + is_first_result_(true) +{ +} + +// @param one_result for one batch +int ObHTableFilterOperator::get_next_result(ObTableQueryResult *&next_result) +{ + int ret = OB_SUCCESS; + if (is_first_result_) { + is_first_result_ = false; + if (0 != one_result_.get_property_count()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("property should be empty", K(ret)); + } + const ObIArray &select_columns = query_.get_select_columns(); + const int64_t N = select_columns.count(); + for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) + { + if (OB_FAIL(one_result_.add_property_name(select_columns.at(i)))) { + LOG_WARN("failed to copy name", K(ret)); + } + } // end for + } else { + one_result_.reset_except_property(); + } + if (OB_SUCC(ret)) { + bool has_filter_row = (NULL != hfilter_) && (hfilter_->has_filter_row()); + next_result = &one_result_; + ObTableQueryResult *htable_row = nullptr; + // ObNewRow first_entity; + // ObObj first_entity_cells[4]; + // first_entity.cells_ = first_entity_cells; + // first_entity.count_ = 4; + while(OB_SUCCESS == ret + && row_iterator_.has_more_result() + && OB_SUCC(row_iterator_.get_next_result(htable_row))) { + LOG_DEBUG("[yzfdebug] got one row", "cells_count", htable_row->get_row_count()); + bool is_empty_row = (htable_row->get_row_count() == 0); + if (is_empty_row) { + if (nullptr != hfilter_) { + hfilter_->reset(); + } + continue; + } + /* + if (NULL != hfilter_) { + // for RowFilter etc. which filter according to rowkey + if (OB_FAIL(htable_row->get_first_row(first_entity))) { + LOG_WARN("failed to get first cell", K(ret)); + } else { + ObHTableCellEntity first_cell_entity(&first_entity); + if (hfilter_->filter_row_key(first_cell_entity)) { + // filter out the current row and fetch the next row + hfilter_->reset(); + LOG_DEBUG("[yzfdebug] skip the row", K(ret)); + continue; + } + } + } + */ + bool exclude = false; + if (has_filter_row) { + // FIXME @todo allows direct modification of the final list to be submitted + hfilter_->filter_row_cells(*htable_row); + is_empty_row = (htable_row->get_row_count() == 0); + if (!is_empty_row) { + // last chance to drop entire row based on the sequence of filter calls + if (hfilter_->filter_row()) { + LOG_DEBUG("[yzfdebug] filter out the row"); + exclude = true; + } + } + } + if (is_empty_row || exclude) { + if (NULL != hfilter_) { + hfilter_->reset(); + } + // fetch next row + continue; + } + /* @todo check batch limit and size limit */ + // We have got one hbase row, store it to this batch + if (OB_FAIL(one_result_.add_all_row(*htable_row))) { + LOG_WARN("failed to add cells to row", K(ret)); + } + if (NULL != hfilter_) { + hfilter_->reset(); + } + if (OB_SUCC(ret)) { + if (one_result_.reach_batch_size_or_result_size(batch_size_, max_result_size_)) { + break; + } + } + } + if (!row_iterator_.has_more_result()) { + ret = OB_ITER_END; + } + } + if (OB_ITER_END == ret + && one_result_.get_row_count() > 0) { + ret = OB_SUCCESS; + } + LOG_DEBUG("[yzfdebug] get_next_result", K(ret), "row_count", one_result_.get_row_count()); + return ret; +} + +int ObHTableFilterOperator::parse_filter_string(common::ObArenaAllocator* allocator) +{ + int ret = OB_SUCCESS; + const ObString &hfilter_string = query_.get_htable_filter().get_filter(); + if (hfilter_string.empty()) { + hfilter_ = NULL; + } else if (NULL == allocator) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("allocator is nullptr", K(ret)); + } else if (OB_FAIL(filter_parser_.init(allocator))) { + LOG_WARN("failed to init filter_parser", K(ret)); + } else if (OB_FAIL(filter_parser_.parse_filter(hfilter_string, hfilter_))) { + LOG_WARN("failed to parse filter", K(ret), K(hfilter_string)); + } else { + LOG_DEBUG("[yzfdebug] parse filter success", K(hfilter_string), "hfilter", *hfilter_); + row_iterator_.set_hfilter(hfilter_); + } + return ret; +} diff --git a/src/observer/table/ob_htable_filter_operator.h b/src/observer/table/ob_htable_filter_operator.h new file mode 100644 index 0000000000000000000000000000000000000000..dee367aded1ac42b51a284e2164b8d31fa7ae0d6 --- /dev/null +++ b/src/observer/table/ob_htable_filter_operator.h @@ -0,0 +1,253 @@ +/** + * 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. + */ + +#ifndef _OB_HTABLE_FILTER_OPERATOR_H +#define _OB_HTABLE_FILTER_OPERATOR_H 1 +#include "lib/string/ob_string.h" +#include "lib/container/ob_array.h" +#include "share/table/ob_table.h" +#include "share/table/ob_table_rpc_struct.h" +#include "common/row/ob_row_iterator.h" +#include "ob_htable_utils.h" +#include "ob_htable_filter_parser.h" +#include "ob_htable_filters.h" +#include + +namespace oceanbase +{ +namespace table +{ +class ObHColumnDescriptor final +{ +public: + ObHColumnDescriptor() + :time_to_live_(0) + {} + int from_string(const common::ObString &str); + + void set_time_to_live(int32_t v) { time_to_live_ = v; } + int32_t get_time_to_live() const { return time_to_live_; } +private: + int32_t time_to_live_; // Time-to-live of cell contents, in seconds. +}; + +enum class ObHTableMatchCode +{ + INCLUDE = 0, + INCLUDE_AND_SEEK_NEXT_COL = 1, + INCLUDE_AND_SEEK_NEXT_ROW = 2, + SKIP = 3, + SEEK_NEXT_COL = 4, + SEEK_NEXT_ROW = 5, + SEEK_NEXT_USING_HINT = 6, + DONE = 7, + DONE_SCAN = 8, + DONE_REVERSE_SCAN = 9, +}; + +// Interface ObHTableColumnTracker +class ObHTableColumnTracker +{ +public: + // types and constants + typedef std::pair ColumnCount; + class ColumnCountComparator; + class ColumnCountReverseComparator; +public: + ObHTableColumnTracker() + :max_versions_(1), + min_versions_(0), + oldest_stamp_(0) + {} + virtual ~ObHTableColumnTracker() {} + virtual int init(const table::ObHTableFilter &htable_filter, common::ObQueryFlag::ScanOrder &scan_order) = 0; + virtual int check_column(const ObHTableCell &cell, ObHTableMatchCode &match_code) = 0; + virtual int check_versions(const ObHTableCell &cell, ObHTableMatchCode &match_code) = 0; + virtual const ColumnCount *get_curr_column() const = 0; + virtual void reset() = 0; + virtual bool done() const = 0; + virtual int get_next_column_or_row(const ObHTableCell &cell, ObHTableMatchCode &match_code) = 0; + virtual common::ObQueryFlag::ScanOrder get_scan_order() { return tracker_scan_order_; } + virtual void set_scan_order(common::ObQueryFlag::ScanOrder tracker_scan_order) { tracker_scan_order_ = tracker_scan_order; } + // Give the tracker a chance to declare it's done based on only the timestamp. + bool is_done(int64_t timestamp) const; + void set_ttl(int32_t ttl_value); +protected: + int32_t max_versions_; // default: 1 + int32_t min_versions_; // default: 0 + int64_t oldest_stamp_; // default: 0 + common::ObQueryFlag::ScanOrder tracker_scan_order_; +protected: + bool is_expired(int64_t timestamp) const { return (-timestamp) < oldest_stamp_; } +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(ObHTableColumnTracker); +}; + +class ObHTableExplicitColumnTracker: public ObHTableColumnTracker +{ +public: + ObHTableExplicitColumnTracker(); + virtual ~ObHTableExplicitColumnTracker() {} + virtual int init(const table::ObHTableFilter &htable_filter, common::ObQueryFlag::ScanOrder &scan_order) override; + + virtual int check_column(const ObHTableCell &cell, ObHTableMatchCode &match_code) override; + virtual int check_versions(const ObHTableCell &cell, ObHTableMatchCode &match_code) override; + virtual int get_next_column_or_row(const ObHTableCell &cell, ObHTableMatchCode &match_code) override; + virtual const ColumnCount *get_curr_column() const override { return curr_column_; } + virtual void reset() override; + virtual bool done() const override; +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(ObHTableExplicitColumnTracker); + // function members + + void done_with_column(const ObHTableCell &cell); + ObHTableMatchCode check_version(int64_t timestamp); +private: + common::ObSEArray columns_; + int64_t curr_column_idx_; + ColumnCount *curr_column_; + int32_t current_count_; +}; + +class ObHTableWildcardColumnTracker: public ObHTableColumnTracker +{ +public: + ObHTableWildcardColumnTracker(); + virtual ~ObHTableWildcardColumnTracker() {} + virtual int init(const table::ObHTableFilter &htable_filter, common::ObQueryFlag::ScanOrder &scan_order) override; + virtual int check_column(const ObHTableCell &cell, ObHTableMatchCode &match_code) override; + virtual int check_versions(const ObHTableCell &cell, ObHTableMatchCode &match_code) override; + virtual int get_next_column_or_row(const ObHTableCell &cell, ObHTableMatchCode &match_code) override; + virtual const ColumnCount *get_curr_column() const override { return NULL; } + virtual void reset() override; + virtual bool done() const override { return false; } +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(ObHTableWildcardColumnTracker); + // function members + int reset_cell(const ObHTableCell &cell); + ObHTableMatchCode check_version(int64_t timestamp); +private: + // states + common::ObArenaAllocator allocator_; + ObString current_qualifier_; + int32_t current_count_; +}; + +class ObHTableScanMatcher +{ +public: + explicit ObHTableScanMatcher(const table::ObHTableFilter &htable_filter, ObHTableColumnTracker *column_tracker = nullptr); + virtual ~ObHTableScanMatcher() {} + void init(ObHTableColumnTracker *tracker, table::hfilter::Filter *hfilter) { column_tracker_ = tracker; hfilter_ = hfilter; } + void set_hfilter(table::hfilter::Filter *hfilter) { hfilter_ = hfilter; } + + int match(const ObHTableCell &cell, ObHTableMatchCode &match_code); + int create_key_for_next_col(common::ObArenaAllocator &allocator, const ObHTableCell &cell, ObHTableCell *&next_cell); + + const ObHTableCell* get_curr_row() const; + void clear_curr_row() { curr_row_.set_ob_row(NULL); } + int set_to_new_row(const ObHTableCell &curr_row); + bool is_curr_row_empty() const { return NULL == curr_row_.get_ob_row(); } + ObHTableMatchCode merge_filter_return_code(const ObHTableCell &cell, + const ObHTableMatchCode match_code, + hfilter::Filter::ReturnCode filter_rc); +private: + DISALLOW_COPY_AND_ASSIGN(ObHTableScanMatcher); + int pre_check(const ObHTableCell &cell, ObHTableMatchCode &match_code, bool &need_match_column); + int match_column(const ObHTableCell &cell, ObHTableMatchCode &match_code); +private: + ObNegativeTimeRange time_range_; + ObHTableColumnTracker *column_tracker_; + table::hfilter::Filter *hfilter_; + common::ObArenaAllocator allocator_; + ObHTableCellEntity curr_row_; // the first cell of current row + common::ObNewRow curr_ob_row_; +}; + +class ObHTableRowIterator: public ObTableQueryResultIterator +{ +public: + ObHTableRowIterator(const ObTableQuery &query); + virtual ~ObHTableRowIterator(); + /// Fetch next row + virtual int get_next_result(ObTableQueryResult *&one_row) override; + + int seek(const ObHTableCell &key); + void set_scan_result(common::ObNewRowIterator *scan_result) { child_op_ = scan_result; } + bool has_more_result() const { return has_more_cells_; } + void set_hfilter(table::hfilter::Filter *hfilter); + void set_ttl(int32_t ttl_value); + int add_same_kq_to_res(ObIArray &same_kq_cells, ObTableQueryResult *&out_result); + ObIArray &get_same_kq_cells() { return same_kq_cells_; } +private: + int next_cell(); + int reverse_next_cell(ObIArray &same_kq_cells, ObTableQueryResult *&out_result); + int seek_or_skip_to_next_row(const ObHTableCell &cell); + int seek_or_skip_to_next_col(const ObHTableCell &cell); + bool reach_batch_limit() const; + bool reach_size_limit() const; +private: + common::ObNewRowIterator *child_op_; + const table::ObHTableFilter &htable_filter_; + table::hfilter::Filter *hfilter_; + int32_t limit_per_row_per_cf_; + int32_t offset_per_row_per_cf_; + int64_t max_result_size_; + int32_t batch_size_; + int32_t time_to_live_; // Time-to-live of cell contents, in seconds. + + table::ObTableQueryResult one_hbase_row_; + ObHTableCellEntity curr_cell_; + common::ObArenaAllocator allocator_; // used for deep copy of curr_cell_ + ObHTableColumnTracker *column_tracker_; + ObHTableScanMatcher *matcher_; + ObHTableWildcardColumnTracker column_tracker_wildcard_; + ObHTableExplicitColumnTracker column_tracker_explicit_; + ObHTableScanMatcher matcher_impl_; + common::ObQueryFlag::ScanOrder scan_order_; + ObSEArray same_kq_cells_; + int32_t cell_count_; + int32_t count_per_row_; + bool has_more_cells_; +}; + +// entry class +class ObHTableFilterOperator: public ObTableQueryResultIterator +{ +public: + ObHTableFilterOperator(const ObTableQuery &query, table::ObTableQueryResult &one_result); + virtual ~ObHTableFilterOperator() {} + /// Fetch next batch result + virtual int get_next_result(ObTableQueryResult *&one_result) override; + virtual bool has_more_result() const override { return row_iterator_.has_more_result(); } + void set_scan_result(common::ObNewRowIterator *scan_result) { row_iterator_.set_scan_result(scan_result); } + void set_ttl(int32_t ttl_value) { row_iterator_.set_ttl(ttl_value); } + // parse the filter string + int parse_filter_string(common::ObArenaAllocator* allocator); +private: + const ObTableQuery &query_; + ObHTableRowIterator row_iterator_; + table::ObTableQueryResult &one_result_; + table::ObHTableFilterParser filter_parser_; + table::hfilter::Filter *hfilter_; + int32_t batch_size_; + int64_t max_result_size_; + bool is_first_result_; +}; + +} // end namespace table +} // end namespace oceanbase + +#endif /* _OB_HTABLE_FILTER_OPERATOR_H */ diff --git a/src/observer/table/ob_htable_filter_parser.cpp b/src/observer/table/ob_htable_filter_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b178b6dd412eb4f8665dbbf1c53bb7235e487442 --- /dev/null +++ b/src/observer/table/ob_htable_filter_parser.cpp @@ -0,0 +1,229 @@ +/** + * 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. + */ + +#define USING_LOG_PREFIX SERVER +#include "ob_htable_filter_parser.h" +#include "htable_filter_lex.hxx" +using namespace oceanbase::table; +using namespace oceanbase::common; + +ObHTableFilterParser::ObHTableFilterParser() + :scanner_(nullptr), + error_code_(OB_SUCCESS), + first_column_(0), + last_column_(0), + first_line_(0), + last_line_(0), + allocator_(nullptr), + filter_string_(nullptr), + result_filter_(nullptr) +{ + error_msg_[0] = '\0'; +} + +ObHTableFilterParser::~ObHTableFilterParser() +{ + destroy(); +} + +int ObHTableFilterParser::init(common::ObArenaAllocator* allocator) +{ + int ret = OB_SUCCESS; + if (nullptr != scanner_ || nullptr != allocator_) { + ret = OB_INIT_TWICE; + LOG_WARN("scanner already inited", K(ret)); + } else { + allocator_ = allocator; + if (OB_FAIL(ob_hfilter_lex_init_extra(this, &scanner_))) { + LOG_WARN("failed to init lex", K(ret)); + } + } + return ret; +} +using hfilter::Comparable; +using hfilter::Filter; + +void ObHTableFilterParser::destroy() +{ + if (nullptr != scanner_) { + ob_hfilter_lex_destroy(scanner_); + scanner_ = nullptr; + } + int64_t N = comparators_.count(); + for (int64_t i = 0; i < N; ++i) { + comparators_.at(i)->~Comparable(); + } + comparators_.reset(); + N = filters_.count(); + for (int64_t i = 0; i < N; ++i) { + filters_.at(i)->~Filter(); + } + filters_.reset(); +} + +// @see htable_filter_tab.cxx +extern int ob_hfilter_parse(oceanbase::table::ObHTableFilterParser *parse_ctx); + +int ObHTableFilterParser::parse_filter(const ObString &filter_string, hfilter::Filter *&filter) +{ + int ret = OB_SUCCESS; + filter = NULL; + filter_string_ = &filter_string; + const char * buf = filter_string.ptr(); + int32_t len = filter_string.length(); + YY_BUFFER_STATE bp = ob_hfilter__scan_bytes(buf, len, scanner_); + ob_hfilter__switch_to_buffer(bp, scanner_); + ret = ob_hfilter_parse(this); // the bison parser + LOG_DEBUG("parse filter", K(ret), K(filter_string)); + if (OB_SUCC(ret)) { + filter = result_filter_; + } else { + if (1 == ret) { // syntax error + if (OB_SUCCESS != error_code_) { + ret = error_code_; + } else { + ret = OB_ERR_PARSER_SYNTAX; + } + } + LOG_WARN("failed to parse filter", K(ret), K_(error_msg), K(filter_string)); + } + ob_hfilter__delete_buffer(bp, scanner_); + return ret; +} + +const ObString ObHTableFilterParser::BINARY_TYPE = ObString::make_string("binary"); +const ObString ObHTableFilterParser::BINARY_PREFIX_TYPE = ObString::make_string("binaryprefix"); +const ObString ObHTableFilterParser::REGEX_STRING_TYPE = ObString::make_string("regexstring"); +const ObString ObHTableFilterParser::SUB_STRING_TYPE = ObString::make_string("substring"); +int ObHTableFilterParser::create_comparator(const SimpleString &bytes, hfilter::Comparable *&comparator) +{ + int ret = OB_SUCCESS; + char *p = static_cast(memchr(bytes.str_, ':', bytes.len_)); + if (NULL == p) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("no : found in the comprator", K(ret)); + } else { + comparator = NULL; + int64_t len1 = p-bytes.str_; + ObString comparator_type(len1, bytes.str_); + ObString comparator_value(bytes.len_-len1-1, p+1); + if (comparator_type == BINARY_TYPE) { + comparator = OB_NEWx(hfilter::BinaryComparator, allocator_, comparator_value); + } else if (comparator_type == BINARY_PREFIX_TYPE) { + comparator = OB_NEWx(hfilter::BinaryPrefixComparator, allocator_, comparator_value); + } else if (comparator_type == REGEX_STRING_TYPE) { + //comparator = OB_NEWx(hfilter::RegexStringComparator, allocator_, comparator_value); + LOG_WARN("regexstring comparator not supported yet", K(ret)); + ret = OB_NOT_SUPPORTED; + } else if (comparator_type == SUB_STRING_TYPE) { + comparator = OB_NEWx(hfilter::SubStringComparator, allocator_, comparator_value); + } else { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid comprator type", K(ret), K(comparator_type)); + } + if (OB_SUCC(ret) && NULL == comparator) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } + if (NULL != comparator) { + if (OB_FAIL(comparators_.push_back(comparator))) { + LOG_WARN("failed to add comparator", K(ret)); + comparator->~Comparable(); + comparator = NULL; + } + } + } + return ret; +} + +int ObHTableFilterParser::create_prefix_comparator(const SimpleString &bytes, hfilter::Comparable *&comparator) +{ + int ret = OB_SUCCESS; + ObString comparator_value(bytes.len_, bytes.str_); + comparator = OB_NEWx(hfilter::BinaryPrefixComparator, allocator_, comparator_value); + if (NULL == comparator) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } + if (NULL != comparator) { + if (OB_FAIL(comparators_.push_back(comparator))) { + LOG_WARN("failed to add comparator", K(ret)); + comparator->~Comparable(); + comparator = NULL; + } + } + return ret; +} + +int ObHTableFilterParser::store_filter(hfilter::Filter *&filter) +{ + int ret = OB_SUCCESS; + if (NULL != filter) { + if (OB_FAIL(filters_.push_back(filter))) { + LOG_WARN("failed to add filter", K(ret)); + filter->~Filter(); + filter = NULL; + } + } + return ret; +} + +#include "sql/parser/parse_malloc.h" +void *ObHTableFilterParser::alloc(int64_t size) +{ + return parse_malloc(size, allocator_); +} + +void *ObHTableFilterParser::realloc(void *ptr, int64_t size) +{ + return parse_realloc(ptr, size, allocator_); +} + +void ObHTableFilterParser::free(void *ptr) +{ + // we don't need to free the memory from arena allocator + UNUSED(ptr); +} + +void ob_hfilter_error(YYLTYPE *loc, oceanbase::table::ObHTableFilterParser *p, const char *format_msg, ...) +{ + if (OB_LIKELY(NULL != p)) { + va_list ap; + va_start(ap, format_msg); + vsnprintf(p->error_msg_, p->PARSER_ERROR_MSG_SIZE, format_msg, ap); + if (OB_LIKELY(NULL != loc)) { + p->first_column_ = loc->first_column; + p->last_column_ = loc->last_column; + p->first_line_ = loc->first_line; + p->last_line_ = loc->last_line; + } + va_end(ap); + } +} + +void *ob_hfilter_alloc(size_t bytes, void* yyscanner) +{ + ObHTableFilterParser *p = ob_hfilter_get_extra(yyscanner); + return p->alloc(bytes); +} + +void *ob_hfilter_realloc(void *ptr, size_t bytes, void* yyscanner) +{ + ObHTableFilterParser *p = ob_hfilter_get_extra(yyscanner); + return p->realloc(ptr, bytes); +} + +void ob_hfilter_free(void *ptr, void* yyscanner) +{ + ObHTableFilterParser *p = ob_hfilter_get_extra(yyscanner); + p->free(ptr); +} diff --git a/src/observer/table/ob_htable_filter_parser.h b/src/observer/table/ob_htable_filter_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..2713cb69a72d1ec08ffff49313107d9f052c0344 --- /dev/null +++ b/src/observer/table/ob_htable_filter_parser.h @@ -0,0 +1,95 @@ +/** + * 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. + */ + +#ifndef _OB_HTABLE_FILTER_PARSER_H +#define _OB_HTABLE_FILTER_PARSER_H 1 +#include "lib/ob_define.h" +#include "lib/string/ob_string.h" +#include "lib/container/ob_se_array.h" +namespace oceanbase +{ +namespace common +{ +class ObArenaAllocator; +} // end namespace common +namespace table +{ +namespace hfilter +{ +class Filter; +class Comparable; +} +class ObHTableFilterParser +{ +public: + struct SimpleString + { + char *str_; + int64_t len_; + }; +public: + static const int64_t PARSER_ERROR_MSG_SIZE = 512; + void *scanner_; // the reentrant lex scanner + int error_code_; + // for yyerror() + int first_column_; + int last_column_; + int first_line_; + int last_line_; + char error_msg_[PARSER_ERROR_MSG_SIZE]; +public: + ObHTableFilterParser(); + virtual ~ObHTableFilterParser(); + int init(common::ObArenaAllocator* allocator); + void destroy(); + // parse the filter string + int parse_filter(const common::ObString &filter_string, hfilter::Filter *&filter); + + int64_t get_input_len() const { return filter_string_->length(); } + const char *get_input_str() const { return filter_string_->ptr(); } + void set_result_filter(hfilter::Filter *filter) { result_filter_ = filter; } + + void *alloc(int64_t size); + void *realloc(void *ptr, int64_t size); + void free(void *ptr); + common::ObArenaAllocator *allocator() { return allocator_; } + int create_comparator(const SimpleString &bytes, hfilter::Comparable *&comparator); + int create_prefix_comparator(const SimpleString &bytes, hfilter::Comparable *&comparator); + int store_filter(hfilter::Filter *&filter); +private: + static const common::ObString BINARY_TYPE; + static const common::ObString BINARY_PREFIX_TYPE; + static const common::ObString REGEX_STRING_TYPE; + static const common::ObString SUB_STRING_TYPE; +private: + common::ObArenaAllocator* allocator_; + common::ObSEArray comparators_; + common::ObSEArray filters_; + // the input filter string + const common::ObString *filter_string_; + // parse result + hfilter::Filter *result_filter_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(ObHTableFilterParser); +}; + +} // end namespace table +} // end namespace oceanbase + +// for yacc/lex error report +class YYLTYPE; +extern void ob_hfilter_error(YYLTYPE *loc, oceanbase::table::ObHTableFilterParser *p, const char *s, ...); +// for flex memory management +extern void *ob_hfilter_alloc(size_t bytes, void* yyscanner); +extern void *ob_hfilter_realloc(void *ptr, size_t bytes, void* yyscanner); +extern void ob_hfilter_free(void *ptr, void* yyscanner); +#endif /* _OB_HTABLE_FILTER_PARSER_H */ diff --git a/src/observer/table/ob_htable_filters.cpp b/src/observer/table/ob_htable_filters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..855a020b08d0da468e401963b8a1e4171a6805b3 --- /dev/null +++ b/src/observer/table/ob_htable_filters.cpp @@ -0,0 +1,913 @@ +/** + * 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. + */ + +#define USING_LOG_PREFIX SERVER +#include "ob_htable_filters.h" +using namespace oceanbase::common; +using namespace oceanbase::table; +using namespace oceanbase::table::hfilter; +Filter::Filter() + :is_reversed_(false) +{ +} + +Filter::~Filter() +{} + +FilterBase::~FilterBase() {} +//////////////////////////////////////////////////////////////// +CompareFilter::~CompareFilter() +{} + +const char* FilterBase::compare_operator_to_string(CompareOperator cmp_op) +{ + const char* op_str = "UNKNOWN"; + switch (cmp_op) { + case CompareOperator::EQUAL: + op_str = "EQUAL"; + break; + case CompareOperator::GREATER: + op_str = "GREATER"; + break; + case CompareOperator::GREATER_OR_EQUAL: + op_str = "GREATER_OR_EQUAL"; + break; + case CompareOperator::LESS: + op_str = "LESS"; + break; + case CompareOperator::LESS_OR_EQUAL: + op_str = "LESS_OR_EQUAL"; + break; + case CompareOperator::NO_OP: + op_str = "NO_OP"; + break; + case CompareOperator::NOT_EQUAL: + op_str = "NOT_EQUAL"; + break; + default: + break; + } + return op_str; +} + +int CompareFilter::check_arguments() const +{ + int ret = OB_SUCCESS; + if (NULL != dynamic_cast(comparator_) + || NULL != dynamic_cast(comparator_)) { + if (CompareOperator::EQUAL != cmp_op_ + && CompareOperator::NOT_EQUAL != cmp_op_) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("regexstring comparator and substring comparator can only be used with EQUAL or NOT_EQUAL", K(ret)); + } + } + return ret; +} + + +// return true indicates it will be filtered +bool CompareFilter::compare(CompareOperator op, int cmp_ret) +{ + bool bret = true; + switch (op) { + case CompareOperator::EQUAL: + bret = (0 != cmp_ret); + break; + case CompareOperator::GREATER: + bret = (cmp_ret >= 0); + break; + case CompareOperator::GREATER_OR_EQUAL: + bret = (cmp_ret > 0); + break; + case CompareOperator::LESS: + bret = (cmp_ret <= 0); + break; + case CompareOperator::LESS_OR_EQUAL: + bret = (cmp_ret < 0); + break; + case CompareOperator::NOT_EQUAL: + bret = (cmp_ret == 0); + break; + default: + break; + } + return bret; +} + +bool CompareFilter::compare_row(CompareOperator op, Comparable &comparator, const ObHTableCell &cell) +{ + bool bret = false; + if (CompareOperator::NO_OP == op) { + bret = true; + } else { + int cmp_ret = comparator.compare_to(cell.get_rowkey()); + bret = compare(op, cmp_ret); + } + return bret; +} + +bool CompareFilter::compare_qualifier(CompareOperator op, Comparable &comparator, const ObHTableCell &cell) +{ + bool bret = false; + if (CompareOperator::NO_OP == op) { + bret = true; + } else { + int cmp_ret = comparator.compare_to(cell.get_qualifier()); + bret = compare(op, cmp_ret); + } + return bret; +} + +bool CompareFilter::compare_value(CompareOperator op, Comparable &comparator, const ObHTableCell &cell) +{ + bool bret = false; + if (CompareOperator::NO_OP == op) { + bret = true; + } else { + int cmp_ret = comparator.compare_to(cell.get_value()); + bret = compare(op, cmp_ret); + } + return bret; +} + +//////////////////////////////////////////////////////////////// +int BinaryComparator::compare_to(const ObString &b) +{ + return comparator_value_.compare(b); +} + +int BinaryPrefixComparator::compare_to(const ObString &b) +{ + int cmp_ret = 0; + if (b.length() <= comparator_value_.length()) { + cmp_ret = comparator_value_.compare(b); + } else { + ObString b_prefix(comparator_value_.length(), b.ptr()); + cmp_ret = comparator_value_.compare(b_prefix); + } + return cmp_ret; +} + +int RegexStringComparator::compare_to(const ObString &b) +{ + // @todo + UNUSED(b); + LOG_WARN("regexstring comparator not supported yet"); + return 0; +} + +// If value_ is substring of b, return 0; otherwise return 1 +int SubStringComparator::compare_to(const ObString &b) +{ + int cmp_ret = 0; + char *a_dup = strndupa(comparator_value_.ptr(), comparator_value_.length()); + char *b_dup = strndupa(b.ptr(), b.length()); + if (NULL == a_dup || NULL == b_dup) { + LOG_WARN("failed to dup string"); + } else { + char* p = strcasestr(b_dup, a_dup); + cmp_ret = (NULL == p) ? 1: 0; + } + return cmp_ret; +} + +//////////////////////////////////////////////////////////////// +RowFilter::~RowFilter() +{} + +void RowFilter::reset() +{ + filter_out_row_ = false; +} + +bool RowFilter::filter_row_key(const ObHTableCell &first_row_cell) +{ + filter_out_row_ = compare_row(cmp_op_, *comparator_, first_row_cell); + return filter_out_row_; +} + +int RowFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) +{ + int ret = OB_SUCCESS; + UNUSED(cell); + ret_code = (filter_out_row_)?(ReturnCode::NEXT_ROW):(ReturnCode::INCLUDE); + return ret; +} + +bool RowFilter::filter_row() +{ + return filter_out_row_; +} + +//////////////////////////////////////////////////////////////// +QualifierFilter::~QualifierFilter() +{} + +int QualifierFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) +{ + int ret = OB_SUCCESS; + ret_code = ReturnCode::INCLUDE; + const ObString qualifier = cell.get_qualifier(); + if (qualifier.length() > 0) { + if (compare_qualifier(cmp_op_, *comparator_, cell)) { + ret_code = ReturnCode::SKIP; + } + } + return ret; +} + +//////////////////////////////////////////////////////////////// +ValueFilter::~ValueFilter() {} +int ValueFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) +{ + int ret = OB_SUCCESS; + ret_code = ReturnCode::INCLUDE; + if (compare_value(cmp_op_, *comparator_, cell)) { + ret_code = ReturnCode::SKIP; + } + return ret; +} + +//////////////////////////////////////////////////////////////// +FilterListBase::~FilterListBase() +{} + +int FilterListBase::add_filter(Filter *filter) +{ + int ret = OB_SUCCESS; + if (NULL == filter) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("filter is nullptr", K(ret)); + } else if (OB_FAIL(filters_.push_back(filter))) { + LOG_WARN("failed to push back", K(ret)); + } + return ret; +} + +const char* FilterListBase::operator_to_string(Operator op) +{ + const char* op_str = "UNKNOWN"; + switch(op) { + case Operator::MUST_PASS_ALL: + op_str = "AND"; + break; + case Operator::MUST_PASS_ONE: + op_str = "OR"; + break; + default: + break; + } + return op_str; +} + +void FilterListBase::reset() +{ + const int64_t N = filters_.count(); + for (int64_t i = 0; i < N; ++i) + { + filters_.at(i)->reset(); + } // end for +} +//////////////////////////////////////////////////////////////// +FilterListAND::~FilterListAND() +{} + +// Maximal Step Rule +Filter::ReturnCode FilterListAND::merge_return_code(ReturnCode rc, ReturnCode local_rc) +{ + ReturnCode ret_code = local_rc; + if (rc == ReturnCode::SEEK_NEXT_USING_HINT) { + ret_code = ReturnCode::SEEK_NEXT_USING_HINT; + } else { + switch (local_rc) { + case ReturnCode::SEEK_NEXT_USING_HINT: + ret_code = ReturnCode::SEEK_NEXT_USING_HINT; + break; + case ReturnCode::INCLUDE: + ret_code = rc; + break; + case ReturnCode::INCLUDE_AND_NEXT_COL: + if (rc == ReturnCode::INCLUDE + || rc == ReturnCode::INCLUDE_AND_NEXT_COL) { + ret_code = ReturnCode::INCLUDE_AND_NEXT_COL; + } else if (rc == ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW) { + ret_code = ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW; + } else if (rc == ReturnCode::SKIP + || rc == ReturnCode::NEXT_COL) { + ret_code = ReturnCode::NEXT_COL; + } else if (rc == ReturnCode::NEXT_ROW) { + ret_code = ReturnCode::NEXT_ROW; + } + break; + case ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW: + if (rc == ReturnCode::INCLUDE + || rc == ReturnCode::INCLUDE_AND_NEXT_COL + || rc == ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW) { + ret_code = ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW; + } else if (rc == ReturnCode::SKIP + || rc == ReturnCode::NEXT_COL + || rc == ReturnCode::NEXT_ROW) { + ret_code = ReturnCode::NEXT_ROW; + } + break; + case ReturnCode::SKIP: + if (rc == ReturnCode::INCLUDE + || rc == ReturnCode::SKIP) { + ret_code = ReturnCode::SKIP; + } else if (rc == ReturnCode::INCLUDE_AND_NEXT_COL + || rc == ReturnCode::NEXT_COL) { + ret_code = ReturnCode::NEXT_COL; + } else if (rc == ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW + || rc == ReturnCode::NEXT_ROW) { + ret_code = ReturnCode::NEXT_ROW; + } + break; + case ReturnCode::NEXT_COL: + if (rc == ReturnCode::INCLUDE + || rc == ReturnCode::INCLUDE_AND_NEXT_COL + || rc == ReturnCode::SKIP + || rc == ReturnCode::NEXT_COL) { + ret_code = ReturnCode::NEXT_COL; + } else if (rc == ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW + || rc == ReturnCode::NEXT_ROW) { + ret_code = ReturnCode::NEXT_ROW; + } + break; + case ReturnCode::NEXT_ROW: + ret_code = ReturnCode::NEXT_ROW; + break; + default: + break; + } // end switch + } + return ret_code; +} + +int FilterListAND::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) +{ + int ret = OB_SUCCESS; + if (filters_.empty()) { + ret_code = ReturnCode::INCLUDE; + } else { + ret_code = ReturnCode::INCLUDE; + seek_hint_filters_.reset(); + const int64_t N = filters_.count(); + for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) + { + Filter *filter = filters_.at(i); + if (filter->filter_all_remaining()) { + ret_code = ReturnCode::NEXT_ROW; + break; + } else { + ReturnCode local_rc; + if (OB_FAIL(filter->filter_cell(cell, local_rc))) { + LOG_WARN("failed to filter cell", K(ret)); + } else { + ret_code = merge_return_code(ret_code, local_rc); + LOG_DEBUG("[yzfdebug] AND filter cell", K(i), K(local_rc), K(ret_code)); + if (local_rc == ReturnCode::SEEK_NEXT_USING_HINT) { + if (OB_FAIL(seek_hint_filters_.push_back(filter))) { + LOG_WARN("failed to push back", K(ret)); + } + } + } + } + } // end for + if (!seek_hint_filters_.empty()) { + ret_code = ReturnCode::SEEK_NEXT_USING_HINT; + } + } + return ret; +} + +void FilterListAND::reset() +{ + FilterListBase::reset(); + seek_hint_filters_.reset(); +} + +bool FilterListAND::filter_all_remaining() +{ + bool bret = false; + if (filters_.empty()) { + bret = FilterListBase::filter_all_remaining(); + } else { + const int64_t N = filters_.count(); + for (int64_t i = 0; i < N; ++i) + { + if (filters_.at(i)->filter_all_remaining()) { + bret = true; + break; + } + } // end for + } + return bret; +} + +bool FilterListAND::filter_row_key(const ObHTableCell &first_row_cell) +{ + bool bret = false; + if (filters_.empty()) { + bret = FilterListBase::filter_row_key(first_row_cell); + } else { + const int64_t N = filters_.count(); + for (int64_t i = 0; i < N; ++i) + { + Filter *filter = filters_.at(i); + if (filter->filter_all_remaining() || filter->filter_row_key(first_row_cell)) { + bret = true; + // can not break here + } + } // end for + } + return bret; +} + +bool FilterListAND::filter_row() +{ + bool bret = false; + if (filters_.empty()) { + bret = FilterListBase::filter_row(); + } else { + const int64_t N = filters_.count(); + for (int64_t i = 0; i < N; ++i) + { + Filter *filter = filters_.at(i); + if (filter->filter_row()) { + bret = true; + break; + } + } // end for + } + return bret; +} +//////////////////////////////////////////////////////////////// +FilterListOR::~FilterListOR() +{} + +void FilterListOR::reset() +{ + FilterListBase::reset(); +} + +bool FilterListOR::filter_all_remaining() +{ + bool bret = true; + if (filters_.empty()) { + bret = FilterListBase::filter_all_remaining(); + } else { + const int64_t N = filters_.count(); + for (int64_t i = 0; i < N; ++i) + { + if (!filters_.at(i)->filter_all_remaining()) { + bret = false; + break; + } + } // end for + } + return bret; +} + +bool FilterListOR::filter_row_key(const ObHTableCell &first_row_cell) +{ + bool bret = true; + if (filters_.empty()) { + bret = FilterListBase::filter_row_key(first_row_cell); + } else { + const int64_t N = filters_.count(); + for (int64_t i = 0; i < N; ++i) + { + Filter *filter = filters_.at(i); + if (!filter->filter_all_remaining() && !filter->filter_row_key(first_row_cell)) { + bret = false; + // can not break here + } + } // end for + } + return bret; +} + +// Minimal Step Rule +Filter::ReturnCode FilterListOR::merge_return_code(ReturnCode rc, ReturnCode local_rc) +{ + ReturnCode ret_code = local_rc; + switch (local_rc) { + case ReturnCode::INCLUDE: + ret_code = ReturnCode::INCLUDE; + break; + case ReturnCode::INCLUDE_AND_NEXT_COL: + if (ReturnCode::INCLUDE == rc + || ReturnCode::SKIP == rc + || ReturnCode::SEEK_NEXT_USING_HINT == rc) { + ret_code = ReturnCode::INCLUDE; + } else if (ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW == rc + || ReturnCode::INCLUDE_AND_NEXT_COL == rc + || ReturnCode::NEXT_COL == rc + || ReturnCode::NEXT_ROW == rc) { + ret_code = ReturnCode::INCLUDE_AND_NEXT_COL; + } + break; + case ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW: + if (ReturnCode::INCLUDE == rc + || ReturnCode::SKIP == rc + || ReturnCode::SEEK_NEXT_USING_HINT == rc) { + ret_code = ReturnCode::INCLUDE; + } else if (ReturnCode::INCLUDE_AND_NEXT_COL == rc + || ReturnCode::NEXT_COL == rc) { + ret_code = ReturnCode::INCLUDE_AND_NEXT_COL; + } else if (ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW == rc + || ReturnCode::NEXT_ROW == rc) { + ret_code = ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW; + } + break; + case ReturnCode::SKIP: + if (ReturnCode::INCLUDE == rc + || ReturnCode::INCLUDE_AND_NEXT_COL == rc + || ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW == rc) { + ret_code = ReturnCode::INCLUDE; + } else { + ret_code = ReturnCode::SKIP; + } + break; + case ReturnCode::NEXT_COL: + { + switch (rc) { + case ReturnCode::INCLUDE: + ret_code = ReturnCode::INCLUDE; + break; + case ReturnCode::NEXT_COL: + case ReturnCode::NEXT_ROW: + ret_code = ReturnCode::NEXT_COL; + break; + case ReturnCode::INCLUDE_AND_NEXT_COL: + case ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW: + ret_code = ReturnCode::INCLUDE_AND_NEXT_COL; + break; + case ReturnCode::SKIP: + case ReturnCode::SEEK_NEXT_USING_HINT: + ret_code = ReturnCode::SKIP; + break; + default: + LOG_ERROR("BUG"); + break; + } + } + break; + case ReturnCode::NEXT_ROW: + { + switch (rc) { + case ReturnCode::INCLUDE: + ret_code = ReturnCode::INCLUDE; + break; + case ReturnCode::NEXT_COL: + ret_code = ReturnCode::NEXT_COL; + break; + case ReturnCode::NEXT_ROW: + ret_code = ReturnCode::NEXT_ROW; + break; + case ReturnCode::INCLUDE_AND_NEXT_COL: + ret_code = ReturnCode::INCLUDE_AND_NEXT_COL; + break; + case ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW: + ret_code = ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW; + break; + case ReturnCode::SKIP: + case ReturnCode::SEEK_NEXT_USING_HINT: + ret_code = ReturnCode::SKIP; + break; + default: + LOG_ERROR("BUG"); + break; + } + } + break; + case ReturnCode::SEEK_NEXT_USING_HINT: + { + switch (rc) { + case ReturnCode::INCLUDE: + case ReturnCode::INCLUDE_AND_NEXT_COL: + case ReturnCode::INCLUDE_AND_SEEK_NEXT_ROW: + ret_code = ReturnCode::INCLUDE; + break; + case ReturnCode::SKIP: + case ReturnCode::NEXT_COL: + case ReturnCode::NEXT_ROW: + ret_code = ReturnCode::SKIP; + break; + case ReturnCode::SEEK_NEXT_USING_HINT: + ret_code = ReturnCode::SEEK_NEXT_USING_HINT; + break; + default: + LOG_ERROR("BUG", K(rc)); + break; + } + } + break; + default: + LOG_ERROR("BUG", K(local_rc)); + break; + } // end switch + return ret_code; +} + +int FilterListOR::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) +{ + int ret = OB_SUCCESS; + if (filters_.empty()) { + ret_code = ReturnCode::INCLUDE; + } else { + bool every_filter_return_hint = true; + ret_code = ReturnCode::SKIP; // Each sub-filter in filter list got true for filterAllRemaining(). + const int64_t N = filters_.count(); + for (int64_t i = 0; i < N; ++i) + { + Filter *filter = filters_.at(i); + if (filter->filter_all_remaining()) { + continue; + } else { + ReturnCode local_rc; + if (OB_FAIL(filter->filter_cell(cell, local_rc))) { + LOG_WARN("failed to filter cell", K(ret)); + } else { + if (ReturnCode::SEEK_NEXT_USING_HINT != local_rc) { + every_filter_return_hint = false; + } + ret_code = merge_return_code(ret_code, local_rc); + LOG_DEBUG("[yzfdebug] OR filter cell", K(i), K(local_rc), K(ret_code)); + } + } + } // end for + if (every_filter_return_hint) { + ret_code = ReturnCode::SEEK_NEXT_USING_HINT; + } + } + return ret; +} + +bool FilterListOR::filter_row() +{ + bool bret = true; + if (filters_.empty()) { + bret = FilterListBase::filter_row(); + } else { + const int64_t N = filters_.count(); + for (int64_t i = 0; i < N; ++i) + { + Filter *filter = filters_.at(i); + if (!filter->filter_row()) { + bret = false; + break; + } + } // end for + } + return bret; +} +//////////////////////////////////////////////////////////////// +SkipFilter::~SkipFilter() {} +void SkipFilter::reset() +{ + if (NULL != filter_) { + filter_->reset(); + } + filter_row_ = false; +} + +bool SkipFilter::filter_row_key(const ObHTableCell &first_row_cell) +{ + UNUSED(first_row_cell); + return false; +} + +// A wrapper filter that filters an entire row if any of the Cell checks do not pass. +int SkipFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(filter_->filter_cell(cell, ret_code))) { + } else { + filter_row_ = filter_row_ || (ReturnCode::INCLUDE != ret_code); + } + return ret; +} + +bool SkipFilter::filter_row() +{ + return filter_row_; +} + +int SkipFilter::transform_cell(const ObHTableCell &cell, const ObHTableCell *&new_cell) +{ + return filter_->transform_cell(cell, new_cell); +} +//////////////////////////////////////////////////////////////// +WhileMatchFilter::~WhileMatchFilter() {} + +void WhileMatchFilter::reset() +{ + if (NULL != filter_) { + filter_->reset(); + } +} + +bool WhileMatchFilter::filter_all_remaining() +{ + return filter_all_remaining_ || filter_->filter_all_remaining(); +} + +bool WhileMatchFilter::filter_row_key(const ObHTableCell &first_row_cell) +{ + bool bret = true; + if (filter_all_remaining()) { + bret = true; + } else { + bret = filter_->filter_row_key(first_row_cell); + filter_all_remaining_ = filter_all_remaining_ || bret; + } + return bret; +} + +int WhileMatchFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(filter_->filter_cell(cell, ret_code))) { + } else { + filter_all_remaining_ = filter_all_remaining_ || (ReturnCode::INCLUDE != ret_code); + } + return ret; +} + +int WhileMatchFilter::transform_cell(const ObHTableCell &cell, const ObHTableCell *&new_cell) +{ + return filter_->transform_cell(cell, new_cell); +} + +bool WhileMatchFilter::filter_row() +{ + bool bret = filter_->filter_row(); + filter_all_remaining_ = filter_all_remaining_ || bret; + return bret; +} + +//////////////////////////////////////////////////////////////// +SingleColumnValueFilter::~SingleColumnValueFilter() +{} + +void SingleColumnValueFilter::reset() +{ + LOG_DEBUG("[yzfdebug] reset SingleColumnValueFilter"); + found_column_ = false; + matched_column_ = false; +} + +int SingleColumnValueFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) +{ + int ret = OB_SUCCESS; + if (matched_column_) { + // already found and matched the single column + ret_code = ReturnCode::INCLUDE; + LOG_DEBUG("[yzfdebug] already matched column", K(ret_code)); + } else if (latest_version_only_ && found_column_) { + // found but not matched the column + ret_code = ReturnCode::NEXT_ROW; + LOG_DEBUG("[yzfdebug] latest verion only but not matched", K(ret_code)); + } else if (!match_column(cell)) { + ret_code = ReturnCode::INCLUDE; + LOG_DEBUG("[yzfdebug] not found column yet", K(ret_code)); + } else { + found_column_ = true; + LOG_DEBUG("[yzfdebug] found column", K_(found_column)); + if (filter_column_value(cell)) { + ret_code = (latest_version_only_) ? (ReturnCode::NEXT_ROW) : (ReturnCode::INCLUDE); + LOG_DEBUG("[yzfdebug] found column but value not match", K_(latest_version_only), K(ret_code)); + } else { + matched_column_ = true; + ret_code = ReturnCode::INCLUDE; + LOG_DEBUG("[yzfdebug] found column and match", K(ret_code)); + } + } + return ret; +} + +bool SingleColumnValueFilter::match_column(const ObHTableCell &cell) +{ + return qualifier_ == cell.get_qualifier(); +} + +bool SingleColumnValueFilter::filter_column_value(const ObHTableCell &cell) +{ + int cmp_ret = comparator_->compare_to(cell.get_value()); + return CompareFilter::compare(cmp_op_, cmp_ret); +} + +bool SingleColumnValueFilter::filter_row() +{ + LOG_DEBUG("[yzfdebug] filter row", K_(found_column), K_(matched_column), K_(filter_if_missing)); + return found_column_ ? (!matched_column_) : (filter_if_missing_); +} +//////////////////////////////////////////////////////////////// +void ColumnCountGetFilter::reset() +{ + count_ = 0; +} + +bool ColumnCountGetFilter::filter_row_key(const ObHTableCell &first_row_cell) +{ + UNUSED(first_row_cell); + return filter_all_remaining(); +} + +bool ColumnCountGetFilter::filter_all_remaining() +{ + return count_ > limit_; +} + +int ColumnCountGetFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) +{ + int ret = OB_SUCCESS; + UNUSED(cell); + ++count_; + if (filter_all_remaining()) { + ret_code = ReturnCode::NEXT_COL; + } else { + ret_code = ReturnCode::INCLUDE_AND_NEXT_COL; + } + return ret; +} +//////////////////////////////////////////////////////////////// +CheckAndMutateFilter::~CheckAndMutateFilter() +{} + +void CheckAndMutateFilter::reset() +{ + LOG_DEBUG("[yzfdebug] reset CheckAndMutateFilter"); + found_column_ = false; + matched_column_ = false; +} + +int CheckAndMutateFilter::filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) +{ + int ret = OB_SUCCESS; + if (matched_column_) { + // already found and matched the single column + ret_code = ReturnCode::INCLUDE; + LOG_DEBUG("[yzfdebug] already matched column", K(ret_code)); + } else if (found_column_) { // latest_version_only_ == true + // found but not matched the column + if (value_is_null_) { + ret_code = ReturnCode::INCLUDE; + } else { + ret_code = ReturnCode::NEXT_ROW; + } + LOG_DEBUG("[yzfdebug] latest verion only but not matched", K(ret_code)); + } else if (!match_column(cell)) { + ret_code = ReturnCode::INCLUDE; + LOG_DEBUG("[yzfdebug] not found column yet", K(ret_code)); + } else { + found_column_ = true; + LOG_DEBUG("[yzfdebug] found column", K_(found_column)); + if (value_is_null_) { + ret_code = ReturnCode::NEXT_ROW; + } else { + if (filter_column_value(cell)) { + ret_code = ReturnCode::NEXT_ROW; + LOG_DEBUG("[yzfdebug] found column but value not match", K(ret_code)); + } else { + matched_column_ = true; + ret_code = ReturnCode::INCLUDE; + LOG_DEBUG("[yzfdebug] found column and match", K(ret_code)); + } + } + } + return ret; +} + +bool CheckAndMutateFilter::match_column(const ObHTableCell &cell) +{ + return qualifier_ == cell.get_qualifier(); +} + +bool CheckAndMutateFilter::filter_column_value(const ObHTableCell &cell) +{ + int cmp_ret = comparator_->compare_to(cell.get_value()); + return CompareFilter::compare(cmp_op_, cmp_ret); +} + +bool CheckAndMutateFilter::filter_row() +{ + LOG_DEBUG("[yzfdebug] filter row", K_(found_column), K_(matched_column), K_(value_is_null)); + bool bret = true; + if (value_is_null_) { + bret = found_column_; + } else { + bret = found_column_ ? (!matched_column_) : (false/*filter_if_missing*/); + } + return bret; +} diff --git a/src/observer/table/ob_htable_filters.h b/src/observer/table/ob_htable_filters.h new file mode 100644 index 0000000000000000000000000000000000000000..def8d1350eb9a6ffacb116b0780883057dcaf860 --- /dev/null +++ b/src/observer/table/ob_htable_filters.h @@ -0,0 +1,492 @@ +/** + * 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. + */ + +#ifndef _OB_HTABLE_FILTERS_H +#define _OB_HTABLE_FILTERS_H 1 +#include "ob_htable_utils.h" +#include "share/table/ob_table_rpc_struct.h" +namespace oceanbase +{ +namespace table +{ +/// hbase filters +/// @see https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/Filter.html +namespace hfilter +{ +typedef table::ObTableQueryResult RowCells; +/** Interface Filter + * Interface for row and column filters directly applied within the regionserver. A filter can expect the following call sequence: + * + reset() : reset the filter state before filtering a new row. + * + filterAllRemaining(): true means row scan is over; false means keep going. + * + filterRowKey(Cell): true means drop this row; false means include. + * + filterCell(Cell): decides whether to include or exclude this Cell. See Filter.ReturnCode. + * + transformCell(Cell): if the Cell is included, let the filter transform the Cell. + * + filterRowCells(List): allows direct modification of the final list to be submitted + * + filterRow(): last chance to drop entire row based on the sequence of filter calls. Eg: filter a row if it doesn't contain a specified column. + */ +class Filter +{ +public: + enum class ReturnCode + { + INCLUDE = 0, + INCLUDE_AND_NEXT_COL = 1, + INCLUDE_AND_SEEK_NEXT_ROW = 2, + SKIP = 3, + NEXT_COL = 4, + NEXT_ROW = 5, + SEEK_NEXT_USING_HINT = 6 + }; +public: + Filter(); + virtual ~Filter(); + + /// Reset the state of the filter between rows. + virtual void reset() = 0; + /// If this returns true, the scan will terminate. + virtual bool filter_all_remaining() = 0; + /// Filters a row based on the row key. + virtual bool filter_row_key(const ObHTableCell &first_row_cell) = 0; + /// A way to filter based on the column family, column qualifier and/or the column value. + virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) = 0; + /// Give the filter a chance to transform the passed KeyValue. + virtual int transform_cell(const ObHTableCell &cell, const ObHTableCell *&new_cell) = 0; + /// Chance to alter the list of Cells to be submitted. + virtual int filter_row_cells(const RowCells &cells) = 0; + /// Last chance to veto row based on previous filterCell(Cell) calls. + virtual bool filter_row() = 0; + + /// Primarily used to check for conflicts with scans(such as scans that do not read a full row at a time). + virtual bool has_filter_row() = 0; + + void set_reversed(bool reversed) { is_reversed_ = reversed; } + bool is_reversed() const { return is_reversed_; } + VIRTUAL_TO_STRING_KV("filter", "Filter"); +protected: + bool is_reversed_; +private: + DISALLOW_COPY_AND_ASSIGN(Filter); +}; + +enum class CompareOperator +{ + EQUAL, GREATER, GREATER_OR_EQUAL, LESS, LESS_OR_EQUAL, NO_OP, NOT_EQUAL +}; + +class FilterBase: public Filter +{ +public: + FilterBase() {} + virtual ~FilterBase(); + + virtual void reset() override {} + virtual bool filter_all_remaining() override { return false; } + virtual bool filter_row_key(const ObHTableCell &first_row_cell) override + { UNUSED(first_row_cell); if (filter_all_remaining()) return true; else return false; } + virtual int transform_cell(const ObHTableCell &cell, const ObHTableCell *&new_cell) override + { new_cell = &cell; return common::OB_SUCCESS; } + virtual int filter_row_cells(const RowCells &cells) override + { UNUSED(cells); return common::OB_SUCCESS; } + virtual bool filter_row() override { return false; } + virtual bool has_filter_row() override { return false; } + + static const char* compare_operator_to_string(CompareOperator cmp_op); +private: + DISALLOW_COPY_AND_ASSIGN(FilterBase); +}; + +class Comparable +{ +public: + Comparable(const ObString &comparator_value) + :comparator_value_(comparator_value) + {} + virtual ~Comparable() {} + virtual int compare_to(const ObString &b) = 0; + VIRTUAL_TO_STRING_KV("comprable", "Comprable"); +protected: + ObString comparator_value_; +private: + DISALLOW_COPY_AND_ASSIGN(Comparable); +}; + +class BinaryComparator: public Comparable +{ +public: + BinaryComparator(const ObString &comparator_value) + :Comparable(comparator_value) + {} + virtual ~BinaryComparator() {} + virtual int compare_to(const ObString &b) override; + TO_STRING_KV("comparable", "BinaryComparator"); +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(BinaryComparator); +}; + +class BinaryPrefixComparator: public Comparable +{ +public: + BinaryPrefixComparator(const ObString &comparator_value) + :Comparable(comparator_value) + {} + virtual ~BinaryPrefixComparator() {} + virtual int compare_to(const ObString &b) override; + TO_STRING_KV("comparable", "BinaryPrefixComparator"); +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(BinaryPrefixComparator); +}; + +class RegexStringComparator: public Comparable +{ +public: + RegexStringComparator(const ObString &comparator_value) + :Comparable(comparator_value) + {} + virtual ~RegexStringComparator() {} + virtual int compare_to(const ObString &b) override; + TO_STRING_KV("comparable", "RegexStringComparator"); +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(RegexStringComparator); +}; + +class SubStringComparator: public Comparable +{ +public: + SubStringComparator(const ObString &comparator_value) + :Comparable(comparator_value) + {} + virtual ~SubStringComparator() {} + virtual int compare_to(const ObString &b) override; + TO_STRING_KV("comparable", "SubStringComparator"); +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(SubStringComparator); +}; + +class CompareFilter: public FilterBase +{ +public: + CompareFilter(CompareOperator cmp_op, Comparable *comparator) + :cmp_op_(cmp_op), + comparator_(comparator) + {} + virtual ~CompareFilter(); + int check_arguments() const; + static bool compare(CompareOperator op, int cmp_ret); +protected: + bool compare_row(CompareOperator op, Comparable &comparator, const ObHTableCell &cell); + bool compare_qualifier(CompareOperator op, Comparable &comparator, const ObHTableCell &cell); + bool compare_value(CompareOperator op, Comparable &comparator, const ObHTableCell &cell); +protected: + CompareOperator cmp_op_; + Comparable *comparator_; +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(CompareFilter); +}; + +/// This filter is used to filter based on the key. +class RowFilter: public CompareFilter +{ +public: + RowFilter(CompareOperator cmp_op, Comparable *comparator) + :CompareFilter(cmp_op, comparator), + filter_out_row_(false) + {} + virtual ~RowFilter(); + virtual void reset() override; + virtual bool filter_row_key(const ObHTableCell &first_row_cell) override; + virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override; + virtual bool filter_row() override; + TO_STRING_KV("filter", "RowFilter", + "cmp_op", compare_operator_to_string(cmp_op_), + "comparator", comparator_); +private: + bool filter_out_row_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(RowFilter); +}; + +/// This filter is used to filter based on the key. +class QualifierFilter: public CompareFilter +{ +public: + QualifierFilter(CompareOperator cmp_op, Comparable *comparator) + :CompareFilter(cmp_op, comparator) + {} + virtual ~QualifierFilter(); + + virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override; + TO_STRING_KV("filter", "QualifierFilter", + "cmp_op", compare_operator_to_string(cmp_op_), + "comparator", comparator_); +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(QualifierFilter); +}; + +/// This filter is used to filter based on column value. +class ValueFilter: public CompareFilter +{ +public: + ValueFilter(CompareOperator cmp_op, Comparable *comparator) + :CompareFilter(cmp_op, comparator) + {} + virtual ~ValueFilter(); + virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override; + TO_STRING_KV("filter", "ValueFilter", + "cmp_op", compare_operator_to_string(cmp_op_), + "comparator", comparator_); +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(ValueFilter); +}; + +/// represents an ordered List of Filters which will be evaluated with a specified boolean operator +/// FilterList.Operator.MUST_PASS_ALL (AND) or FilterList.Operator.MUST_PASS_ONE (OR). +class FilterListBase: public FilterBase +{ +public: + enum class Operator + { MUST_PASS_ALL/*AND*/, MUST_PASS_ONE/*OR*/ }; +public: + FilterListBase(Operator op) + :op_(op) + {} + virtual ~FilterListBase(); + + int add_filter(Filter *filter); + Operator get_operator() const { return op_; } + virtual void reset() override; + + TO_STRING_KV("filter", "FilterList", + "op", operator_to_string(op_), + "filters", filters_); + static const char* operator_to_string(Operator op); +protected: + Operator op_; + ObSEArray filters_; +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(FilterListBase); +}; + +class FilterListAND: public FilterListBase +{ +public: + FilterListAND(Operator op) + :FilterListBase(op) + {} + virtual ~FilterListAND(); + virtual void reset() override; + virtual bool filter_all_remaining() override; + virtual bool filter_row_key(const ObHTableCell &first_row_cell) override; + virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override; + virtual bool filter_row() override; +private: + static ReturnCode merge_return_code(ReturnCode rc, ReturnCode local_rc); + ObSEArray seek_hint_filters_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(FilterListAND); +}; + +class FilterListOR: public FilterListBase +{ +public: + FilterListOR(Operator op) + :FilterListBase(op) + {} + virtual ~FilterListOR(); + virtual void reset() override; + virtual bool filter_all_remaining() override; + virtual bool filter_row_key(const ObHTableCell &first_row_cell) override; + virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override; + virtual bool filter_row() override; +private: + static ReturnCode merge_return_code(ReturnCode rc, ReturnCode local_rc); + // disallow copy + DISALLOW_COPY_AND_ASSIGN(FilterListOR); +}; + +/// A wrapper filter that filters an entire row if any of the Cell checks do not pass. +class SkipFilter: public FilterBase +{ +public: + SkipFilter(Filter *filter) + :filter_(filter), + filter_row_(false) + {} + virtual ~SkipFilter(); + virtual void reset() override; + virtual bool filter_row_key(const ObHTableCell &first_row_cell) override; + virtual bool filter_row() override; + virtual bool has_filter_row() override { return true; } + virtual int transform_cell(const ObHTableCell &cell, const ObHTableCell *&new_cell) override; + virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override; + TO_STRING_KV("filter", "SkipFilter", + "sub_filter", filter_); +private: + Filter *filter_; + bool filter_row_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(SkipFilter); +}; + +/// A wrapper filter that returns true from filterAllRemaining() as soon as the wrapped filters +/// Filter.filterRowKey(), Filter.filterCell(), Filter.filterRow() or Filter.filterAllRemaining() methods returns true. +class WhileMatchFilter: public FilterBase +{ +public: + WhileMatchFilter(Filter *filter) + :filter_(filter), + filter_all_remaining_(false) + {} + virtual ~WhileMatchFilter(); + + virtual void reset() override; + virtual bool filter_all_remaining() override; + virtual bool filter_row_key(const ObHTableCell &first_row_cell) override; + virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override; + virtual int transform_cell(const ObHTableCell &cell, const ObHTableCell *&new_cell) override; + virtual bool filter_row() override; + virtual bool has_filter_row() override { return true; } + + TO_STRING_KV("filter", "WhileMatchFilter", + "sub_filter", filter_); +private: + Filter *filter_; + bool filter_all_remaining_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(WhileMatchFilter); +}; + +class SingleColumnValueFilter: public FilterBase +{ +public: + SingleColumnValueFilter(const ObString &family, const ObString &qualifier, CompareOperator cmp_op, Comparable *comparator) + :family_(family), + qualifier_(qualifier), + cmp_op_(cmp_op), + comparator_(comparator), + filter_if_missing_(false), + latest_version_only_(true), + found_column_(false), + matched_column_(false) + {} + virtual ~SingleColumnValueFilter(); + void set_filter_if_missing(bool v) { filter_if_missing_ = v; } + void set_latest_version_only(bool v) { latest_version_only_ = v; } + + virtual void reset() override; + virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override; + virtual bool filter_row() override; + virtual bool has_filter_row() override { return true; } + TO_STRING_KV("filter", "SingleColumnValueFilter", + K_(family), + K_(qualifier), + "cmp_op", compare_operator_to_string(cmp_op_), + K_(comparator), + K_(filter_if_missing), + K_(latest_version_only)); +private: + bool filter_column_value(const ObHTableCell &cell); + bool match_column(const ObHTableCell &cell); +private: + ObString family_; + ObString qualifier_; + CompareOperator cmp_op_; + Comparable *comparator_; + bool filter_if_missing_; // default: false + bool latest_version_only_; // default: true + // state + bool found_column_; + bool matched_column_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(SingleColumnValueFilter); +}; + +/// Simple filter that returns first N columns on row only. +class ColumnCountGetFilter: public FilterBase +{ +public: + ColumnCountGetFilter(int64_t limit) + :limit_(limit), + count_(0) + {} + virtual ~ColumnCountGetFilter() {} + virtual void reset() override; + virtual bool filter_row_key(const ObHTableCell &first_row_cell) override; + virtual bool filter_all_remaining() override; + virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override; + TO_STRING_KV("filter", "ColumnCountGetFilter", + K_(limit)); +private: + int64_t limit_; + int64_t count_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(ColumnCountGetFilter); +}; + +/// CheckAndMutateFilter is used to implement the check logic of CheckAndMutate +/// @see https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html#checkAndMutate-byte:A-byte:A- +class CheckAndMutateFilter: public FilterBase +{ +public: + CheckAndMutateFilter(const ObString &family, const ObString &qualifier, CompareOperator cmp_op, + Comparable *comparator, bool value_is_null) + :family_(family), + qualifier_(qualifier), + cmp_op_(cmp_op), + comparator_(comparator), + value_is_null_(value_is_null), + found_column_(false), + matched_column_(false) + {} + virtual ~CheckAndMutateFilter(); + + virtual void reset() override; + virtual int filter_cell(const ObHTableCell &cell, ReturnCode &ret_code) override; + virtual bool filter_row() override; + virtual bool has_filter_row() override { return true; } + TO_STRING_KV("filter", "CheckAndMutateFilter", + K_(family), + K_(qualifier), + "cmp_op", compare_operator_to_string(cmp_op_), + K_(comparator), + K_(value_is_null)); +private: + bool filter_column_value(const ObHTableCell &cell); + bool match_column(const ObHTableCell &cell); +private: + ObString family_; + ObString qualifier_; + CompareOperator cmp_op_; + Comparable *comparator_; + // If the passed value is null, the check is for the lack of column (ie: non-existence) + bool value_is_null_; // default: false + // state + bool found_column_; + bool matched_column_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(CheckAndMutateFilter); +}; + + +} // end namespace hfilter + +} // end namespace table +} // end namespace oceanbase + +#endif /* _OB_HTABLE_FILTERS_H */ diff --git a/src/observer/table/ob_htable_utils.cpp b/src/observer/table/ob_htable_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d63e4ab4a48d05519a1674c6b26fe7427e7f97ff --- /dev/null +++ b/src/observer/table/ob_htable_utils.cpp @@ -0,0 +1,312 @@ +/** + * 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. + */ + +#define USING_LOG_PREFIX SERVER +#include "ob_htable_utils.h" +#include // be64toh +using namespace oceanbase::common; +using namespace oceanbase::table; + +ObHTableCellEntity::ObHTableCellEntity(common::ObNewRow *ob_row) + :ob_row_(ob_row) +{} + +ObHTableCellEntity::ObHTableCellEntity() + :ob_row_(NULL) +{} + +ObHTableCellEntity::~ObHTableCellEntity() +{} + +ObString ObHTableCellEntity::get_rowkey() const +{ + return ob_row_->get_cell(ObHTableConstants::COL_IDX_K).get_varchar(); +} + +ObString ObHTableCellEntity::get_qualifier() const +{ + return ob_row_->get_cell(ObHTableConstants::COL_IDX_Q).get_varchar(); +} + +int64_t ObHTableCellEntity::get_timestamp() const +{ + return ob_row_->get_cell(ObHTableConstants::COL_IDX_T).get_int(); +} + +ObString ObHTableCellEntity::get_value() const +{ + return ob_row_->get_cell(ObHTableConstants::COL_IDX_V).get_varchar(); +} +//////////////////////////////////////////////////////////////// +ObString ObHTableCellEntity2::get_rowkey() const +{ + ObString rowkey_str; + int ret = OB_SUCCESS; + ObObj val; + if (OB_FAIL(entity_->get_property(ObHTableConstants::ROWKEY_CNAME_STR, val))) { + LOG_WARN("failed to get property K", K(ret)); + } else { + rowkey_str = val.get_varchar(); + } + return rowkey_str; +} + +ObString ObHTableCellEntity2::get_qualifier() const +{ + ObString rowkey_str; + int ret = OB_SUCCESS; + ObObj val; + if (OB_FAIL(entity_->get_property(ObHTableConstants::CQ_CNAME_STR, val))) { + LOG_WARN("failed to get property K", K(ret)); + } else { + rowkey_str = val.get_varchar(); + } + return rowkey_str; +} + +int64_t ObHTableCellEntity2::get_timestamp() const +{ + int64_t ts = -1; + int ret = OB_SUCCESS; + ObObj val; + if (OB_FAIL(entity_->get_property(ObHTableConstants::VERSION_CNAME_STR, val))) { + LOG_WARN("failed to get property K", K(ret)); + } else { + ts = val.get_int(); + } + return ts; +} + +ObString ObHTableCellEntity2::get_value() const +{ + ObString rowkey_str; + int ret = OB_SUCCESS; + ObObj val; + if (OB_FAIL(entity_->get_property(ObHTableConstants::VALUE_CNAME_STR, val))) { + LOG_WARN("failed to get property K", K(ret)); + } else { + rowkey_str = val.get_varchar(); + } + return rowkey_str; +} +//////////////////////////////////////////////////////////////// +ObString ObHTableCellEntity3::get_rowkey() const +{ + int ret = OB_SUCCESS; + last_get_is_null_ = false; + ObObj obj; + ObString val; + if (OB_FAIL(entity_->get_rowkey_value(ObHTableConstants::COL_IDX_K, obj))) { + LOG_WARN("failed to get K from entity", K(ret), K_(entity)); + } else if (obj.is_null()) { + last_get_is_null_ = true; + } else { + val = obj.get_varchar(); + } + return val; +} + +ObString ObHTableCellEntity3::get_qualifier() const +{ + int ret = OB_SUCCESS; + last_get_is_null_ = false; + ObObj obj; + ObString val; + if (OB_FAIL(entity_->get_rowkey_value(ObHTableConstants::COL_IDX_Q, obj))) { + LOG_WARN("failed to get T from entity", K(ret), K_(entity)); + } else if (obj.is_null()) { + last_get_is_null_ = true; + } else { + val = obj.get_varchar(); + } + return val; +} + +int64_t ObHTableCellEntity3::get_timestamp() const +{ + int ret = OB_SUCCESS; + last_get_is_null_ = false; + ObObj obj; + int64_t val = 0; + if (OB_FAIL(entity_->get_rowkey_value(ObHTableConstants::COL_IDX_T, obj))) { + LOG_WARN("failed to get T from entity", K(ret), K_(entity)); + } else if (obj.is_null()) { + last_get_is_null_ = true; + } else if (OB_FAIL(obj.get_int(val))) { + LOG_WARN("invalid obj type for T", K(ret), K(obj)); + last_get_is_null_ = true; + } + return val; +} + +ObString ObHTableCellEntity3::get_value() const +{ + int ret = OB_SUCCESS; + last_get_is_null_ = false; + ObObj obj; + ObString str; + if (OB_FAIL(entity_->get_property(ObHTableConstants::VALUE_CNAME_STR, obj))) { + LOG_WARN("failed to get property V", K(ret), K_(entity)); + } else if (obj.is_null()) { + last_get_is_null_ = true; + } else if (!obj.is_string_type()) { + LOG_WARN("invalid obj type", K(ret), K(obj)); + last_get_is_null_ = true; + } else { + str = obj.get_varchar(); + } + return str; +} + +//////////////////////////////////////////////////////////////// +int ObHTableUtils::create_last_cell_on_row_col(common::ObArenaAllocator &allocator, + const ObHTableCell &cell, ObHTableCell *&new_cell) +{ + int ret = OB_SUCCESS; + ObString rowkey_clone; + ObString qualifier_clone; + if (OB_FAIL(ob_write_string(allocator, cell.get_rowkey(), rowkey_clone))) { + LOG_WARN("failed to clone rowkey", K(ret)); + } else if (OB_FAIL(ob_write_string(allocator, cell.get_qualifier(), qualifier_clone))) { + LOG_WARN("failed to clone qualifier", K(ret)); + } else { + new_cell = OB_NEWx(ObHTableLastOnRowColCell, (&allocator), rowkey_clone, qualifier_clone); + if (NULL == new_cell) { + LOG_WARN("no memory", K(ret)); + ret = OB_ALLOCATE_MEMORY_FAILED; + } + } + return ret; +} + +int ObHTableUtils::create_first_cell_on_row_col(common::ObArenaAllocator &allocator, + const ObHTableCell &cell, + const common::ObString &qualifier, + ObHTableCell *&new_cell) +{ + int ret = OB_SUCCESS; + ObString rowkey_clone; + ObString qualifier_clone; + if (OB_FAIL(ob_write_string(allocator, cell.get_rowkey(), rowkey_clone))) { + LOG_WARN("failed to clone rowkey", K(ret)); + } else if (OB_FAIL(ob_write_string(allocator, qualifier, qualifier_clone))) { + LOG_WARN("failed to clone qualifier", K(ret)); + } else { + new_cell = OB_NEWx(ObHTableFirstOnRowColCell, (&allocator), rowkey_clone, qualifier_clone); + if (NULL == new_cell) { + LOG_WARN("no memory", K(ret)); + ret = OB_ALLOCATE_MEMORY_FAILED; + } + } + return ret; +} + +int ObHTableUtils::create_last_cell_on_row(common::ObArenaAllocator &allocator, + const ObHTableCell &cell, ObHTableCell *&new_cell) +{ + int ret = OB_SUCCESS; + ObString rowkey_clone; + if (OB_FAIL(ob_write_string(allocator, cell.get_rowkey(), rowkey_clone))) { + LOG_WARN("failed to clone rowkey", K(ret)); + } else { + new_cell = OB_NEWx(ObHTableLastOnRowCell, (&allocator), rowkey_clone); + if (NULL == new_cell) { + LOG_WARN("no memory", K(ret)); + ret = OB_ALLOCATE_MEMORY_FAILED; + } + } + return ret; +} + +int ObHTableUtils::compare_cell(const ObHTableCell &cell1, const ObHTableCell &cell2, common::ObQueryFlag::ScanOrder &scan_order) +{ + // compare rowkey + int cmp_ret; + if (common::ObQueryFlag::Reverse == scan_order) { + cmp_ret = cell2.get_rowkey().compare(cell1.get_rowkey()); + } else { + cmp_ret = cell1.get_rowkey().compare(cell2.get_rowkey()); + } + if (0 == cmp_ret) { + // the same rowkey + if (ObHTableCell::Type::LAST_ON_ROW == cell1.get_type()) { + // cell1 is last cell on row + cmp_ret = 1; + } else if (ObHTableCell::Type::LAST_ON_ROW == cell2.get_type()) { + // cell2 is last cell on row + cmp_ret = -1; + } else { + // compare qualifiers + ObString qualifier1 = cell1.get_qualifier(); + ObString qualifier2 = cell2.get_qualifier(); + if(common::ObQueryFlag::Reverse == scan_order){ + cmp_ret = qualifier2.compare(qualifier1); + } else { + cmp_ret = qualifier1.compare(qualifier2); + } + if (0 == cmp_ret) { + // compare timestamps in ascending order (the value of timestamp is negative) + int64_t ts1 = cell1.get_timestamp(); + int64_t ts2 = cell2.get_timestamp(); + if (ts1 == ts2) { + // one of the cells could be ObHTableFirstOnRowCell or ObHTableFirstOnRowColCell + if (common::ObQueryFlag::Reverse == scan_order) { + cmp_ret = static_cast(cell2.get_type()) - static_cast(cell1.get_type()); + } else { + cmp_ret = static_cast(cell1.get_type()) - static_cast(cell2.get_type()); + } + } else if (ts1 < ts2) { + cmp_ret = -1; + } else { + cmp_ret = 1; + } + } + } + } + return cmp_ret; +} + +int ObHTableUtils::compare_qualifier(const common::ObString &cq1, const common::ObString &cq2) +{ + return cq1.compare(cq2); +} + +int ObHTableUtils::compare_rowkey(const common::ObString &rk1, const common::ObString &rk2) +{ + return rk1.compare(rk2); +} + +int ObHTableUtils::compare_rowkey(const ObHTableCell &cell1, const ObHTableCell &cell2) +{ + return compare_rowkey(cell1.get_rowkey(), cell2.get_rowkey()); +} + +int ObHTableUtils::java_bytes_to_int64(const ObString &bytes, int64_t &val) +{ + int ret = OB_SUCCESS; + if (bytes.length() != sizeof(int64_t)) { + ret = OB_INVALID_DATA; + LOG_WARN("length should be 8 bytes", K(ret), "len", bytes.length()); + } else { + // In Java, data is stored in big-endian format (also called network order). + const uint64_t *big_endian_64bits = reinterpret_cast(bytes.ptr()); + val = be64toh(*big_endian_64bits); + } + return ret; +} + +int ObHTableUtils::int64_to_java_bytes(int64_t val, char bytes[8]) +{ + uint64_t big_endian_64bits = htobe64(val); + memcpy(bytes, &big_endian_64bits, sizeof(int64_t)); + return OB_SUCCESS; +} diff --git a/src/observer/table/ob_htable_utils.h b/src/observer/table/ob_htable_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..eff95628edda16920942b646a863139b8f02fd88 --- /dev/null +++ b/src/observer/table/ob_htable_utils.h @@ -0,0 +1,313 @@ +/** + * 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. + */ + +#ifndef _OB_HTABLE_UTILS_H +#define _OB_HTABLE_UTILS_H 1 +#include "common/row/ob_row.h" +#include "lib/string/ob_string.h" +#include "share/table/ob_table.h" +#include + +namespace oceanbase +{ +namespace table +{ +// Interface ObHTableCell +class ObHTableCell +{ +public: + ObHTableCell() {} + virtual ~ObHTableCell() {} + + virtual common::ObString get_rowkey() const = 0; + virtual common::ObString get_qualifier() const = 0; + virtual int64_t get_timestamp() const = 0; + virtual common::ObString get_value() const = 0; + enum class Type + { + FIRST_ON_ROW = 0 /*virtual cell which present the first cell on row*/, + FIRST_ON_COL = 1 /*virtual cell which present the first cell on column*/, + NORMAL = 2, + LAST_ON_COL = 3 /*virtual cell which present the last cell on column, "bigger" than other cells*/, + LAST_ON_ROW = 4 /*virtual cell which present the last cell on row, "bigger" than other cells*/ + }; + // true for + virtual Type get_type() const = 0; + TO_STRING_KV(ObHTableConstants::ROWKEY_CNAME, get_rowkey(), + ObHTableConstants::CQ_CNAME, get_qualifier(), + ObHTableConstants::VERSION_CNAME, get_timestamp(), + ObHTableConstants::VALUE_CNAME, get_value()); +private: + DISALLOW_COPY_AND_ASSIGN(ObHTableCell); +}; + +class ObHTableCellEntity: public ObHTableCell +{ +public: + explicit ObHTableCellEntity(common::ObNewRow *ob_row); + ObHTableCellEntity(); + virtual ~ObHTableCellEntity(); + + void set_ob_row(common::ObNewRow *ob_row) { ob_row_ = ob_row; } + const common::ObNewRow* get_ob_row() const { return ob_row_; } + + virtual common::ObString get_rowkey() const override; + virtual common::ObString get_qualifier() const override; + virtual int64_t get_timestamp() const override; + virtual common::ObString get_value() const override; + virtual Type get_type() const { return Type::NORMAL; } +private: + common::ObNewRow *ob_row_; + DISALLOW_COPY_AND_ASSIGN(ObHTableCellEntity); +}; + +class ObHTableEmptyCell: public ObHTableCell +{ +public: + ObHTableEmptyCell() {} + virtual ~ObHTableEmptyCell() {} + + virtual common::ObString get_rowkey() const override { return common::ObString(); } + virtual common::ObString get_qualifier() const override { return common::ObString(); } + virtual common::ObString get_value() const override { return common::ObString(); } +private: + DISALLOW_COPY_AND_ASSIGN(ObHTableEmptyCell); +}; + +class ObHTableFirstOnRowCell: public ObHTableEmptyCell +{ +public: + ObHTableFirstOnRowCell(const common::ObString &rowkey) + :rowkey_(rowkey) + {} + virtual ~ObHTableFirstOnRowCell() {} + + virtual common::ObString get_rowkey() const override { return rowkey_; } + virtual int64_t get_timestamp() const override { return ObHTableConstants::LATEST_TIMESTAMP; } + virtual Type get_type() const { return Type::FIRST_ON_ROW; } +private: + common::ObString rowkey_; + DISALLOW_COPY_AND_ASSIGN(ObHTableFirstOnRowCell); +}; + +class ObHTableFirstOnRowColCell: public ObHTableFirstOnRowCell +{ +public: + ObHTableFirstOnRowColCell(const common::ObString &rowkey, const common::ObString &qualifier) + :ObHTableFirstOnRowCell(rowkey), + qualifier_(qualifier) + {} + virtual ~ObHTableFirstOnRowColCell() {} + + virtual common::ObString get_qualifier() const override { return qualifier_; } + virtual Type get_type() const { return Type::FIRST_ON_COL; } +private: + common::ObString qualifier_; + DISALLOW_COPY_AND_ASSIGN(ObHTableFirstOnRowColCell); +}; + +class ObHTableLastOnRowCell: public ObHTableEmptyCell +{ +public: + ObHTableLastOnRowCell(const common::ObString &rowkey) + :rowkey_(rowkey) + {} + virtual ~ObHTableLastOnRowCell() {} + + virtual common::ObString get_rowkey() const override { return rowkey_; } + virtual int64_t get_timestamp() const override { return ObHTableConstants::OLDEST_TIMESTAMP; } + virtual Type get_type() const { return Type::LAST_ON_ROW; } +private: + common::ObString rowkey_; + DISALLOW_COPY_AND_ASSIGN(ObHTableLastOnRowCell); +}; + +class ObHTableLastOnRowColCell: public ObHTableLastOnRowCell +{ +public: + ObHTableLastOnRowColCell(const common::ObString &rowkey, const common::ObString &qualifier) + :ObHTableLastOnRowCell(rowkey), + qualifier_(qualifier) + {} + virtual ~ObHTableLastOnRowColCell() {} + + virtual common::ObString get_qualifier() const override { return qualifier_; } + virtual Type get_type() const { return Type::LAST_ON_COL; } +private: + common::ObString qualifier_; + DISALLOW_COPY_AND_ASSIGN(ObHTableLastOnRowColCell); +}; + +class ObHTableCellEntity2: public ObHTableCell +{ +public: + explicit ObHTableCellEntity2(const ObITableEntity *entity) + :entity_(entity) + {} + virtual ~ObHTableCellEntity2() {} + + virtual common::ObString get_rowkey() const override; + virtual common::ObString get_qualifier() const override; + virtual int64_t get_timestamp() const override; + virtual common::ObString get_value() const override; + virtual Type get_type() const { return Type::NORMAL; } +private: + const ObITableEntity *entity_; + DISALLOW_COPY_AND_ASSIGN(ObHTableCellEntity2); +}; + +class ObHTableCellEntity3: public ObHTableCell +{ +public: + explicit ObHTableCellEntity3(const ObITableEntity *entity) + :entity_(entity), + last_get_is_null_(false) + {} + virtual ~ObHTableCellEntity3() {} + + virtual common::ObString get_rowkey() const override; + virtual common::ObString get_qualifier() const override; + virtual int64_t get_timestamp() const override; + virtual common::ObString get_value() const override; + bool last_get_is_null() const { return last_get_is_null_; } + virtual Type get_type() const { return Type::NORMAL; } +private: + const ObITableEntity *entity_; + mutable bool last_get_is_null_; + DISALLOW_COPY_AND_ASSIGN(ObHTableCellEntity3); +}; + +/// Represents an interval of version timestamps. +/// [min_stamp, max_stamp), e.g. [3, 5) +class ObTimeRange final +{ +public: + ObTimeRange() + :min_stamp_(ObHTableConstants::INITIAL_MIN_STAMP), + max_stamp_(ObHTableConstants::INITIAL_MAX_STAMP), + is_all_time_(true) + {} + + ObTimeRange(int64_t min, int64_t max) + :min_stamp_(min), + max_stamp_(max) + { + is_all_time_ = is_all_time(); + } + /** + * Compare the timestamp to timerange. + * @return -1 if timestamp is less than timerange, + * 0 if timestamp is within timerange, + * 1 if timestamp is greater than timerange + */ + inline int compare(int64_t timestamp) const + { + int cmp_ret = 0; + if (is_all_time()) { + cmp_ret = 0; + } else if (timestamp < min_stamp_) { + cmp_ret = -1; + } else if (timestamp >= max_stamp_) { + cmp_ret = 1; + } + return cmp_ret; + } +private: + bool is_all_time() const + { + return ObHTableConstants::INITIAL_MIN_STAMP == min_stamp_ + && ObHTableConstants::INITIAL_MAX_STAMP == max_stamp_; + } +private: + int64_t min_stamp_; + int64_t max_stamp_; + bool is_all_time_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(ObTimeRange); +}; + +/// (min_stamp, max_stamp], e.g. (-5, -3] +class ObNegativeTimeRange final +{ + static constexpr int64_t INITIAL_NEG_MIN_STAMP = -INT64_MAX; + static constexpr int64_t INITIAL_NEG_MAX_STAMP = 0; +public: + ObNegativeTimeRange() + :min_stamp_(INITIAL_NEG_MIN_STAMP), + max_stamp_(INITIAL_NEG_MAX_STAMP) + { + is_all_time_ = is_all_time(); + } + ObNegativeTimeRange(int64_t min, int64_t max) + :min_stamp_(min), + max_stamp_(max) + { + is_all_time_ = is_all_time(); + } /** + * Compare the timestamp to timerange. + * @return -1 if timestamp is less than timerange, + * 0 if timestamp is within timerange, + * 1 if timestamp is greater than timerange + */ + inline int compare(int64_t timestamp) const + { + int cmp_ret = 0; + if (is_all_time()) { + cmp_ret = 0; + } else if (timestamp <= min_stamp_) { + cmp_ret = 1; + } else if (timestamp > max_stamp_) { + cmp_ret = -1; + } + return cmp_ret; + } + TO_STRING_KV(K_(min_stamp), K_(max_stamp), K_(is_all_time)); +private: + bool is_all_time() const + { + return INITIAL_NEG_MIN_STAMP == min_stamp_ + && INITIAL_NEG_MAX_STAMP == max_stamp_; + } +private: + int64_t min_stamp_; + int64_t max_stamp_; + bool is_all_time_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(ObNegativeTimeRange); +}; + +class ObHTableUtils +{ +public: + /// Create a Cell that is larger than all other possible Cells for the given Cell's rk:cf:q + static int create_last_cell_on_row_col(common::ObArenaAllocator &allocator, const ObHTableCell &cell, ObHTableCell *&new_cell); + /// Create a Cell that is smaller than all other possible Cells for the given Cell's rk:cf and passed qualifier. + static int create_first_cell_on_row_col(common::ObArenaAllocator &allocator, const ObHTableCell &cell, const common::ObString &qualifier, ObHTableCell *&new_cell); + /// Create a Cell that is larger than all other possible Cells for the given Cell's row. + static int create_last_cell_on_row(common::ObArenaAllocator &allocator, const ObHTableCell &cell, ObHTableCell *&new_cell); + + static int compare_qualifier(const common::ObString &cq1, const common::ObString &cq2); + static int compare_rowkey(const common::ObString &rk1, const common::ObString &rk2); + static int compare_rowkey(const ObHTableCell &cell1, const ObHTableCell &cell2); + static int compare_cell(const ObHTableCell &cell1, const ObHTableCell &cell2, common::ObQueryFlag::ScanOrder &scan_order); + static int64_t current_time_millis() { return common::ObTimeUtility::current_time() / 1000; } + static int java_bytes_to_int64(const ObString &bytes, int64_t &val); + static int int64_to_java_bytes(int64_t val, char bytes[8]); +private: + ObHTableUtils() = delete; + ~ObHTableUtils() = delete; +}; + +} // end namespace table +} // end namespace oceanbase + +#endif /* _OB_HTABLE_UTILS_H */ diff --git a/src/observer/table/ob_table_batch_execute_processor.cpp b/src/observer/table/ob_table_batch_execute_processor.cpp index 7d6951293eb274df83a4f289d491f66e25316145..41951f2279220a26a8b85e3f29f3d4094d591aea 100644 --- a/src/observer/table/ob_table_batch_execute_processor.cpp +++ b/src/observer/table/ob_table_batch_execute_processor.cpp @@ -19,7 +19,7 @@ #include "sql/optimizer/ob_table_location.h" // ObTableLocation #include "lib/stat/ob_diagnose_info.h" #include "lib/stat/ob_session_stat.h" - +#include "ob_htable_utils.h" using namespace oceanbase::observer; using namespace oceanbase::common; using namespace oceanbase::table; @@ -40,13 +40,27 @@ int ObTableBatchExecuteP::deserialize() arg_.batch_operation_.set_entity_factory(&default_entity_factory_); result_.set_entity_factory(&default_entity_factory_); int ret = ParentType::deserialize(); + if (OB_SUCC(ret) && ObTableEntityType::ET_HKV == arg_.entity_type_) { + // for HKV, modify the value of timestamp to be negative + const int64_t N = arg_.batch_operation_.count(); + for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) + { + ObITableEntity *entity = nullptr; + if (OB_FAIL(const_cast(arg_.batch_operation_.at(i)).get_entity(entity))) { + LOG_WARN("failed to get entity", K(ret), K(i)); + } else if (OB_FAIL(ObTableRpcProcessorUtil::negate_htable_timestamp(*entity))) { + LOG_WARN("failed to negate timestamp value", K(ret)); + } + } // end for + } return ret; } int ObTableBatchExecuteP::check_arg() { int ret = OB_SUCCESS; - if (arg_.consistency_level_ != ObTableConsistencyLevel::STRONG) { + if (!(arg_.consistency_level_ == ObTableConsistencyLevel::STRONG || + arg_.consistency_level_ == ObTableConsistencyLevel::EVENTUAL)) { ret = OB_NOT_SUPPORTED; LOG_WARN("some options not supported yet", K(ret), "consistency_level", arg_.consistency_level_); @@ -102,7 +116,22 @@ int ObTableBatchExecuteP::response(const int retcode) { int ret = OB_SUCCESS; if (!need_retry_in_queue_ && !did_async_end_trans()) { - ret = ObRpcProcessor::response(retcode); + // For HKV table, modify the value of timetamp to be positive + if (OB_SUCC(ret) && ObTableEntityType::ET_HKV == arg_.entity_type_) { + const int64_t N = result_.count(); + for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) + { + ObITableEntity *entity = nullptr; + if (OB_FAIL(result_.at(i).get_entity(entity))) { + LOG_WARN("failed to get entity", K(ret), K(i)); + } else if (OB_FAIL(ObTableRpcProcessorUtil::negate_htable_timestamp(*entity))) { + LOG_WARN("failed to negate timestamp value", K(ret)); + } + } // end for + } + if (OB_SUCC(ret)) { + ret = ObRpcProcessor::response(retcode); + } } return ret; } @@ -140,16 +169,26 @@ int ObTableBatchExecuteP::try_process() ret = multi_insert(); break; case ObTableOperationType::DEL: - stat_event_type_ = ObTableProccessType::TABLE_API_MULTI_DELETE; - ret = multi_delete(); + if (ObTableEntityType::ET_HKV == arg_.entity_type_) { + stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_DELETE; + ret = htable_delete(); + } else { + stat_event_type_ = ObTableProccessType::TABLE_API_MULTI_DELETE; + ret = multi_delete(); + } break; case ObTableOperationType::UPDATE: stat_event_type_ = ObTableProccessType::TABLE_API_MULTI_UPDATE; ret = multi_update(); break; case ObTableOperationType::INSERT_OR_UPDATE: - stat_event_type_ = ObTableProccessType::TABLE_API_MULTI_INSERT_OR_UPDATE; - ret = multi_insert_or_update(); + if (ObTableEntityType::ET_HKV == arg_.entity_type_) { + stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_PUT; + ret = htable_put(); + } else { + stat_event_type_ = ObTableProccessType::TABLE_API_MULTI_INSERT_OR_UPDATE; + ret = multi_insert_or_update(); + } break; case ObTableOperationType::REPLACE: stat_event_type_ = ObTableProccessType::TABLE_API_MULTI_REPLACE; @@ -169,9 +208,15 @@ int ObTableBatchExecuteP::try_process() break; } } else { - // complex batch hybrid operation - stat_event_type_ = ObTableProccessType::TABLE_API_BATCH_HYBRID; - ret = batch_execute(false); + if (ObTableEntityType::ET_HKV == arg_.entity_type_) { + // HTable mutate_row(RowMutations) + stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_HYBRID; + ret = htable_mutate_row(); + } else { + // complex batch hybrid operation + stat_event_type_ = ObTableProccessType::TABLE_API_BATCH_HYBRID; + ret = batch_execute(false); + } } } @@ -277,6 +322,54 @@ int ObTableBatchExecuteP::multi_insert_or_update() return ret; } +int ObTableBatchExecuteP::htable_put() +{ + int ret = OB_SUCCESS; + const ObTableBatchOperation &batch_operation = arg_.batch_operation_; + const bool is_readonly = false; + uint64_t table_id = OB_INVALID_ID; + ObSEArray part_ids; + + if (OB_FAIL(check_arg2())) { + } else if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) { + LOG_WARN("failed to get table id", K(ret)); + } else if (OB_FAIL(get_partition_ids(table_id, part_ids))) { + LOG_WARN("failed to get part id", K(ret)); + } else if (1 != part_ids.count()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("should have one partition", K(ret), K(part_ids)); + } else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_INSERT, table_id, part_ids, get_timeout_ts()))) { + LOG_WARN("failed to start transaction", K(ret)); + } else { + int64_t affected_rows = 0; + ObHTablePutExecutor put_executor(allocator_, + table_id, + part_ids.at(0), + get_timeout_ts(), + this, + table_service_, + part_service_); + ret = put_executor.htable_put(batch_operation, affected_rows); + if (OB_SUCC(ret)) { + ObTableOperationResult single_op_result; + single_op_result.set_entity(result_entity_); + single_op_result.set_type(ObTableOperationType::INSERT_OR_UPDATE); + single_op_result.set_errno(ret); + single_op_result.set_affected_rows(affected_rows); + result_.reset(); + if (OB_FAIL(result_.push_back(single_op_result))) { + LOG_WARN("failed to add result", K(ret)); + } + } + } + int tmp_ret = ret; + if (OB_FAIL(end_trans(OB_SUCCESS != ret, req_, get_timeout_ts()))) { + LOG_WARN("failed to end trans"); + } + ret = (OB_SUCCESS == tmp_ret) ? ret : tmp_ret; + return ret; +} + int ObTableBatchExecuteP::multi_get() { int ret = OB_SUCCESS; @@ -288,6 +381,7 @@ int ObTableBatchExecuteP::multi_get() arg_.binlog_row_image_type_); ObSEArray part_ids; const bool is_readonly = true; + const ObTableConsistencyLevel consistency_level = arg_.consistency_level_; if (OB_FAIL(check_arg2())) { } else if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) { LOG_WARN("failed to get table id", K(ret)); @@ -297,7 +391,7 @@ int ObTableBatchExecuteP::multi_get() ret = OB_NOT_SUPPORTED; LOG_WARN("should have one partition", K(ret), K(part_ids)); } else if (FALSE_IT(table_service_ctx_.param_partition_id() = part_ids.at(0))) { - } else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_SELECT, table_id, part_ids, get_timeout_ts()))) { + } else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_SELECT, consistency_level, table_id, part_ids, get_timeout_ts()))) { LOG_WARN("failed to start readonly transaction", K(ret)); } else if (OB_FAIL(table_service_->multi_get(table_service_ctx_, arg_.batch_operation_, result_))) { if (OB_TRY_LOCK_ROW_CONFLICT != ret) { @@ -348,6 +442,54 @@ int ObTableBatchExecuteP::multi_delete() return ret; } +int ObTableBatchExecuteP::htable_delete() +{ + int ret = OB_SUCCESS; + const ObTableBatchOperation &batch_operation = arg_.batch_operation_; + const bool is_readonly = false; + uint64_t table_id = OB_INVALID_ID; + ObSEArray part_ids; + + if (OB_FAIL(check_arg2())) { + } else if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) { + LOG_WARN("failed to get table id", K(ret)); + } else if (OB_FAIL(get_partition_ids(table_id, part_ids))) { + LOG_WARN("failed to get part id", K(ret)); + } else if (1 != part_ids.count()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("should have one partition", K(ret), K(part_ids)); + } else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_DELETE, table_id, part_ids, get_timeout_ts()))) { + LOG_WARN("failed to start transaction", K(ret)); + } else { + int64_t affected_rows = 0; + ObHTableDeleteExecutor delete_executor(allocator_, + table_id, + part_ids.at(0), + get_timeout_ts(), + this, + table_service_, + part_service_); + ret = delete_executor.htable_delete(batch_operation, affected_rows); + if (OB_SUCC(ret)) { + ObTableOperationResult single_op_result; + single_op_result.set_entity(result_entity_); + single_op_result.set_type(ObTableOperationType::DEL); + single_op_result.set_errno(ret); + single_op_result.set_affected_rows(affected_rows); + result_.reset(); + if (OB_FAIL(result_.push_back(single_op_result))) { + LOG_WARN("failed to add result", K(ret)); + } + } + } + int tmp_ret = ret; + if (OB_FAIL(end_trans(OB_SUCCESS != ret, req_, get_timeout_ts()))) { + LOG_WARN("failed to end trans"); + } + ret = (OB_SUCCESS == tmp_ret) ? ret : tmp_ret; + return ret; +} + int ObTableBatchExecuteP::multi_insert() { int ret = OB_SUCCESS; @@ -465,6 +607,7 @@ int ObTableBatchExecuteP::batch_execute(bool is_readonly) arg_.returning_affected_entity_, arg_.returning_rowkey_); ObSEArray part_ids; + const ObTableConsistencyLevel consistency_level = arg_.consistency_level_; if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) { LOG_WARN("failed to get table id", K(ret)); } else if (OB_FAIL(get_partition_ids(table_id, part_ids))) { @@ -474,7 +617,7 @@ int ObTableBatchExecuteP::batch_execute(bool is_readonly) LOG_WARN("should have one partition", K(ret), K(part_ids)); } else if (FALSE_IT(table_service_ctx_.param_partition_id() = part_ids.at(0))) { } else if (OB_FAIL(start_trans(is_readonly, (is_readonly ? sql::stmt::T_SELECT : sql::stmt::T_UPDATE), - table_id, part_ids, get_timeout_ts()))) { + consistency_level, table_id, part_ids, get_timeout_ts()))) { LOG_WARN("failed to start transaction", K(ret)); } else if (OB_FAIL(table_service_->batch_execute(table_service_ctx_, batch_operation, result_))) { if (OB_TRY_LOCK_ROW_CONFLICT != ret) { @@ -488,3 +631,74 @@ int ObTableBatchExecuteP::batch_execute(bool is_readonly) ret = (OB_SUCCESS == tmp_ret) ? ret : tmp_ret; return ret; } + +int ObTableBatchExecuteP::htable_mutate_row() +{ + int ret = OB_SUCCESS; + const ObTableBatchOperation &batch_operation = arg_.batch_operation_; + const bool is_readonly = false; + uint64_t table_id = OB_INVALID_ID; + ObSEArray part_ids; + int64_t now_ms = -ObHTableUtils::current_time_millis(); + if (OB_FAIL(check_arg2())) { + } else if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) { + LOG_WARN("failed to get table id", K(ret)); + } else if (OB_FAIL(get_partition_ids(table_id, part_ids))) { + LOG_WARN("failed to get part id", K(ret)); + } else if (1 != part_ids.count()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("should have one partition", K(ret), K(part_ids)); + } else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_DELETE, table_id, part_ids, get_timeout_ts()))) { + LOG_WARN("failed to start transaction", K(ret)); + } else { + int64_t N = batch_operation.count(); + for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) + { + // execute each mutation one by one + const ObTableOperation &table_operation = batch_operation.at(i); + ObTableBatchOperation batch_ops; + if (OB_FAIL(batch_ops.add(table_operation))) { + LOG_WARN("failed to add", K(ret)); + break; + } + switch(table_operation.type()) { + case ObTableOperationType::INSERT_OR_UPDATE: + { + int64_t affected_rows = 0; + ObHTablePutExecutor put_executor(allocator_, + table_id, + part_ids.at(0), + get_timeout_ts(), + this, + table_service_, + part_service_); + ret = put_executor.htable_put(batch_ops, affected_rows, now_ms); + } + break; + case ObTableOperationType::DEL: + { + int64_t affected_rows = 0; + ObHTableDeleteExecutor delete_executor(allocator_, + table_id, + part_ids.at(0), + get_timeout_ts(), + this, + table_service_, + part_service_); + ret = delete_executor.htable_delete(batch_ops, affected_rows); + } + break; + default: + ret = OB_NOT_SUPPORTED; + LOG_WARN("not supported mutation type", K(ret), K(table_operation)); + break; + } // end switch + } // end for + } + int tmp_ret = ret; + if (OB_FAIL(end_trans(OB_SUCCESS != ret, req_, get_timeout_ts()))) { + LOG_WARN("failed to end trans"); + } + ret = (OB_SUCCESS == tmp_ret) ? ret : tmp_ret; + return ret; +} \ No newline at end of file diff --git a/src/observer/table/ob_table_batch_execute_processor.h b/src/observer/table/ob_table_batch_execute_processor.h index 71b216ad7d01a6defaf850366b7eaf371419493e..0590eb6489889b228fc6a11b9744476251dd415a 100644 --- a/src/observer/table/ob_table_batch_execute_processor.h +++ b/src/observer/table/ob_table_batch_execute_processor.h @@ -50,6 +50,9 @@ private: int multi_replace(); int multi_update(); int batch_execute(bool is_readonly); + int htable_delete(); + int htable_put(); + int htable_mutate_row(); private: static const int64_t COMMON_COLUMN_NUM = 16; table::ObTableEntityFactory default_entity_factory_; diff --git a/src/observer/table/ob_table_execute_processor.cpp b/src/observer/table/ob_table_execute_processor.cpp index 102a0fcccfb36bf7e93c4e8dcb46dbb4db06eb9f..a85d74c5a218bcc20b775eea2f19032eaded2f11 100644 --- a/src/observer/table/ob_table_execute_processor.cpp +++ b/src/observer/table/ob_table_execute_processor.cpp @@ -64,13 +64,18 @@ int ObTableApiExecuteP::deserialize() arg_.table_operation_.set_entity(request_entity_); result_.set_entity(result_entity_); int ret = ParentType::deserialize(); + if (OB_SUCC(ret) && ObTableEntityType::ET_HKV == arg_.entity_type_) { + // @note modify the timestamp to be negative + ret = ObTableRpcProcessorUtil::negate_htable_timestamp(request_entity_); + } return ret; } int ObTableApiExecuteP::check_arg() { int ret = OB_SUCCESS; - if (arg_.consistency_level_ != ObTableConsistencyLevel::STRONG) { + if (!(arg_.consistency_level_ == ObTableConsistencyLevel::STRONG || + arg_.consistency_level_ == ObTableConsistencyLevel::EVENTUAL)) { ret = OB_NOT_SUPPORTED; LOG_WARN("some options not supported yet", K(ret), "consistency_level", arg_.consistency_level_, @@ -207,7 +212,13 @@ int ObTableApiExecuteP::response(const int retcode) { int ret = OB_SUCCESS; if (!need_retry_in_queue_ && !did_async_end_trans()) { - ret = ObRpcProcessor::response(retcode); + if (OB_SUCC(ret) && ObTableEntityType::ET_HKV == arg_.entity_type_) { + // @note modify the value of timestamp to be positive + ret = ObTableRpcProcessorUtil::negate_htable_timestamp(result_entity_); + } + if (OB_SUCC(ret)) { + ret = ObRpcProcessor::response(retcode); + } } return ret; } @@ -255,6 +266,7 @@ int ObTableApiExecuteP::process_get() arg_.entity_type_, arg_.binlog_row_image_type_); const bool is_readonly = true; + const ObTableConsistencyLevel consistency_level = arg_.consistency_level_; ObRowkey rowkey = const_cast(arg_.table_operation_.entity()).get_rowkey(); ObSEArray part_ids; if (OB_FAIL(check_arg2())) { @@ -264,7 +276,7 @@ int ObTableApiExecuteP::process_get() LOG_WARN("failed to get partition id", K(ret)); } else if (OB_FAIL(part_ids.push_back(get_ctx_.param_partition_id()))) { LOG_WARN("failed to push back", K(ret)); - } else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_SELECT, table_id, part_ids, get_timeout_ts()))) { + } else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_SELECT, consistency_level, table_id, part_ids, get_timeout_ts()))) { LOG_WARN("failed to start readonly transaction", K(ret)); } else if (OB_FAIL(table_service_->execute_get(get_ctx_, arg_.table_operation_, result_))) { if (OB_TRY_LOCK_ROW_CONFLICT != ret) { diff --git a/src/observer/table/ob_table_query_and_mutate_processor.cpp b/src/observer/table/ob_table_query_and_mutate_processor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7bf2bb120f209b1e45966960d45ccdeeac7199ed --- /dev/null +++ b/src/observer/table/ob_table_query_and_mutate_processor.cpp @@ -0,0 +1,292 @@ +/** + * 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. + */ + +#define USING_LOG_PREFIX SERVER +#include "ob_table_query_and_mutate_processor.h" +#include "ob_table_rpc_processor_util.h" +#include "observer/ob_service.h" +#include "storage/ob_partition_service.h" +#include "ob_table_end_trans_cb.h" +#include "sql/optimizer/ob_table_location.h" // ObTableLocation +#include "lib/stat/ob_diagnose_info.h" +#include "lib/stat/ob_session_stat.h" +#include "ob_htable_utils.h" +using namespace oceanbase::observer; +using namespace oceanbase::common; +using namespace oceanbase::table; +using namespace oceanbase::share; +using namespace oceanbase::sql; + +ObTableQueryAndMutateP::ObTableQueryAndMutateP(const ObGlobalContext &gctx) + :ObTableRpcProcessor(gctx), + allocator_(ObModIds::TABLE_PROC), + query_ctx_(allocator_) +{ +} + +int ObTableQueryAndMutateP::deserialize() +{ + arg_.query_and_mutate_.set_deserialize_allocator(&allocator_); + arg_.query_and_mutate_.set_entity_factory(&default_entity_factory_); + + int ret = ParentType::deserialize(); + if (OB_SUCC(ret) && ObTableEntityType::ET_HKV == arg_.entity_type_) { + // For HKV table, modify the timestamp value to be negative + ObTableBatchOperation &mutations = arg_.query_and_mutate_.get_mutations(); + const int64_t N = mutations.count(); + for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) + { + ObITableEntity *entity = nullptr; + ObTableOperation &mutation = const_cast(mutations.at(i)); + if (OB_FAIL(mutation.get_entity(entity))) { + LOG_WARN("failed to get entity", K(ret), K(i)); + } else if (OB_FAIL(ObTableRpcProcessorUtil::negate_htable_timestamp(*entity))) { + LOG_WARN("failed to negate timestamp value", K(ret)); + } + } // end for + } + return ret; +} + +int ObTableQueryAndMutateP::check_arg() +{ + int ret = OB_SUCCESS; + ObTableQuery &query = arg_.query_and_mutate_.get_query(); + ObHTableFilter &hfilter = query.htable_filter(); + ObTableBatchOperation &mutations = arg_.query_and_mutate_.get_mutations(); + if (!query.is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid table query request", K(ret), K(query)); + } else if (!hfilter.is_valid()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("QueryAndMutate only supports hbase model table for now", K(ret)); + } else if (mutations.count() <= 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("should have at least one mutation operation", K(ret), K(mutations)); + } else { + // these options are meaningless for QueryAndMutate users but we should control them internally + query.set_batch(1); // mutate for each row + query.set_max_result_size(-1); + + hfilter.set_max_versions(1); + hfilter.set_row_offset_per_column_family(0); + hfilter.set_max_results_per_column_family(-1); + } + return ret; +} + +void ObTableQueryAndMutateP::audit_on_finish() +{ + audit_record_.consistency_level_ = ObConsistencyLevel::STRONG; // todo: exact consistency + audit_record_.return_rows_ = arg_.query_and_mutate_.return_affected_entity() ? result_.affected_entity_.get_row_count() : 0; + audit_record_.table_scan_ = true; // todo: exact judgement + audit_record_.affected_rows_ = result_.affected_rows_; + audit_record_.try_cnt_ = retry_count_ + 1; +} + +uint64_t ObTableQueryAndMutateP::get_request_checksum() +{ + uint64_t checksum = 0; + checksum = ob_crc64(checksum, arg_.table_name_.ptr(), arg_.table_name_.length()); + const uint64_t op_checksum = arg_.query_and_mutate_.get_checksum(); + checksum = ob_crc64(checksum, &op_checksum, sizeof(op_checksum)); + checksum = ob_crc64(checksum, &arg_.binlog_row_image_type_, sizeof(arg_.binlog_row_image_type_)); + return checksum; +} + +void ObTableQueryAndMutateP::reset_ctx() +{ + query_ctx_.reset_query_ctx(part_service_); + need_retry_in_queue_ = false; + one_result_.reset(); + ObTableApiProcessorBase::reset_ctx(); +} + +ObTableAPITransCb *ObTableQueryAndMutateP::new_callback(rpc::ObRequest *req) +{ + UNUSED(req); + return nullptr; +} + +int ObTableQueryAndMutateP::get_partition_ids(uint64_t table_id, ObIArray &part_ids) +{ + int ret = OB_SUCCESS; + uint64_t partition_id = arg_.partition_id_; + if (OB_INVALID_ID == partition_id) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("partitioned table not supported", K(ret), K(table_id)); + } else { + if (OB_FAIL(part_ids.push_back(partition_id))) { + LOG_WARN("failed to push back", K(ret)); + } + } + return ret; +} + +int ObTableQueryAndMutateP::try_process() +{ + int ret = OB_SUCCESS; + const ObTableQuery &query = arg_.query_and_mutate_.get_query(); + ObTableBatchOperation &mutations = arg_.query_and_mutate_.get_mutations(); + int64_t rpc_timeout = 0; + if (NULL != rpc_pkt_) { + rpc_timeout = rpc_pkt_->get_timeout(); + } + uint64_t &table_id = query_ctx_.param_table_id(); + query_ctx_.init_param(get_timeout_ts(), this, &allocator_, + false/*ignored*/, + arg_.entity_type_, + table::ObBinlogRowImageType::MINIMAL/*ignored*/); + ObSEArray part_ids; + const bool is_readonly = false; + ObTableQueryResultIterator *result_iterator = nullptr; + int32_t result_count = 0; + int64_t affected_rows = 0; + if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) { + LOG_WARN("failed to get table id", K(ret)); + } else if (OB_FAIL(get_partition_ids(table_id, part_ids))) { + LOG_WARN("failed to get part id", K(ret)); + } else if (1 != part_ids.count()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("should have one partition", K(ret), K(part_ids)); + } else if (FALSE_IT(query_ctx_.param_partition_id() = part_ids.at(0))) { + } else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_UPDATE, table_id, part_ids, + get_timeout_ts()))) { + LOG_WARN("failed to start readonly transaction", K(ret)); + } else if (OB_FAIL(table_service_->execute_query(query_ctx_, query, + one_result_, result_iterator))) { + if (OB_TRY_LOCK_ROW_CONFLICT != ret) { + LOG_WARN("failed to execute query", K(ret), K(table_id)); + } + } else { + // one_result references to result_ + ObTableQueryResult *one_result = nullptr; + // htable queryAndXXX only check one row + ret = result_iterator->get_next_result(one_result); + if (OB_ITER_END == ret || OB_SUCC(ret)) { + ret = OB_SUCCESS; + one_result = &one_result_; // empty result is OK for APPEND and INCREMENT + const ObTableOperation &mutation = mutations.at(0); + switch(mutation.type()) { + case ObTableOperationType::DEL: // checkAndDelete + stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_CHECK_AND_DELETE; + if (one_result->get_row_count() > 0) { // not empty result means check passed + affected_rows = 1; + int64_t deleted_cells = 0; + ObHTableDeleteExecutor delete_executor(allocator_, + table_id, + part_ids.at(0), + get_timeout_ts(), + this, + table_service_, + part_service_); + ret = delete_executor.htable_delete(mutations, deleted_cells); + } + break; + case ObTableOperationType::INSERT_OR_UPDATE: // checkAndPut + stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_CHECK_AND_PUT; + if (one_result->get_row_count() > 0) { // not empty result means check passed + affected_rows = 1; + int64_t put_rows = 0; + ObHTablePutExecutor put_executor(allocator_, + table_id, + part_ids.at(0), + get_timeout_ts(), + this, + table_service_, + part_service_); + ret = put_executor.htable_put(mutations, put_rows); + } + break; + case ObTableOperationType::INCREMENT: // Increment + stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_INCREMENT; + { // one_result->get_row_count() >= 0 + affected_rows = 1; + ObHTableIncrementExecutor inc_executor(ObTableOperationType::INCREMENT, + allocator_, + table_id, + part_ids.at(0), + get_timeout_ts(), + this, + table_service_, + part_service_); + int64_t put_cells = 0; + table::ObTableQueryResult *results = NULL; + if (arg_.query_and_mutate_.return_affected_entity()) { + results = &result_.affected_entity_; + } + ret = inc_executor.htable_increment(*one_result, mutations, + put_cells, results); + } + break; + case ObTableOperationType::APPEND: // Append + stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_APPEND; + { // one_result->get_row_count() >= 0 + affected_rows = 1; + ObHTableIncrementExecutor apd_executor(ObTableOperationType::APPEND, + allocator_, + table_id, + part_ids.at(0), + get_timeout_ts(), + this, + table_service_, + part_service_); + int64_t put_cells = 0; + table::ObTableQueryResult *results = NULL; + if (arg_.query_and_mutate_.return_affected_entity()) { + results = &result_.affected_entity_; + } + ret = apd_executor.htable_increment(*one_result, mutations, + put_cells, results); + } + break; + default: + ret = OB_NOT_SUPPORTED; + LOG_WARN("not supported mutation type", K(ret), "type", mutation.type()); + break; + } + } else { + LOG_WARN("failed to get one row", K(ret)); + } + + NG_TRACE_EXT(tag1, OB_ID(found_rows), result_count, + OB_ID(affected_rows), affected_rows); + } + query_ctx_.destroy_result_iterator(part_service_); + bool need_rollback_trans = (OB_SUCCESS != ret); + int tmp_ret = ret; + const bool use_sync = true; + if (OB_FAIL(end_trans(need_rollback_trans, req_, get_timeout_ts(), use_sync))) { + LOG_WARN("failed to end trans", K(ret), "rollback", need_rollback_trans); + } + ret = (OB_SUCCESS == tmp_ret) ? ret : tmp_ret; + if (OB_SUCC(ret)) { + result_.affected_rows_ = affected_rows; + } else { + result_.affected_rows_ = 0; + } + + // record events + audit_row_count_ = 1; + +#ifndef NDEBUG + // debug mode + LOG_INFO("[TABLE] execute query_and_mutate", K(ret), K_(arg), K(rpc_timeout), + K_(retry_count), K(result_count)); +#else + // release mode + LOG_TRACE("[TABLE] execute query_and_mutate", K(ret), K_(arg), + K(rpc_timeout), K_(retry_count), + "receive_ts", get_receive_timestamp(), K(result_count)); +#endif + return ret; +} diff --git a/src/observer/table/ob_table_query_and_mutate_processor.h b/src/observer/table/ob_table_query_and_mutate_processor.h new file mode 100644 index 0000000000000000000000000000000000000000..a0aeb745f468a2e75d444465e7d1b5b8e7d66346 --- /dev/null +++ b/src/observer/table/ob_table_query_and_mutate_processor.h @@ -0,0 +1,56 @@ +/** + * 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. + */ + +#ifndef _OB_TABLE_QUERY_AND_MUTATE_PROCESSOR_H +#define _OB_TABLE_QUERY_AND_MUTATE_PROCESSOR_H 1 +#include "rpc/obrpc/ob_rpc_proxy.h" +#include "rpc/obrpc/ob_rpc_processor.h" +#include "share/table/ob_table_rpc_proxy.h" +#include "ob_table_rpc_processor.h" +#include "ob_table_service.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableQueryAndMutateP: public ObTableRpcProcessor > +{ + typedef ObTableRpcProcessor > ParentType; +public: + explicit ObTableQueryAndMutateP(const ObGlobalContext &gctx); + virtual ~ObTableQueryAndMutateP() {} + + virtual int deserialize() override; +protected: + virtual int check_arg() override; + virtual int try_process() override; + virtual void reset_ctx() override; + virtual table::ObTableAPITransCb *new_callback(rpc::ObRequest *req) override; + virtual void audit_on_finish() override; + virtual uint64_t get_request_checksum() override; + +private: + int get_partition_ids(uint64_t table_id, common::ObIArray &part_ids); + int check_rowkey_and_generate_mutations( + ObTableQueryResult &one_row, + ObTableBatchOperation *&mutations); + DISALLOW_COPY_AND_ASSIGN(ObTableQueryAndMutateP); +private: + common::ObArenaAllocator allocator_; + table::ObTableEntityFactory default_entity_factory_; + ObTableServiceQueryCtx query_ctx_; + table::ObTableQueryResult one_result_; +}; +} // end namespace observer +} // end namespace oceanbase + +#endif /* _OB_TABLE_QUERY_AND_MUTATE_PROCESSOR_H */ diff --git a/src/observer/table/ob_table_query_processor.cpp b/src/observer/table/ob_table_query_processor.cpp index 7d4b88555b670efeccfb333aa57274b14c7d54ff..6f9e510c523563e1539e931ce04c98b941a140de 100644 --- a/src/observer/table/ob_table_query_processor.cpp +++ b/src/observer/table/ob_table_query_processor.cpp @@ -49,7 +49,8 @@ int ObTableQueryP::check_arg() if (!arg_.query_.is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid table query request", K(ret), "query", arg_.query_); - } else if (arg_.consistency_level_ != ObTableConsistencyLevel::STRONG) { + } else if (!(arg_.consistency_level_ == ObTableConsistencyLevel::STRONG || + arg_.consistency_level_ == ObTableConsistencyLevel::EVENTUAL)) { ret = OB_NOT_SUPPORTED; LOG_WARN("some options not supported yet", K(ret), "consistency_level", arg_.consistency_level_); @@ -121,6 +122,7 @@ int ObTableQueryP::try_process() table::ObBinlogRowImageType::MINIMAL/*ignored*/); ObSEArray part_ids; const bool is_readonly = true; + const ObTableConsistencyLevel consistency_level = arg_.consistency_level_; ObTableQueryResultIterator *result_iterator = nullptr; int32_t result_count = 0; if (OB_FAIL(get_table_id(arg_.table_name_, arg_.table_id_, table_id))) { @@ -131,7 +133,7 @@ int ObTableQueryP::try_process() ret = OB_NOT_SUPPORTED; LOG_WARN("should have one partition", K(ret), K(part_ids)); } else if (FALSE_IT(table_service_ctx_.param_partition_id() = part_ids.at(0))) { - } else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_SELECT, table_id, part_ids, timeout_ts))) { + } else if (OB_FAIL(start_trans(is_readonly, sql::stmt::T_SELECT, consistency_level, table_id, part_ids, timeout_ts))) { LOG_WARN("failed to start readonly transaction", K(ret)); } else if (OB_FAIL(table_service_->execute_query(table_service_ctx_, arg_.query_, result_, result_iterator))) { @@ -139,6 +141,19 @@ int ObTableQueryP::try_process() LOG_WARN("failed to execute query", K(ret), K(table_id)); } } else { + if (arg_.query_.get_htable_filter().is_valid()) { + // hbase model, compress the result packet + ObCompressorType compressor_type = INVALID_COMPRESSOR; + if (OB_FAIL(ObCompressorPool::get_instance().get_compressor_type( + GCONF.tableapi_transport_compress_func, compressor_type))) { + compressor_type = INVALID_COMPRESSOR; + } else if (NONE_COMPRESSOR == compressor_type) { + compressor_type = INVALID_COMPRESSOR; + } + this->set_result_compress_type(compressor_type); + ret = OB_SUCCESS; // reset ret + LOG_DEBUG("[yzfdebug] use compressor", K(compressor_type)); + } // one_result references to result_ ObTableQueryResult *one_result = nullptr; while (OB_SUCC(ret)) { @@ -182,10 +197,12 @@ int ObTableQueryP::try_process() LOG_WARN("failed to end trans", K(ret), "rollback", need_rollback_trans); } ret = (OB_SUCCESS == tmp_ret) ? ret : tmp_ret; - // record events - stat_event_type_ = ObTableProccessType::TABLE_API_TABLE_QUERY;// table query - + if (arg_.query_.get_htable_filter().is_valid()) { + stat_event_type_ = ObTableProccessType::TABLE_API_HBASE_QUERY; // hbase query + } else { + stat_event_type_ = ObTableProccessType::TABLE_API_TABLE_QUERY;// table query + } audit_row_count_ = result_row_count_; #ifndef NDEBUG diff --git a/src/observer/table/ob_table_rpc_processor.cpp b/src/observer/table/ob_table_rpc_processor.cpp index 90a5033e43b09032dc97f8ba5fa11fa74c84fb03..85ae6f46b7711f4b7b346cdd467679105ed659d3 100644 --- a/src/observer/table/ob_table_rpc_processor.cpp +++ b/src/observer/table/ob_table_rpc_processor.cpp @@ -19,6 +19,7 @@ #include "sql/session/ob_sql_session_info.h" #include "lib/stat/ob_diagnose_info.h" #include "lib/stat/ob_session_stat.h" +#include "ob_htable_utils.h" #include "sql/ob_sql.h" #include "share/table/ob_table_rpc_proxy.h" #include "ob_table_rpc_processor_util.h" @@ -241,7 +242,8 @@ ObTableApiProcessorBase::ObTableApiProcessorBase(const ObGlobalContext &gctx) request_string_len_(0), need_retry_in_queue_(false), retry_count_(0), - did_async_end_trans_(false) + did_async_end_trans_(false), + consistency_level_(ObTableConsistencyLevel::STRONG) { need_audit_ = GCONF.enable_sql_audit; } @@ -418,6 +420,23 @@ int ObTableApiProcessorBase::get_participants(uint64_t table_id, const common::O return get_participants_optimistic(table_id, part_ids, partition_leaders); } +int ObTableApiProcessorBase::start_trans(bool is_readonly, const sql::stmt::StmtType stmt_type, + const ObTableConsistencyLevel consistency_level, uint64_t table_id, + const common::ObIArray &part_ids, int64_t timeout_ts) +{ + int ret = OB_SUCCESS; + + if ((!is_readonly) && (ObTableConsistencyLevel::EVENTUAL == consistency_level)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("some options not supported yet", K(ret), K(is_readonly), K(consistency_level)); + return ret; + } + + set_consistency_level(consistency_level); + ret = start_trans(is_readonly, stmt_type, table_id, part_ids, timeout_ts); + return ret; +} + int ObTableApiProcessorBase::start_trans(bool is_readonly, const sql::stmt::StmtType stmt_type, uint64_t table_id, const common::ObIArray &part_ids, int64_t timeout_ts) { @@ -428,6 +447,13 @@ int ObTableApiProcessorBase::start_trans(bool is_readonly, const sql::stmt::Stmt } const uint64_t tenant_id = credential_.tenant_id_; const int64_t trans_timeout_ts = timeout_ts; + const int64_t trans_consistency_level = (ObTableConsistencyLevel::STRONG == consistency_level_) ? + transaction::ObTransConsistencyLevel::STRONG : + transaction::ObTransConsistencyLevel::WEAK; + const int32_t trans_consistency_type = (ObTableConsistencyLevel::STRONG == consistency_level_) ? + transaction::ObTransConsistencyType::CURRENT_READ : + transaction::ObTransConsistencyType::BOUNDED_STALENESS_READ; + // 1. start transaction if (OB_SUCC(ret)) { transaction::ObStartTransParam start_trans_param; @@ -436,11 +462,11 @@ int ObTableApiProcessorBase::start_trans(bool is_readonly, const sql::stmt::Stmt start_trans_param.set_type(transaction::ObTransType::TRANS_USER); start_trans_param.set_isolation(transaction::ObTransIsolation::READ_COMMITED); start_trans_param.set_autocommit(true); - // @todo ObTableConsistencyLevel::EVENTUAL - start_trans_param.set_consistency_type(transaction::ObTransConsistencyType::CURRENT_READ); - // By default only statement snapshot semantics, - // If need other semantics, please see ObTransConsistencyType and ObTransReadSnapshotType for reference - // ObSqlTransControl::decide_trans_read_interface_specs() decide the semantic of sql layer + // 设置事务一致性类型 + start_trans_param.set_consistency_type(trans_consistency_type); + // 默认只要求语句级别快照 + // 如果要控制其他的语义,参见ObTransConsistencyType和ObTransReadSnapshotType定义 + // SQL层在ObSqlTransControl::decide_trans_read_interface_specs()来决定语义 start_trans_param.set_read_snapshot_type(transaction::ObTransReadSnapshotType::STATEMENT_SNAPSHOT); start_trans_param.set_cluster_version(GET_MIN_CLUSTER_VERSION()); @@ -468,6 +494,7 @@ int ObTableApiProcessorBase::start_trans(bool is_readonly, const sql::stmt::Stmt if (OB_SUCC(ret)) { transaction::ObStmtDesc &stmt_desc = trans_desc_.get_cur_stmt_desc(); const bool is_sfu = false; + stmt_desc.stmt_tenant_id_ = tenant_id; stmt_desc.phy_plan_type_ = sql::OB_PHY_PLAN_LOCAL; stmt_desc.stmt_type_ = stmt_type; stmt_desc.is_sfu_ = is_sfu; @@ -475,7 +502,7 @@ int ObTableApiProcessorBase::start_trans(bool is_readonly, const sql::stmt::Stmt // optimize out stmt_desc.set_sql_id_and_save_trace_id(""); // stmt_desc.set_trans_app_trace_id_str(ObString::make_string("")); stmt_desc.inner_sql_ = false; - stmt_desc.consistency_level_ = transaction::ObTransConsistencyLevel::STRONG; + stmt_desc.consistency_level_ = trans_consistency_level; stmt_desc.is_contain_inner_table_ = false; const int64_t stmt_timeout_ts = trans_timeout_ts; const bool is_retry_sql = false; @@ -876,6 +903,7 @@ int ObTableApiProcessorBase::process_with_retry(const ObString &credential, cons template class oceanbase::observer::ObTableRpcProcessor >; template class oceanbase::observer::ObTableRpcProcessor >; template class oceanbase::observer::ObTableRpcProcessor >; +template class oceanbase::observer::ObTableRpcProcessor >; template int ObTableRpcProcessor::deserialize() @@ -989,6 +1017,580 @@ void ObTableRpcProcessor::generate_sql_id() "TABLEAPI0x%04Xvv%016lX", RpcProcessor::PCODE, checksum); } + +//////////////////////////////////////////////////////////////// +ObHTableDeleteExecutor::ObHTableDeleteExecutor(common::ObArenaAllocator &alloc, + uint64_t table_id, + uint64_t partition_id, + int64_t timeout_ts, + ObTableApiProcessorBase *processor, + ObTableService *table_service, + storage::ObPartitionService *part_service) + :table_service_(table_service), + part_service_(part_service), + query_ctx_(alloc), + mutate_ctx_(alloc) +{ + query_ctx_.param_table_id() = table_id; + query_ctx_.param_partition_id() = partition_id; + query_ctx_.init_param(timeout_ts, processor, &alloc, + false/*ignored*/, table::ObTableEntityType::ET_HKV, + table::ObBinlogRowImageType::MINIMAL/*ignored*/); + mutate_ctx_.param_table_id() = table_id; + mutate_ctx_.param_partition_id() = partition_id; + mutate_ctx_.init_param(timeout_ts, processor, &alloc, + false/*no affected rows*/, table::ObTableEntityType::ET_HKV, + table::ObBinlogRowImageType::MINIMAL/*hbase cell can use put*/); + mutations_result_.set_entity_factory(&entity_factory_); +} + +// @see https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Delete.html +int ObHTableDeleteExecutor::htable_delete(const ObTableBatchOperation &batch_operation, int64_t &affected_rows) +{ + int ret = OB_SUCCESS; + affected_rows = 0; + ObHTableFilter &htable_filter = query_.htable_filter(); + htable_filter.set_valid(true); + if (OB_FAIL(query_.add_select_column(ObHTableConstants::ROWKEY_CNAME_STR))) { + LOG_WARN("failed to add K", K(ret)); + } else if (OB_FAIL(query_.add_select_column(ObHTableConstants::CQ_CNAME_STR))) { + LOG_WARN("failed to add Q", K(ret)); + } else if (OB_FAIL(query_.add_select_column(ObHTableConstants::VERSION_CNAME_STR))) { + LOG_WARN("failed to add T", K(ret)); + } else if (OB_FAIL(query_.add_select_column(ObHTableConstants::VALUE_CNAME_STR))) { + LOG_WARN("failed to add V", K(ret)); + } else { + query_.set_batch(1); // mutate for each row + query_.set_max_result_size(-1); + } + ObObj pk_objs_start[3]; + ObObj pk_objs_end[3]; + ObNewRange range; + range.start_key_.assign(pk_objs_start, 3); + range.end_key_.assign(pk_objs_end, 3); + range.border_flag_.set_inclusive_start(); + range.border_flag_.set_inclusive_end(); + + const int64_t N = batch_operation.count(); + for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) // for each delete + { + const ObTableOperation &del_op = batch_operation.at(i); + const ObITableEntity &entity = del_op.entity(); + ObHTableCellEntity3 htable_cell(&entity); + ObString row = htable_cell.get_rowkey(); + if (htable_cell.last_get_is_null()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("K is null", K(ret), K(entity)); + break; + } + if (0 == i) { + // generate scan range by K + pk_objs_start[0].set_varbinary(row); + pk_objs_start[1].set_min_value(); + pk_objs_start[2].set_min_value(); + pk_objs_end[0].set_varbinary(row); + pk_objs_end[1].set_max_value(); + pk_objs_end[2].set_max_value(); + if (OB_FAIL(query_.add_scan_range(range))) { + LOG_WARN("failed to add range", K(ret)); + break; + } + } + htable_filter.clear_columns(); + ObString qualifier = htable_cell.get_qualifier(); + if (htable_cell.last_get_is_null()) { + // delete column family, so we need to scan all qualifier + // wildcard scan + } else if (OB_FAIL(htable_filter.add_column(qualifier))) { + LOG_WARN("failed to add column", K(ret)); + break; + } + int64_t timestamp = -htable_cell.get_timestamp(); // negative to get the original value + if (-ObHTableConstants::LATEST_TIMESTAMP == timestamp) { // INT64_MAX + // delete the most recently added cell + htable_filter.set_max_versions(1); + htable_filter.set_time_range(ObHTableConstants::INITIAL_MIN_STAMP, ObHTableConstants::INITIAL_MAX_STAMP); + } else if (timestamp > 0) { + // delete the specific version + htable_filter.set_max_versions(1); + htable_filter.set_timestamp(timestamp); + } else if (ObHTableConstants::LATEST_TIMESTAMP == timestamp) { // -INT64_MAX + // delete all version + htable_filter.set_max_versions(INT32_MAX); + htable_filter.set_time_range(ObHTableConstants::INITIAL_MIN_STAMP, ObHTableConstants::INITIAL_MAX_STAMP); + } else { + // delete all versions less than or equal to the timestamp + htable_filter.set_max_versions(INT32_MAX); + htable_filter.set_time_range(ObHTableConstants::INITIAL_MIN_STAMP, (-timestamp)+1); + } + // execute the query + ObTableQueryResultIterator *result_iterator = nullptr; + ObTableQueryResult *one_result = nullptr; + if (OB_FAIL(execute_query(query_, result_iterator))) { + } else { + ret = result_iterator->get_next_result(one_result); + if (OB_ITER_END == ret) { + // empty + ret = OB_SUCCESS; + } else if (OB_SUCCESS != ret) { + LOG_WARN("failed to query", K(ret)); + } else if (OB_ISNULL(one_result)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("one_result is NULL", K(ret)); + } else { + if (OB_FAIL(generate_delete_cells(*one_result, entity_factory_, mutations_))) { + LOG_WARN("failed to delete cells", K(ret)); + } else if (OB_FAIL(execute_mutation(mutations_, mutations_result_))) { + LOG_WARN("failed to execute mutations", K(ret)); + } else { + const int64_t result_num = mutations_result_.count(); + affected_rows += result_num; + } + } // end else + } + query_ctx_.reset_query_ctx(part_service_); + mutate_ctx_.reset_get_ctx(); + } // end for each delete op + return ret; +} + +int ObHTableDeleteExecutor::execute_query(const table::ObTableQuery &query, + ObTableQueryResultIterator *&result_iterator) +{ + int ret = OB_SUCCESS; + one_result_.reset(); + if (OB_FAIL(table_service_->execute_query(query_ctx_, query, + one_result_, result_iterator))) { + if (OB_TRY_LOCK_ROW_CONFLICT != ret) { + LOG_WARN("failed to execute query", K(ret)); + } + } + return ret; +} + +int ObHTableDeleteExecutor::generate_delete_cells( + ObTableQueryResult &one_row, + table::ObTableEntityFactory &entity_factory, + ObTableBatchOperation &mutations_out) +{ + int ret = OB_SUCCESS; + mutations_out.reset(); + entity_factory.free_and_reuse(); + one_row.rewind(); + ObObj rk, cq, ts; + ObObj key1, key2, key3; + // delete all the selected key-values + const ObITableEntity *key_value = nullptr; + while (OB_SUCC(ret) && OB_SUCC(one_row.get_next_entity(key_value))) { + // for each cell of the row + ObHTableCellEntity2 cell(key_value); + key1.set_varbinary(cell.get_rowkey()); // K + key2.set_varbinary(cell.get_qualifier()); // Q + key3.set_int(-cell.get_timestamp()); // T + ObITableEntity* new_entity = entity_factory.alloc(); + if (NULL == new_entity) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret)); + } else if (OB_FAIL(new_entity->add_rowkey_value(key1))) { + } else if (OB_FAIL(new_entity->add_rowkey_value(key2))) { + } else if (OB_FAIL(new_entity->add_rowkey_value(key3))) { + } else if (OB_FAIL(mutations_out.del(*new_entity))) { + LOG_WARN("failed to add delete operation", K(ret)); + } else { + LOG_DEBUG("[yzfdebug] delete cell", K(ret), "htable_cell", *new_entity, "kv", *key_value); + } + } // end while + if (OB_ITER_END == ret) { + ret = OB_SUCCESS; + } + return ret; +} + +int ObHTableDeleteExecutor::execute_mutation(const ObTableBatchOperation &mutations, + ObTableBatchOperationResult &mutations_result) +{ + int ret = OB_SUCCESS; + mutations_result.reset(); + if (OB_FAIL(table_service_->multi_delete(mutate_ctx_, mutations, mutations_result))) { + if (OB_TRY_LOCK_ROW_CONFLICT != ret) { + LOG_WARN("failed to multi_delete", K(ret)); + } + } + return ret; +} + +//////////////////////////////////////////////////////////////// +ObHTablePutExecutor::ObHTablePutExecutor(common::ObArenaAllocator &alloc, + uint64_t table_id, + uint64_t partition_id, + int64_t timeout_ts, + ObTableApiProcessorBase *processor, + ObTableService *table_service, + storage::ObPartitionService *part_service) + :table_service_(table_service), + part_service_(part_service), + mutate_ctx_(alloc) +{ + mutate_ctx_.param_table_id() = table_id; + mutate_ctx_.param_partition_id() = partition_id; + mutate_ctx_.init_param(timeout_ts, processor, &alloc, + false/*no affected rows*/, table::ObTableEntityType::ET_HKV, + table::ObBinlogRowImageType::MINIMAL/*hbase cell can use put*/); + + mutations_result_.set_entity_factory(&entity_factory_); +} + +int ObHTablePutExecutor::htable_put(const ObTableBatchOperation &mutations, int64_t &affected_rows, int64_t now_ms/*=0*/) +{ + int ret = OB_SUCCESS; + if (0 == now_ms) { + now_ms = -ObHTableUtils::current_time_millis(); + } + //ObString htable_row; + const int64_t N = mutations.count(); + for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) + { + const ObTableOperation &mutation = mutations.at(i); + const ObITableEntity &entity = mutation.entity(); + if (ObTableOperationType::INSERT_OR_UPDATE != mutation.type()) { // for insert_or_update only + ret = OB_INVALID_ARGUMENT; + LOG_WARN("htable put should use INSERT_OR_UPDATE", K(ret), K(mutation)); + } else if (entity.get_rowkey_size() != 3) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("htable should be with 3 rowkey columns", K(ret), K(entity)); + } else { + ObRowkey mutate_rowkey = const_cast(entity).get_rowkey(); + ObObj &hbase_timestamp = const_cast(mutate_rowkey.get_obj_ptr()[ObHTableConstants::COL_IDX_T]); // column T + ObHTableCellEntity3 htable_cell(&entity); + bool row_is_null = htable_cell.last_get_is_null(); + int64_t timestamp = htable_cell.get_timestamp(); + bool timestamp_is_null = htable_cell.last_get_is_null(); + if (row_is_null || timestamp_is_null) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument for htable put", K(ret), K(row_is_null), K(timestamp_is_null)); + } else { + // update timestamp iff LATEST_TIMESTAMP + if (ObHTableConstants::LATEST_TIMESTAMP == timestamp) { + hbase_timestamp.set_int(now_ms); + } + } + } + } // end for + if (OB_SUCC(ret)) { + // do the multi_put + mutations_result_.reset(); + affected_rows = 0; + if (OB_FAIL(table_service_->multi_insert_or_update(mutate_ctx_, mutations, mutations_result_))) { + if (OB_TRY_LOCK_ROW_CONFLICT != ret) { + LOG_WARN("failed to multi_delete", K(ret)); + } + } else { + affected_rows = 1; + } + } + return ret; +} +//////////////////////////////////////////////////////////////// +ObHTableIncrementExecutor::ObHTableIncrementExecutor(table::ObTableOperationType::Type type, + common::ObArenaAllocator &alloc, + uint64_t table_id, + uint64_t partition_id, + int64_t timeout_ts, + ObTableApiProcessorBase *processor, + ObTableService *table_service, + storage::ObPartitionService *part_service) + :type_(type), + table_service_(table_service), + part_service_(part_service), + mutate_ctx_(alloc) +{ + mutate_ctx_.param_table_id() = table_id; + mutate_ctx_.param_partition_id() = partition_id; + mutate_ctx_.init_param(timeout_ts, processor, &alloc, + false/*no affected rows*/, table::ObTableEntityType::ET_HKV, + table::ObBinlogRowImageType::MINIMAL/*hbase cell can use put*/); + mutations_result_.set_entity_factory(&entity_factory_); +} + +class ObHTableIncrementExecutor::ColumnIdxComparator +{ +public: + bool operator()(const ColumnIdx &a, const ColumnIdx &b) const + { + return a.first.compare(b.first) < 0; + } +}; + + +int ObHTableIncrementExecutor::sort_qualifier(const table::ObTableBatchOperation &increment) +{ + int ret = OB_SUCCESS; + const int64_t N = increment.count(); + if (N <= 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("empty increment", K(ret)); + } + ObString htable_row; + for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) + { + const ObTableOperation &mutation = increment.at(i); + const ObITableEntity &entity = mutation.entity(); + if (type_ != mutation.type()) { // increment or append + ret = OB_INVALID_ARGUMENT; + LOG_WARN("should use INCREMENT/APPEND", K(ret), K_(type), K(mutation)); + } else if (entity.get_rowkey_size() != 3) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("htable should be with 3 rowkey columns", K(ret), K(entity)); + } else { + ObHTableCellEntity3 htable_cell(&entity); + ObString row = htable_cell.get_rowkey(); + bool row_is_null = htable_cell.last_get_is_null(); + ObString qualifier = htable_cell.get_qualifier(); + bool qualifier_is_null = htable_cell.last_get_is_null(); + (void)htable_cell.get_timestamp(); + bool timestamp_is_null = htable_cell.last_get_is_null(); + if (row_is_null || timestamp_is_null || qualifier_is_null) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument for htable put", K(ret), + K(row_is_null), K(timestamp_is_null), K(qualifier_is_null)); + } else { + if (0 == i) { + htable_row = row; // shallow copy + } else if (htable_row != row) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("rowkey not the same", K(ret), K(row), K(htable_row)); + break; + } + if (OB_FAIL(columns_.push_back(std::make_pair(qualifier, i)))) { + LOG_WARN("failed to push back", K(ret)); + break; + } + } + } + } // end for + if (OB_SUCC(ret)) { + // sort qualifiers + ColumnIdx *end = &columns_.at(columns_.count()-1); + ++end; + std::sort(&columns_.at(0), end, ColumnIdxComparator()); + } + if (OB_SUCC(ret)) { + // check duplicated qualifiers + for (int64_t i = 0; OB_SUCCESS == ret && i < N-1; ++i) + { + if (columns_.at(i).first == columns_.at(i+1).first) { + ret = OB_ERR_PARAM_DUPLICATE; + LOG_WARN("duplicated qualifiers", K(ret), "cq", columns_.at(i).first, K(i)); + } + } // end for + } + return ret; +} + +int ObHTableIncrementExecutor::htable_increment(ObTableQueryResult &row_cells, + const table::ObTableBatchOperation &increment, + int64_t &affected_rows, + table::ObTableQueryResult *results) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(sort_qualifier(increment))) { + LOG_WARN("failed to sort qualifier", K(ret)); + } + row_cells.rewind(); + int64_t now_ms = -ObHTableUtils::current_time_millis(); + ObObj rk, cq, ts; + const ObITableEntity *get_value = nullptr; + const int64_t N = increment.count(); + for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) + { + const ObTableOperation &mutation = increment.at(columns_.at(i).second); + const ObITableEntity &kv_entity = mutation.entity(); + ObHTableCellEntity3 kv(&kv_entity); + ObString qualifier = kv.get_qualifier(); + bool need_write = false; + int64_t delta_int = 0; + ObString delta_str = kv.get_value(); + bool value_is_null = kv.last_get_is_null(); + if (value_is_null) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("increment value is invalid", K(ret), K(kv_entity)); + break; + } + + if (type_ == ObTableOperationType::INCREMENT) { + if (OB_FAIL(ObHTableUtils::java_bytes_to_int64(delta_str, delta_int))) { + LOG_WARN("failed to convert bytes to integer", K(ret), K(delta_str)); + break; + } else { + need_write = (0 != delta_int); + } + } else { // ObTableOperationType::APPEND + need_write = true; // always apply for APPEND + } + + if (nullptr == get_value) { + if (OB_FAIL(row_cells.get_next_entity(get_value))) { + if (OB_ITER_END == ret) { + get_value = nullptr; + ret = OB_SUCCESS; + } else { + LOG_WARN("failed to get next", K(ret)); + break; + } + } + } + bool first_write = false; + int64_t orig_ts = -1; + ObString orig_str; + if (nullptr != get_value) { + ObHTableCellEntity2 cell(get_value); + ObString qualifier2 = cell.get_qualifier(); + int cmp_ret = ObHTableUtils::compare_qualifier(qualifier, qualifier2); + if (0 == cmp_ret) { + // qualifier exists + orig_str = cell.get_value(); + orig_ts = cell.get_timestamp(); + if (type_ == ObTableOperationType::INCREMENT) { + int64_t orig_int = 0; + if (OB_FAIL(ObHTableUtils::java_bytes_to_int64(orig_str, orig_int))) { + LOG_WARN("failed to convert bytes to integer", K(ret), K(orig_str)); + break; + } else { + delta_int += orig_int; + } + } else { // APPEND + // nothing + } + get_value = nullptr; // next cell + } else { + // qualifier not exist, first write + first_write = true; + } + } else { + // no more cells from get + first_write = true; + } + + rk.set_varbinary(kv.get_rowkey()); // K + cq.set_varbinary(qualifier); // Q + // generate timestamp + if (orig_ts >= 0) { + // already exists + ts.set_int(std::min(-orig_ts, now_ms)); // T + } else { + int64_t new_ts = kv.get_timestamp(); + if (ObHTableConstants::LATEST_TIMESTAMP == new_ts) { + ts.set_int(now_ms); + } else { + ts.set_int(new_ts); + } + } + + // generate V + ObObj value_obj; // V + if (type_ == ObTableOperationType::INCREMENT) { + char* bytes = static_cast(allocator_.alloc(sizeof(int64_t))); + if (NULL == bytes) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret), KP(bytes)); + } else if (OB_FAIL(ObHTableUtils::int64_to_java_bytes(delta_int, bytes))) { + LOG_WARN("failed to convert bytes", K(ret), K(delta_int)); + } else { + ObString v(sizeof(int64_t), bytes); + value_obj.set_varbinary(v); + } + } else { // APPEND + if (orig_str.empty()) { + value_obj.set_varbinary(delta_str); + } else { + int32_t total_len = orig_str.length() + delta_str.length(); + char* bytes = static_cast(allocator_.alloc(total_len)); + if (NULL == bytes) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret), KP(bytes)); + } else { + MEMCPY(bytes, orig_str.ptr(), orig_str.length()); + MEMCPY(bytes+orig_str.length(), delta_str.ptr(), delta_str.length()); + ObString new_str(total_len, bytes); + value_obj.set_varbinary(new_str); + } + } + } + + // generate entity + ObITableEntity* new_entity = nullptr; + if (OB_FAIL(ret)) { + } else if (nullptr == (new_entity = entity_factory_.alloc())) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("no memory", K(ret), KP(new_entity)); + } else { + if (OB_FAIL(new_entity->add_rowkey_value(rk))) { + } else if (OB_FAIL(new_entity->add_rowkey_value(cq))) { + } else if (OB_FAIL(new_entity->add_rowkey_value(ts))) { + } else if (OB_FAIL(new_entity->set_property(ObHTableConstants::VALUE_CNAME_STR, value_obj))) { + } + } + + if (OB_SUCC(ret) && (need_write || first_write)) { + if (OB_FAIL(mutations_.insert_or_update(*new_entity))) { + LOG_WARN("failed to add put operation", K(ret)); + } else { + LOG_DEBUG("[yzfdebug] put cell", K(ret), "new_cell", *new_entity, "kv", kv); + } + } // end if need_write + if (OB_SUCC(ret) && NULL != results) { + // Add to results to get returned to the Client. If null, cilent does not want results. + ret = add_to_results(*results, rk, cq, ts, value_obj); + } + } // end for + if (OB_SUCC(ret) && mutations_.count() > 0) { + // do the multi_put + mutations_result_.reset(); + affected_rows = 0; + if (OB_FAIL(table_service_->multi_insert_or_update(mutate_ctx_, mutations_, mutations_result_))) { + if (OB_TRY_LOCK_ROW_CONFLICT != ret) { + LOG_WARN("failed to multi_delete", K(ret)); + } + } else { + affected_rows = 1; + } + } + return ret; +} + +int ObHTableIncrementExecutor::add_to_results(table::ObTableQueryResult &results, + const ObObj &rk, const ObObj &cq, + const ObObj &ts, const ObObj &value) +{ + int ret = OB_SUCCESS; + if (results.get_property_count() <= 0) { + if (OB_FAIL(results.add_property_name(ObHTableConstants::ROWKEY_CNAME_STR))) { + LOG_WARN("failed to copy name", K(ret)); + } else if (OB_FAIL(results.add_property_name(ObHTableConstants::CQ_CNAME_STR))) { + LOG_WARN("failed to copy name", K(ret)); + } else if (OB_FAIL(results.add_property_name(ObHTableConstants::VERSION_CNAME_STR))) { + LOG_WARN("failed to copy name", K(ret)); + } else if (OB_FAIL(results.add_property_name(ObHTableConstants::VALUE_CNAME_STR))) { + LOG_WARN("failed to copy name", K(ret)); + } + } + if (OB_SUCC(ret)) { + ObObj objs[4]; + objs[0] = rk; + objs[1] = cq; + objs[2] = ts; + int64_t timestamp = 0; + objs[2].get_int(timestamp); + objs[2].set_int(-timestamp); // negate_htable_timestamp + objs[3] = value; + common::ObNewRow row(objs, 4); + if (OB_FAIL(results.add_row(row))) { // deep copy + LOG_WARN("failed to add row to results", K(ret), K(row)); + } + } + return ret; +} + bool oceanbase::observer::is_bad_routing_err(const int err) { // bad routing check : whether client should refresh location cache diff --git a/src/observer/table/ob_table_rpc_processor.h b/src/observer/table/ob_table_rpc_processor.h index 0120f0857d3a5bc9369dfb5c91bbab2483e26f6d..89c256fee189d194272cd1ce6f893538f1305efa 100644 --- a/src/observer/table/ob_table_rpc_processor.h +++ b/src/observer/table/ob_table_rpc_processor.h @@ -20,6 +20,7 @@ #include "sql/optimizer/ob_table_location.h" // ObTableLocation #include "ob_table_service.h" #include "sql/monitor/ob_exec_stat.h" +#include "share/table/ob_table.h" namespace oceanbase { namespace table @@ -28,6 +29,8 @@ class ObTableAPITransCb; } // end namespace table namespace observer { +using namespace oceanbase::table; + class ObGlobalContext; class ObTableService; @@ -124,7 +127,10 @@ public: public: static int init_session(); int check_user_access(const ObString &credential_str); - //@{ transaction control + // transaction control + int start_trans(bool is_readonly, const sql::stmt::StmtType stmt_type, + const ObTableConsistencyLevel consistency_level, uint64_t table_id, + const common::ObIArray &part_ids, int64_t timeout_ts); int start_trans(bool is_readonly, const sql::stmt::StmtType stmt_type, uint64_t table_id, const common::ObIArray &part_ids, int64_t timeout_ts); int end_trans(bool is_rollback, rpc::ObRequest *req, int64_t timeout_ts, bool use_sync = false); @@ -151,6 +157,10 @@ protected: virtual void save_request_string() = 0; virtual void generate_sql_id() = 0; + // set trans consistency level + void set_consistency_level(const ObTableConsistencyLevel consistency_level) { consistency_level_ = consistency_level; } + ObTableConsistencyLevel consistency_level() const { return consistency_level_; } + private: int get_participants(uint64_t table_id, const common::ObIArray &part_ids, common::ObPartitionLeaderArray &partition_leaders); @@ -189,6 +199,7 @@ private: //when start_participants executed in the leader replica transaction::ObPartitionEpochArray part_epoch_list_; bool did_async_end_trans_; + ObTableConsistencyLevel consistency_level_; }; template @@ -214,6 +225,104 @@ protected: }; +class ObHTableDeleteExecutor final +{ +public: + ObHTableDeleteExecutor(common::ObArenaAllocator &alloc, + uint64_t table_id, + uint64_t partition_id, + int64_t timeout_ts, + ObTableApiProcessorBase *processor, + ObTableService *table_service, + storage::ObPartitionService *part_service); + ~ObHTableDeleteExecutor() {} + // @param affected_rows [out] deleted number of htable cells + int htable_delete(const table::ObTableBatchOperation &delete_op, int64_t &affected_rows); +private: + int execute_query(const table::ObTableQuery &query, + table::ObTableQueryResultIterator *&result_iterator); + int generate_delete_cells( + table::ObTableQueryResult &one_row, + table::ObTableEntityFactory &entity_factory, + table::ObTableBatchOperation &mutations_out); + int execute_mutation(const table::ObTableBatchOperation &mutations, + table::ObTableBatchOperationResult &mutations_result); +private: + ObTableService *table_service_; + storage::ObPartitionService *part_service_; + ObTableServiceQueryCtx query_ctx_; + table::ObTableQuery query_; + table::ObTableQueryResult one_result_; + table::ObTableEntityFactory entity_factory_; + table::ObTableBatchOperation mutations_; + table::ObTableBatchOperationResult mutations_result_; + ObTableServiceGetCtx mutate_ctx_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(ObHTableDeleteExecutor); +}; + +class ObHTablePutExecutor final +{ +public: + ObHTablePutExecutor(common::ObArenaAllocator &alloc, + uint64_t table_id, + uint64_t partition_id, + int64_t timeout_ts, + ObTableApiProcessorBase *processor, + ObTableService *table_service, + storage::ObPartitionService *part_service); + ~ObHTablePutExecutor() {} + + int htable_put(const ObTableBatchOperation &put_op, int64_t &affected_rows, int64_t now_ms = 0); +private: + ObTableService *table_service_; + storage::ObPartitionService *part_service_; + table::ObTableEntityFactory entity_factory_; + table::ObTableBatchOperationResult mutations_result_; + ObTableServiceGetCtx mutate_ctx_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(ObHTablePutExecutor); +}; + +// executor of Increment and Append +class ObHTableIncrementExecutor final +{ +public: + ObHTableIncrementExecutor(table::ObTableOperationType::Type type, + common::ObArenaAllocator &alloc, + uint64_t table_id, + uint64_t partition_id, + int64_t timeout_ts, + ObTableApiProcessorBase *processor, + ObTableService *table_service, + storage::ObPartitionService *part_service); + ~ObHTableIncrementExecutor() {} + + int htable_increment(ObTableQueryResult &row_cells, + const table::ObTableBatchOperation &increment_op, + int64_t &affected_rows, + table::ObTableQueryResult *results); +private: + typedef std::pair ColumnIdx; + class ColumnIdxComparator; + int sort_qualifier(const table::ObTableBatchOperation &increment); + int execute_mutation(const table::ObTableBatchOperation &mutations, + table::ObTableBatchOperationResult &mutations_result); + static int add_to_results(table::ObTableQueryResult &results, const ObObj &rk, const ObObj &cq, + const ObObj &ts, const ObObj &value); +private: + table::ObTableOperationType::Type type_; + ObTableService *table_service_; + storage::ObPartitionService *part_service_; + table::ObTableEntityFactory entity_factory_; + table::ObTableBatchOperation mutations_; + table::ObTableBatchOperationResult mutations_result_; + ObTableServiceGetCtx mutate_ctx_; + common::ObSEArray columns_; + common::ObArenaAllocator allocator_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(ObHTableIncrementExecutor); +}; template int64_t ObTableRpcProcessor::get_timeout_ts() const diff --git a/src/observer/table/ob_table_rpc_processor_util.h b/src/observer/table/ob_table_rpc_processor_util.h index 685607b1582415dea82f7a0909270e94bbe308d1..680ee90b78f9e4cfffc1c23a75a0f82291b04577 100644 --- a/src/observer/table/ob_table_rpc_processor_util.h +++ b/src/observer/table/ob_table_rpc_processor_util.h @@ -45,6 +45,15 @@ enum ObTableProccessType TABLE_API_BATCH_RETRIVE, TABLE_API_BATCH_HYBRID, + // hbase mutate + TABLE_API_HBASE_DELETE, + TABLE_API_HBASE_PUT, + TABLE_API_HBASE_CHECK_AND_DELETE, + TABLE_API_HBASE_CHECK_AND_PUT, + TABLE_API_HBASE_INCREMENT, + TABLE_API_HBASE_APPEND, + TABLE_API_HBASE_HYBRID, + // query TABLE_API_TABLE_QUERY, TABLE_API_HBASE_QUERY, @@ -171,6 +180,49 @@ public: EVENT_ADD(TABLEAPI_BATCH_HYBRID_INSERT_OR_UPDATE_ROW, rows); // @todo row count for each type SET_AUDIT_SQL_STRING(batch_hybrid); break; + // hbase mutate + case ObTableProccessType::TABLE_API_HBASE_DELETE: + EVENT_INC(HBASEAPI_DELETE_COUNT); + EVENT_ADD(HBASEAPI_DELETE_TIME, elapsed_us); + EVENT_ADD(HBASEAPI_DELETE_ROW, rows); + SET_AUDIT_SQL_STRING(hbase_delete); + break; + case ObTableProccessType::TABLE_API_HBASE_PUT: + EVENT_INC(HBASEAPI_PUT_COUNT); + EVENT_ADD(HBASEAPI_PUT_TIME, elapsed_us); + EVENT_ADD(HBASEAPI_PUT_ROW, rows); + SET_AUDIT_SQL_STRING(hbase_put); + break; + case ObTableProccessType::TABLE_API_HBASE_CHECK_AND_DELETE: + EVENT_INC(HBASEAPI_CHECK_DELETE_COUNT); + EVENT_ADD(HBASEAPI_CHECK_DELETE_TIME, elapsed_us); + EVENT_ADD(HBASEAPI_CHECK_DELETE_ROW, rows); + SET_AUDIT_SQL_STRING(hbase_check_and_delete); + break; + case ObTableProccessType::TABLE_API_HBASE_CHECK_AND_PUT: + EVENT_INC(HBASEAPI_CHECK_PUT_COUNT); + EVENT_ADD(HBASEAPI_CHECK_PUT_TIME, elapsed_us); + EVENT_ADD(HBASEAPI_CHECK_PUT_ROW, rows); + SET_AUDIT_SQL_STRING(hbase_check_and_put); + break; + case ObTableProccessType::TABLE_API_HBASE_INCREMENT: + EVENT_INC(HBASEAPI_INCREMENT_COUNT); + EVENT_ADD(HBASEAPI_INCREMENT_TIME, elapsed_us); + EVENT_ADD(HBASEAPI_INCREMENT_ROW, rows); + SET_AUDIT_SQL_STRING(hbase_increment); + break; + case ObTableProccessType::TABLE_API_HBASE_APPEND: + EVENT_INC(HBASEAPI_APPEND_COUNT); + EVENT_ADD(HBASEAPI_APPEND_TIME, elapsed_us); + EVENT_ADD(HBASEAPI_APPEND_ROW, rows); + SET_AUDIT_SQL_STRING(hbase_append); + break; + case ObTableProccessType::TABLE_API_HBASE_HYBRID: + EVENT_INC(HBASEAPI_HYBRID_COUNT); + EVENT_ADD(HBASEAPI_HYBRID_TIME, elapsed_us); + EVENT_ADD(HBASEAPI_HYBRID_ROW, rows); + SET_AUDIT_SQL_STRING(hbase_hybrid); + break; // table query case ObTableProccessType::TABLE_API_TABLE_QUERY: EVENT_INC(TABLEAPI_QUERY_COUNT); @@ -178,6 +230,13 @@ public: EVENT_ADD(TABLEAPI_QUERY_ROW, rows); SET_AUDIT_SQL_STRING(table_query); break; + // hbase query + case ObTableProccessType::TABLE_API_HBASE_QUERY: + EVENT_INC(HBASEAPI_SCAN_COUNT); + EVENT_ADD(HBASEAPI_SCAN_TIME, elapsed_us); + EVENT_ADD(HBASEAPI_SCAN_ROW, rows); + SET_AUDIT_SQL_STRING(hbase_scan); + break; default: SET_AUDIT_SQL_STRING(unknown); diff --git a/src/observer/table/ob_table_service.cpp b/src/observer/table/ob_table_service.cpp index c3bb450a4ec5d9abfaa813cd8b47f97f7c75c972..355828418cc5cdef65ae03c7e4cdd35c51808ef9 100644 --- a/src/observer/table/ob_table_service.cpp +++ b/src/observer/table/ob_table_service.cpp @@ -19,6 +19,7 @@ #include "sql/engine/expr/ob_expr_res_type.h" #include "sql/resolver/expr/ob_raw_expr_util.h" #include "lib/thread_local/ob_tsi_factory.h" +#include "ob_htable_filter_operator.h" #include "sql/engine/expr/ob_expr_add.h" using namespace oceanbase::observer; using namespace oceanbase::common; @@ -199,12 +200,15 @@ int ObTableService::check_column_type(const ObExprResType &column_type, ObObj &o return ret; } -int ObTableService::insert_or_update_can_use_put(uint64_t table_id, const ObITableEntity &entity, bool &use_put) +int ObTableService::insert_or_update_can_use_put(ObTableEntityType entity_type, uint64_t table_id, const ObITableEntity &entity, bool &use_put) { int ret = OB_SUCCESS; schema::ObSchemaGetterGuard schema_guard; const schema::ObTableSchema *table_schema = NULL; - if (OB_FAIL(schema_service_->get_schema_guard(schema_guard))) { + if (ObTableEntityType::ET_HKV == entity_type) { + // hbase model table does not have secondary index and always specify all the properties (column V) + use_put = true; + } else if (OB_FAIL(schema_service_->get_schema_guard(schema_guard))) { LOG_WARN("failed to get schema guard", K(ret)); } else if (OB_FAIL(schema_guard.get_table_schema(table_id, table_schema))) { LOG_WARN("get table schema failed", K(table_id), K(ret)); @@ -252,7 +256,7 @@ int ObTableService::execute_insert_or_update(ObTableServiceGetCtx &ctx, const Ob int ret = OB_SUCCESS; const ObITableEntity &entity = table_operation.entity(); bool can_use_put = true; - if (OB_FAIL(insert_or_update_can_use_put(ctx.param_.table_id_, entity, can_use_put))) { + if (OB_FAIL(insert_or_update_can_use_put(ctx.param_.entity_type_, ctx.param_.table_id_, entity, can_use_put))) { LOG_WARN("failed to check", K(ret)); } else if (can_use_put && ctx.param_.binlog_row_image_type_ != ObBinlogRowImageType::FULL) { @@ -386,7 +390,8 @@ int ObTableService::multi_insert_or_update(ObTableServiceGetCtx &ctx, int ret = OB_SUCCESS; const ObTableOperation &one_op = batch_operation.at(0); bool can_use_put = true; - if (OB_FAIL(insert_or_update_can_use_put(ctx.param_.table_id_, one_op.entity(), can_use_put))) { + if (OB_FAIL(insert_or_update_can_use_put(ctx.param_.entity_type_, + ctx.param_.table_id_, one_op.entity(), can_use_put))) { LOG_WARN("failed to check", K(ret)); } else if (can_use_put && ctx.param_.binlog_row_image_type_ != ObBinlogRowImageType::FULL) { @@ -744,12 +749,15 @@ int ObTableService::add_index_columns_if_missing(schema::ObSchemaGetterGuard &sc return ret; } -int ObTableService::delete_can_use_put(uint64_t table_id, bool &use_put) +int ObTableService::delete_can_use_put(table::ObTableEntityType entity_type, uint64_t table_id, bool &use_put) { int ret = OB_SUCCESS; schema::ObSchemaGetterGuard schema_guard; const schema::ObTableSchema *table_schema = NULL; - if (OB_FAIL(schema_service_->get_schema_guard(schema_guard))) { + if (entity_type == ObTableEntityType::ET_HKV) { + // hbase model table does not have secondary index + use_put = true; + } else if (OB_FAIL(schema_service_->get_schema_guard(schema_guard))) { LOG_WARN("failed to get schema guard", K(ret)); } else if (OB_FAIL(schema_guard.get_table_schema(table_id, table_schema))) { LOG_WARN("get table schema failed", K(table_id), K(ret)); @@ -1725,7 +1733,8 @@ int ObTableService::fill_query_table_param(uint64_t table_id, common::ObIArray &rowkey_columns_type, int64_t &schema_version, uint64_t &index_id, - int64_t &padding_num) + int64_t &padding_num, + table::ObHColumnDescriptor *hcolumn_desc) { int ret = OB_SUCCESS; schema::ObSchemaGetterGuard schema_guard; @@ -1754,8 +1763,16 @@ int ObTableService::fill_query_table_param(uint64_t table_id, } else if (OB_FAIL(table_param.convert(*table_schema, ((NULL == index_schema) ? *table_schema: *index_schema), output_column_ids, index_back))) { LOG_WARN("failed to convert table param", K(ret)); - } else { - //do nothing + } else if (!table_schema->get_comment_str().empty() + && NULL != hcolumn_desc) { + if (OB_FAIL(hcolumn_desc->from_string(table_schema->get_comment_str()))) { + LOG_WARN("failed to parse hcolumn_desc from comment string", K(ret), + "comment", table_schema->get_comment_str()); + } else { + LOG_DEBUG("[yzfdebug] get ttl", K(table_id), + "comment", table_schema->get_comment_str(), + "ttl", hcolumn_desc->get_time_to_live()); + } } } return ret; @@ -1986,12 +2003,28 @@ ObNormalTableQueryResultIterator *ObTableServiceQueryCtx::get_normal_result_iter return normal_result_iterator_; } +ObHTableFilterOperator *ObTableServiceQueryCtx::get_htable_result_iterator( + const ObTableQuery &query, table::ObTableQueryResult &one_result) +{ + if (NULL == htable_result_iterator_) { + htable_result_iterator_ = OB_NEWx(ObHTableFilterOperator, param_.allocator_, query, one_result); + if (NULL == htable_result_iterator_) { + LOG_WARN("failed to allocate htable filter"); + } + } + return htable_result_iterator_; +} + void ObTableServiceQueryCtx::destroy_result_iterator(storage::ObPartitionService *part_service) { if (NULL != normal_result_iterator_) { normal_result_iterator_->~ObNormalTableQueryResultIterator(); normal_result_iterator_ = NULL; } + if (NULL != htable_result_iterator_) { + htable_result_iterator_->~ObHTableFilterOperator(); + htable_result_iterator_ = NULL; + } if (NULL != scan_result_) { if (NULL == part_service) { LOG_ERROR("part_service is NULL, memory leak"); @@ -2002,6 +2035,43 @@ void ObTableServiceQueryCtx::destroy_result_iterator(storage::ObPartitionService } } +int ObTableService::check_htable_query_args(const ObTableQuery &query) +{ + int ret = OB_SUCCESS; + const ObIArray &select_columns = query.get_select_columns(); + int64_t N = select_columns.count(); + if (N != 4) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("TableQuery with htable_filter should select 4 columns", K(ret), K(N)); + } + if (OB_SUCC(ret)) { + if (ObHTableConstants::ROWKEY_CNAME_STR != select_columns.at(0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("TableQuery with htable_filter should select K as the first column", K(ret), K(select_columns)); + } else if (ObHTableConstants::CQ_CNAME_STR != select_columns.at(1)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("TableQuery with htable_filter should select Q as the second column", K(ret), K(select_columns)); + } else if (ObHTableConstants::VERSION_CNAME_STR != select_columns.at(2)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("TableQuery with htable_filter should select T as the third column", K(ret), K(select_columns)); + } else if (ObHTableConstants::VALUE_CNAME_STR != select_columns.at(3)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("TableQuery with htable_filter should select V as the fourth column", K(ret), K(select_columns)); + } + } + if (OB_SUCC(ret)) { + if (0 != query.get_offset() + || -1 != query.get_limit()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("htable scan should not set Offset and Limit", K(ret), K(query)); + } else if (ObQueryFlag::Forward != query.get_scan_order() && ObQueryFlag::Reverse != query.get_scan_order()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("TableQuery with htable_filter only support forward and reverse scan yet", K(ret)); + } + } + return ret; +} + int ObTableService::execute_query(ObTableServiceQueryCtx &ctx, const ObTableQuery &query, table::ObTableQueryResult &one_result, table::ObTableQueryResultIterator *&query_result) @@ -2014,16 +2084,33 @@ int ObTableService::execute_query(ObTableServiceQueryCtx &ctx, const ObTableQuer uint64_t index_id = OB_INVALID_ID; int64_t padding_num = 0; - if (NULL == (query_result = ctx.get_normal_result_iterator(query, one_result))) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("failed to allocate result iterator", K(ret)); + ObHColumnDescriptor hcolumn_desc; + ObHColumnDescriptor *p_hcolumn_desc = NULL; + if (query.get_htable_filter().is_valid()) { + if (OB_FAIL(check_htable_query_args(query))) { + LOG_WARN("invalid query request", K(ret)); + } else if (NULL == (query_result = ctx.get_htable_result_iterator(query, one_result))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate htable result iterator", K(ret)); + } else if (OB_FAIL(ctx.htable_result_iterator_->parse_filter_string(ctx.param_.allocator_))) { + LOG_WARN("failed to parse htable filter string", K(ret)); + } else { + p_hcolumn_desc = &hcolumn_desc; + } + } else { + if (NULL == (query_result = ctx.get_normal_result_iterator(query, one_result))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate result iterator", K(ret)); + } } + if (OB_FAIL(ret)) { } else if (OB_FAIL(fill_query_table_param(table_id, query.get_select_columns(), query.get_index_name(), *(ctx.table_param_), output_column_ids, ctx.columns_type_, schema_version, - index_id, padding_num))) { // @todo optimize, table_param_ can be cached + index_id, padding_num, + p_hcolumn_desc))) { // @todo optimize, table_param_ can be cached LOG_WARN("failed to fill param", K(ret)); } else if (OB_FAIL(fill_query_scan_ranges(ctx, query, (table_id != index_id) ? padding_num : -1, @@ -2038,7 +2125,14 @@ int ObTableService::execute_query(ObTableServiceQueryCtx &ctx, const ObTableQuer LOG_WARN("fail to scan table", K(ret)); } } else { - ctx.normal_result_iterator_->set_scan_result(ctx.scan_result_); + if (query.get_htable_filter().is_valid()) { + ctx.htable_result_iterator_->set_scan_result(ctx.scan_result_); + if (p_hcolumn_desc->get_time_to_live() > 0) { + ctx.htable_result_iterator_->set_ttl(p_hcolumn_desc->get_time_to_live()); + } + } else { + ctx.normal_result_iterator_->set_scan_result(ctx.scan_result_); + } } return ret; } diff --git a/src/observer/table/ob_table_service.h b/src/observer/table/ob_table_service.h index 48973d182592fffa86c273682683b39e3c1177de..d932580801fc63c46d26f8d15e5f4ec0a5e0924c 100644 --- a/src/observer/table/ob_table_service.h +++ b/src/observer/table/ob_table_service.h @@ -20,6 +20,11 @@ #include "share/schema/ob_table_param.h" namespace oceanbase { +namespace table +{ +class ObHTableFilterOperator; +class ObHColumnDescriptor; +} // end namespace table namespace storage { class ObPartitionService; @@ -151,10 +156,12 @@ struct ObTableServiceQueryCtx: public ObTableServiceGetCtx { public: ObNormalTableQueryResultIterator *normal_result_iterator_; + table::ObHTableFilterOperator *htable_result_iterator_; public: ObTableServiceQueryCtx(common::ObArenaAllocator &alloc) :ObTableServiceGetCtx(alloc), - normal_result_iterator_(NULL) + normal_result_iterator_(NULL), + htable_result_iterator_(NULL) {} void reset_query_ctx(storage::ObPartitionService *part_service) { @@ -163,6 +170,8 @@ public: } ObNormalTableQueryResultIterator *get_normal_result_iterator(const ObTableQuery &query, table::ObTableQueryResult &one_result); + table::ObHTableFilterOperator *get_htable_result_iterator(const ObTableQuery &query, + table::ObTableQueryResult &one_result); void destroy_result_iterator(storage::ObPartitionService *part_service); }; @@ -215,7 +224,7 @@ private: common::ObIArray &column_ids, common::ObIArray *columns_type); - int insert_or_update_can_use_put(uint64_t table_id, const table::ObITableEntity &entity, bool &use_put); + int insert_or_update_can_use_put(table::ObTableEntityType entity_type, uint64_t table_id, const table::ObITableEntity &entity, bool &use_put); int add_one_result(ObTableBatchOperationResult &result, table::ObTableOperationType::Type op_type, int32_t error_code, @@ -242,7 +251,7 @@ private: const ObTableBatchOperation &batch_operation, ObTableApiRowIterator *scan_result, ObTableBatchOperationResult &result); - int delete_can_use_put(uint64_t table_id, bool &use_put); + int delete_can_use_put(table::ObTableEntityType entity_type, uint64_t table_id, bool &use_put); static int cons_all_index_properties(share::schema::ObSchemaGetterGuard &schema_guard, const share::schema::ObTableSchema &table_schema, common::ObIArray &column_ids, @@ -282,7 +291,8 @@ private: common::ObIArray &rowkey_columns_type, int64_t &schema_version, uint64_t &index_id, - int64_t &padding_num); + int64_t &padding_num, + table::ObHColumnDescriptor *hcolumn_desc); int fill_query_scan_ranges(ObTableServiceCtx &ctx, const ObTableQuery &query, int64_t padding_num, @@ -295,6 +305,7 @@ private: int32_t limit, int32_t offset, storage::ObTableScanParam &scan_param); + int check_htable_query_args(const ObTableQuery &query); private: int fill_new_entity( bool returning_rowkey, diff --git a/src/share/table/ob_table.cpp b/src/share/table/ob_table.cpp index 82f834dfe40565efe0d571d76078bb7c1102684f..80c398cd6d9057cc5b2bf28399860e96a50816f4 100644 --- a/src/share/table/ob_table.cpp +++ b/src/share/table/ob_table.cpp @@ -904,6 +904,7 @@ void ObTableQuery::reset() index_name_.reset(); batch_size_ = -1; max_result_size_ = -1; + htable_filter_.reset(); } bool ObTableQuery::is_valid() const @@ -1021,6 +1022,10 @@ uint64_t ObTableQuery::get_checksum() const checksum = ob_crc64(checksum, index_name_.ptr(), index_name_.length()); checksum = ob_crc64(checksum, &batch_size_, sizeof(batch_size_)); checksum = ob_crc64(checksum, &max_result_size_, sizeof(max_result_size_)); + if (htable_filter_.is_valid()) { + const uint64_t htable_filter_checksum = htable_filter_.get_checksum(); + checksum = ob_crc64(checksum, &htable_filter_checksum, sizeof(htable_filter_checksum)); + } return checksum; } @@ -1033,7 +1038,8 @@ OB_UNIS_DEF_SERIALIZE(ObTableQuery, scan_order_, index_name_, batch_size_, - max_result_size_); + max_result_size_, + htable_filter_); OB_UNIS_DEF_SERIALIZE_SIZE(ObTableQuery, key_ranges_, @@ -1044,7 +1050,8 @@ OB_UNIS_DEF_SERIALIZE_SIZE(ObTableQuery, scan_order_, index_name_, batch_size_, - max_result_size_); + max_result_size_, + htable_filter_); OB_DEF_DESERIALIZE(ObTableQuery,) { @@ -1085,7 +1092,8 @@ OB_DEF_DESERIALIZE(ObTableQuery,) scan_order_, index_name_, batch_size_, - max_result_size_ + max_result_size_, + htable_filter_ ); } return ret; @@ -1095,6 +1103,144 @@ OB_DEF_DESERIALIZE(ObTableQuery,) ObTableEntityIterator::~ObTableEntityIterator() {} +//////////////////////////////////////////////////////////////// +const char* const ObHTableConstants::ROWKEY_CNAME = "K"; +const char* const ObHTableConstants::CQ_CNAME = "Q"; +const char* const ObHTableConstants::VERSION_CNAME = "T"; +const char* const ObHTableConstants::VALUE_CNAME = "V"; + +const ObString ObHTableConstants::ROWKEY_CNAME_STR = ObString::make_string(ROWKEY_CNAME); +const ObString ObHTableConstants::CQ_CNAME_STR = ObString::make_string(CQ_CNAME); +const ObString ObHTableConstants::VERSION_CNAME_STR = ObString::make_string(VERSION_CNAME); +const ObString ObHTableConstants::VALUE_CNAME_STR = ObString::make_string(VALUE_CNAME); + +ObHTableFilter::ObHTableFilter() + :is_valid_(false), + select_column_qualifier_(), + min_stamp_(ObHTableConstants::INITIAL_MIN_STAMP), + max_stamp_(ObHTableConstants::INITIAL_MAX_STAMP), + max_versions_(1), + limit_per_row_per_cf_(-1), + offset_per_row_per_cf_(0), + filter_string_() +{} + +void ObHTableFilter::reset() +{ + is_valid_ = false; + select_column_qualifier_.reset(); + min_stamp_ = ObHTableConstants::INITIAL_MIN_STAMP; + max_stamp_ = ObHTableConstants::INITIAL_MAX_STAMP; + max_versions_ = 1; + limit_per_row_per_cf_ = -1; + offset_per_row_per_cf_ = 0; + filter_string_.reset(); + +} + +int ObHTableFilter::add_column(const ObString &qualifier) +{ + int ret = OB_SUCCESS; + const int64_t N = select_column_qualifier_.count(); + for (int64_t i = 0; OB_SUCCESS == ret && i < N; ++i) + { + if (0 == select_column_qualifier_.at(i).case_compare(qualifier)) { + ret = OB_ERR_COLUMN_DUPLICATE; + LOG_WARN("column already exists", K(ret), K(qualifier)); + break; + } + } // end for + if (OB_SUCC(ret)) { + if (OB_FAIL(select_column_qualifier_.push_back(qualifier))) { + LOG_WARN("failed to push back", K(ret)); + } + } + return ret; +} + +int ObHTableFilter::set_time_range(int64_t min_stamp, int64_t max_stamp) +{ + int ret = OB_SUCCESS; + if (min_stamp >= max_stamp || min_stamp_ < 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid time range", K(ret), K(min_stamp), K(max_stamp)); + } else { + min_stamp_ = min_stamp; + max_stamp_ = max_stamp; + } + return ret; +} + +int ObHTableFilter::set_max_versions(int32_t versions) +{ + int ret = OB_SUCCESS; + if (versions <= 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid max versions", K(ret), K(versions)); + } else { + max_versions_ = versions; + } + return ret; +} + +int ObHTableFilter::set_max_results_per_column_family(int32_t limit) +{ + int ret = OB_SUCCESS; + if (limit < -1 || 0 == limit) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("limit cannot be negative or zero", K(ret), K(limit)); + } else { + limit_per_row_per_cf_ = limit; + } + return ret; +} + +int ObHTableFilter::set_row_offset_per_column_family(int32_t offset) +{ + int ret = OB_SUCCESS; + if (offset < 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("offset cannot be negative", K(ret), K(offset)); + } else { + offset_per_row_per_cf_ = offset; + } + return ret; +} + +int ObHTableFilter::set_filter(const ObString &filter) +{ + filter_string_ = filter; + return OB_SUCCESS; +} + +uint64_t ObHTableFilter::get_checksum() const +{ + uint64_t checksum = 0; + for (int64_t i = 0; i < select_column_qualifier_.count(); ++i) { + const ObString &cur_qualifier = select_column_qualifier_.at(i); + checksum = ob_crc64(checksum, cur_qualifier.ptr(), cur_qualifier.length()); + } + checksum = ob_crc64(checksum, &min_stamp_, sizeof(min_stamp_)); + checksum = ob_crc64(checksum, &max_stamp_, sizeof(max_stamp_)); + checksum = ob_crc64(checksum, &max_versions_, sizeof(max_versions_)); + checksum = ob_crc64(checksum, &limit_per_row_per_cf_, sizeof(limit_per_row_per_cf_)); + checksum = ob_crc64(checksum, &offset_per_row_per_cf_, sizeof(offset_per_row_per_cf_)); + checksum = ob_crc64(checksum, filter_string_.ptr(), filter_string_.length()); + return checksum; +} + +// If valid_ is true, serialize the members. Otherwise, nothing/dummy is serialized. +OB_SERIALIZE_MEMBER_IF(ObHTableFilter, + (true == is_valid_), + is_valid_, + select_column_qualifier_, + min_stamp_, + max_stamp_, + max_versions_, + limit_per_row_per_cf_, + offset_per_row_per_cf_, + filter_string_); + //////////////////////////////////////////////////////////////// ObTableQueryResult::ObTableQueryResult() :row_count_(0), @@ -1379,3 +1525,24 @@ OB_DEF_DESERIALIZE(ObTableQueryResult) } return ret; } + +//////////////////////////////////////////////////////////////// +uint64_t ObTableQueryAndMutate::get_checksum() +{ + uint64_t checksum = 0; + const uint64_t query_checksum = query_.get_checksum(); + const uint64_t mutation_checksum = mutations_.get_checksum(); + checksum = ob_crc64(checksum, &query_checksum, sizeof(query_checksum)); + checksum = ob_crc64(checksum, &mutation_checksum, sizeof(mutation_checksum)); + checksum = ob_crc64(checksum, &return_affected_entity_, sizeof(return_affected_entity_)); + return checksum; +} + +OB_SERIALIZE_MEMBER(ObTableQueryAndMutate, + query_, + mutations_); + +OB_SERIALIZE_MEMBER(ObTableQueryAndMutateResult, + affected_rows_, + affected_entity_); + diff --git a/src/share/table/ob_table.h b/src/share/table/ob_table.h index a98a144a7b0f1c2a7f86b4652013ee1091af0cea..6fa3840d3eb585efcbc8f4b4043495fcc655332c 100644 --- a/src/share/table/ob_table.h +++ b/src/share/table/ob_table.h @@ -131,7 +131,8 @@ private: enum class ObTableEntityType { ET_DYNAMIC = 0, - ET_KV = 1 + ET_KV = 1, + ET_HKV = 2 }; // @note not thread-safe @@ -517,6 +518,94 @@ private: common::ObIAllocator *alloc_; }; +class ObHTableConstants +{ +public: + static constexpr int64_t LATEST_TIMESTAMP = -INT64_MAX; + static constexpr int64_t OLDEST_TIMESTAMP = INT64_MAX; + static constexpr int64_t INITIAL_MIN_STAMP = 0; + static constexpr int64_t INITIAL_MAX_STAMP = INT64_MAX; + + static const char* const ROWKEY_CNAME; + static const char* const CQ_CNAME; + static const char* const VERSION_CNAME; + static const char* const VALUE_CNAME; + static const ObString ROWKEY_CNAME_STR; + static const ObString CQ_CNAME_STR; + static const ObString VERSION_CNAME_STR; + static const ObString VALUE_CNAME_STR; + + // create table t1$cf1 (K varbinary(1024), Q varchar(256), T bigint, V varbinary(1024), primary key(K, Q, T)); + static const int64_t COL_IDX_K = 0; + static const int64_t COL_IDX_Q = 1; + static const int64_t COL_IDX_T = 2; + static const int64_t COL_IDX_V = 3; +private: + ObHTableConstants() = delete; +}; + +/// special filter for HTable +class ObHTableFilter final +{ + OB_UNIS_VERSION(1); +public: + ObHTableFilter(); + ~ObHTableFilter() = default; + void reset(); + void set_valid(bool valid) { is_valid_ = valid; } + bool is_valid() const { return is_valid_; } + + /// Get the column with the specified qualifier. + int add_column(const ObString &qualifier); + /// Get versions of columns with the specified timestamp. + int set_timestamp(int64_t timestamp) { min_stamp_ = timestamp; max_stamp_ = timestamp + 1; return common::OB_SUCCESS; } + /// Get versions of columns only within the specified timestamp range, [minStamp, maxStamp). + int set_time_range(int64_t min_stamp, int64_t max_stamp); + /// Get up to the specified number of versions of each column. + int set_max_versions(int32_t versions); + /// Set the maximum number of values to return per row per Column Family + /// @param limit - the maximum number of values returned / row / CF + int set_max_results_per_column_family(int32_t limit); + /// Set offset for the row per Column Family. + /// @param offset - is the number of kvs that will be skipped. + int set_row_offset_per_column_family(int32_t offset); + /// Apply the specified server-side filter when performing the Query. + /// @param filter - a file string using the hbase filter language + /// @see the filter language at https://issues.apache.org/jira/browse/HBASE-4176 + int set_filter(const ObString &filter); + + const ObIArray &get_columns() const { return select_column_qualifier_; } + bool with_latest_timestamp() const { return with_all_time() && 1 == max_versions_; } + bool with_timestamp() const { return min_stamp_ == max_stamp_ && min_stamp_ >= 0; } + bool with_all_time() const { return ObHTableConstants::INITIAL_MIN_STAMP == min_stamp_ && ObHTableConstants::INITIAL_MAX_STAMP == max_stamp_; } + int64_t get_min_stamp() const { return min_stamp_; } + int64_t get_max_stamp() const { return max_stamp_; } + int32_t get_max_versions() const { return max_versions_; } + int32_t get_max_results_per_column_family() const { return limit_per_row_per_cf_; } + int32_t get_row_offset_per_column_family() const { return offset_per_row_per_cf_; } + const ObString &get_filter() const { return filter_string_; } + void clear_columns() { select_column_qualifier_.reset(); } + uint64_t get_checksum() const; + + TO_STRING_KV(K_(is_valid), + "column_qualifier", select_column_qualifier_, + K_(min_stamp), + K_(max_stamp), + K_(max_versions), + K_(limit_per_row_per_cf), + K_(offset_per_row_per_cf), + K_(filter_string)); +private: + bool is_valid_; + ObSEArray select_column_qualifier_; + int64_t min_stamp_; // default -1 + int64_t max_stamp_; // default -1 + int32_t max_versions_; // default 1 + int32_t limit_per_row_per_cf_; // default -1 means unlimited + int32_t offset_per_row_per_cf_; // default 0 + ObString filter_string_; +}; + /// A table query /// 1. support multi range scan /// 2. support reverse scan @@ -535,7 +624,8 @@ public: scan_order_(common::ObQueryFlag::Forward), index_name_(), batch_size_(-1), - max_result_size_(-1) + max_result_size_(-1), + htable_filter_() {} ~ObTableQuery() = default; void reset(); @@ -556,6 +646,8 @@ public: int set_offset(int32_t offset); /// Add filter, currently NOT supported. int set_filter(const ObString &filter); + /// Add filter only for htable. + ObHTableFilter& htable_filter() { return htable_filter_; } /// Set max row count of each batch. /// For htable, set the maximum number of cells to return for each call to next(). int set_batch(int32_t batch_size); @@ -570,6 +662,7 @@ public: int32_t get_offset() const { return offset_; } common::ObQueryFlag::ScanOrder get_scan_order() const { return scan_order_; } const ObString &get_index_name() const { return index_name_; } + const ObHTableFilter& get_htable_filter() const { return htable_filter_; } int32_t get_batch() const { return batch_size_; } int64_t get_max_result_size() const { return max_result_size_; } int64_t get_range_count() const { return key_ranges_.count(); } @@ -584,6 +677,7 @@ public: K_(offset), K_(scan_order), K_(index_name), + K_(htable_filter), K_(batch_size), K_(max_result_size)); public: @@ -601,6 +695,7 @@ private: ObString index_name_; int32_t batch_size_; int64_t max_result_size_; + ObHTableFilter htable_filter_; }; /// result for ObTableQuery @@ -616,6 +711,42 @@ public: virtual int get_next_entity(const ObITableEntity *&entity) = 0; }; +/// query and mutate the selected rows. +class ObTableQueryAndMutate final +{ + OB_UNIS_VERSION(1); +public: + ObTableQueryAndMutate() + :return_affected_entity_(true) + {} + const ObTableQuery &get_query() const { return query_; } + ObTableQuery &get_query() { return query_; } + const ObTableBatchOperation &get_mutations() const { return mutations_; } + ObTableBatchOperation &get_mutations() { return mutations_; } + bool return_affected_entity() const { return return_affected_entity_; } + + void set_deserialize_allocator(common::ObIAllocator *allocator); + void set_entity_factory(ObITableEntityFactory *entity_factory); + uint64_t get_checksum(); + + TO_STRING_KV(K_(query), + K_(mutations)); +private: + ObTableQuery query_; + ObTableBatchOperation mutations_; + bool return_affected_entity_; +}; + +inline void ObTableQueryAndMutate::set_deserialize_allocator(common::ObIAllocator *allocator) +{ + query_.set_deserialize_allocator(allocator); +} + +inline void ObTableQueryAndMutate::set_entity_factory(ObITableEntityFactory *entity_factory) +{ + mutations_.set_entity_factory(entity_factory); +} + class ObTableQueryResult: public ObTableEntityIterator { OB_UNIS_VERSION(1); @@ -651,6 +782,20 @@ private: ObTableEntity curr_entity_; }; +class ObTableQueryAndMutateResult final +{ + OB_UNIS_VERSION(1); +public: + TO_STRING_KV(K_(affected_rows)); +public: + int64_t affected_rows_; + // If return_affected_entity_ in ObTableQueryAndMutate is set, then return the respond entity. + // In the case of delete and insert_or_update, return the old rows before modified. + // In the case of increment and append, return the new rows after modified. + ObTableQueryResult affected_entity_; +}; + + } // end namespace table } // end namespace oceanbase diff --git a/src/share/table/ob_table_rpc_proxy.h b/src/share/table/ob_table_rpc_proxy.h index 3d67f8ef051056674be94ab181f1d2dc3363c117..2cdfce5419b9dbda33cc37f2900e255b2a8f28db 100644 --- a/src/share/table/ob_table_rpc_proxy.h +++ b/src/share/table/ob_table_rpc_proxy.h @@ -29,6 +29,7 @@ public: RPC_S(PR5 execute, obrpc::OB_TABLE_API_EXECUTE, (table::ObTableOperationRequest), table::ObTableOperationResult); RPC_S(PR5 batch_execute, obrpc::OB_TABLE_API_BATCH_EXECUTE, (table::ObTableBatchOperationRequest), table::ObTableBatchOperationResult); RPC_SS(PR5 execute_query, obrpc::OB_TABLE_API_EXECUTE_QUERY, (table::ObTableQueryRequest), table::ObTableQueryResult); + RPC_S(PR5 query_and_mutate, obrpc::OB_TABLE_API_QUERY_AND_MUTATE, (table::ObTableQueryAndMutateRequest), table::ObTableQueryAndMutateResult); }; }; // end namespace obrpc diff --git a/src/share/table/ob_table_rpc_struct.cpp b/src/share/table/ob_table_rpc_struct.cpp index e9b2530e785c7b8775920ccbf50443fb691ccd2c..04895e12a20a1154857b97eebfeaf8f3e833bc96 100644 --- a/src/share/table/ob_table_rpc_struct.cpp +++ b/src/share/table/ob_table_rpc_struct.cpp @@ -76,3 +76,12 @@ OB_SERIALIZE_MEMBER(ObTableQueryRequest, consistency_level_, query_ ); + +//////////////////////////////////////////////////////////////// +OB_SERIALIZE_MEMBER(ObTableQueryAndMutateRequest, + credential_, + table_name_, + table_id_, + partition_id_, + entity_type_, + query_and_mutate_); \ No newline at end of file diff --git a/src/share/table/ob_table_rpc_struct.h b/src/share/table/ob_table_rpc_struct.h index 2257002d483dcab3b7ac148c0a5f86340607cbc9..eebaa7a919ce279e7cfe67ab81e54457ab4f4102 100644 --- a/src/share/table/ob_table_rpc_struct.h +++ b/src/share/table/ob_table_rpc_struct.h @@ -215,6 +215,31 @@ public: virtual bool has_more_result() const = 0; }; +class ObTableQueryAndMutateRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableQueryAndMutateRequest() + :table_id_(common::OB_INVALID_ID), + partition_id_(common::OB_INVALID_ID), + binlog_row_image_type_(ObBinlogRowImageType::FULL) + {} + TO_STRING_KV("credential", common::ObHexStringWrap(credential_), + K_(table_name), + K_(table_id), + K_(partition_id), + K_(entity_type), + K_(query_and_mutate)); +public: + ObString credential_; + ObString table_name_; + uint64_t table_id_; // for optimize purpose + /// partition id. Set it to gain better performance. If unknown, set it to be OB_INVALID_ID + uint64_t partition_id_; // for optimize purpose + ObTableEntityType entity_type_; // for optimize purpose + ObTableQueryAndMutate query_and_mutate_; + ObBinlogRowImageType binlog_row_image_type_; +}; } // end namespace table } // end namespace oceanbase diff --git a/unittest/observer/CMakeLists.txt b/unittest/observer/CMakeLists.txt index c4c20d6de7a2f6be5a0dc515e08b8d17a8011194..59bf829952b3ea85833e143e31bad73f75794bd1 100644 --- a/unittest/observer/CMakeLists.txt +++ b/unittest/observer/CMakeLists.txt @@ -5,3 +5,4 @@ ob_unittest(test_worker_pool omt/test_worker_pool.cpp) ob_unittest(test_token_calcer omt/test_token_calcer.cpp) ob_unittest(test_information_schema) ob_unittest(test_tableapi tableapi/test_tableapi.cpp) +ob_unittest(test_hbaseapi hbaseapi/test_hfilter_parser.cpp) diff --git a/unittest/observer/hbaseapi/test_hfilter_parser.cpp b/unittest/observer/hbaseapi/test_hfilter_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74f5e8c87e68857c423236053cd0a57dcf516f97 --- /dev/null +++ b/unittest/observer/hbaseapi/test_hfilter_parser.cpp @@ -0,0 +1,148 @@ +/** + * (C) 2010-2018 Alibaba Group Holding Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * Version: $Id$ + * + * test_hfilter_parser.cpp + * + * Authors: + * Zhifeng YANG + * + */ +#include "observer/table/ob_htable_filter_parser.h" +#include "observer/table/ob_htable_filters.h" +#include +#include "lib/utility/ob_test_util.h" +#include "lib/json/ob_json_print_utils.h" // for SJ +#include +using namespace oceanbase::common; +using namespace oceanbase::table; + +class TestHFilterParser: public ::testing::Test +{ +public: + TestHFilterParser(); + virtual ~TestHFilterParser(); + virtual void SetUp(); + virtual void TearDown(); +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(TestHFilterParser); +protected: + // function members + void do_parse(const char *filter_cstr, std::ofstream &of_result, int64_t expect_error); + bool is_prefix_equal(const char* tmp_file, const char* result_file); + void is_equal_content(const char* tmp_file, const char* result_file); +}; + +TestHFilterParser::TestHFilterParser() +{ +} + +TestHFilterParser::~TestHFilterParser() +{ +} + +void TestHFilterParser::SetUp() +{ +} + +void TestHFilterParser::TearDown() +{ +} + +bool TestHFilterParser::is_prefix_equal(const char* tmp_file, const char* result_file) +{ + std::ifstream if_test(tmp_file); + if_test.is_open(); + EXPECT_EQ(true, if_test.is_open()); + std::istream_iterator it_test(if_test); + std::ifstream if_expected(result_file); + if_expected.is_open(); + EXPECT_EQ(true, if_expected.is_open()); + std::istream_iterator it_expected(if_expected); + return std::equal(it_test, std::istream_iterator(), it_expected); +} + +void TestHFilterParser::is_equal_content(const char* tmp_file, const char* result_file) +{ + bool is_equal = is_prefix_equal(tmp_file, result_file) & is_prefix_equal(result_file, tmp_file); + _OB_LOG(WARN, "result file is %s, expect file is %s, is_equal:%d", tmp_file, result_file, is_equal); + if (is_equal) { + std::remove(tmp_file); + } else { + fprintf(stdout, "The result files mismatched, you can choose to\n"); + fprintf(stdout, "diff -u %s %s\n", tmp_file, result_file); + } + EXPECT_EQ(true, is_equal); +} + +void TestHFilterParser::do_parse(const char *filter_cstr, std::ofstream &of_result, int64_t expect_error) +{ + ObArenaAllocator allocator; + ObHTableFilterParser parser; + ASSERT_EQ(OB_SUCCESS, parser.init(&allocator)); + ObString filter_string = ObString::make_string(filter_cstr); + int ret = OB_SUCCESS; + _OB_LOG(INFO, "FILTER: >>>%.*s<<<", filter_string.length(), filter_string.ptr()); + hfilter::Filter *filter = NULL; + ret = parser.parse_filter(filter_string, filter); + if (OB_FAIL(ret)) { + _OB_LOG(WARN, "failed to parse filter. msg=%s [%d.%d-%d.%d]", parser.error_msg_, + parser.first_line_, parser.first_column_, parser.last_line_, parser.last_column_); + } + ASSERT_EQ(expect_error, -ret); + if (NULL != filter){ + of_result << SJ(*filter) << std::endl; + } + parser.destroy(); +} + +TEST_F(TestHFilterParser, basic_test) +{ + const char* test_file = "./hfilter_parser.test"; + const char* result_file = "./hfilter_parser.result"; + const char* tmp_file = "./hfilter_parser.tmp"; + // run tests + std::ifstream if_tests(test_file); + ASSERT_TRUE(if_tests.is_open()); + std::ofstream of_result(tmp_file); + ASSERT_TRUE(of_result.is_open()); + std::string line; + int64_t case_id = 0; + int64_t expect_error = 0; + char *w = NULL; + char *p = NULL; + UNUSED(w); + while (std::getline(if_tests, line)) { + if (line.size() <= 0) continue; + if (line.at(0) == '#') continue; + if (strncmp(line.c_str(), "--error", strlen("--error")) == 0) { + p = const_cast(line.c_str()); + w = strsep(&p, " "); + expect_error = atol(p); + continue; + } + of_result << "************** Case "<< ++case_id << " ***************" << std::endl; + of_result << line << std::endl; + ASSERT_NO_FATAL_FAILURE(do_parse(line.c_str(), of_result, expect_error)); + if (expect_error != 0) { + expect_error = 0; + } + } + of_result.close(); + // verify results + is_equal_content(tmp_file, result_file); +} + +int main(int argc, char **argv) +{ + OB_LOGGER.set_log_level("INFO"); + OB_LOGGER.set_file_name("test_hfilter_parser.log", true); + ::testing::InitGoogleTest(&argc,argv); + return RUN_ALL_TESTS(); +}