[CP] support join join on on [4_2_x_release -> master]

This commit is contained in:
jingtaoye35
2024-07-25 07:28:34 +00:00
committed by ob-robot
parent 26ce6ec537
commit 1b99b3e406
4 changed files with 178 additions and 109 deletions

View File

@ -825,3 +825,27 @@ extern bool nodename_is_sdo_geometry_type(const ParseNode *node)
} }
return result; return result;
} }
ParseNode *adjust_inner_join_inner(int *error_code, ParseNode *inner_join, ParseNode *table_node)
{
ParseNode *ret_node = NULL;
if (OB_ISNULL(error_code)) {
(void)fprintf(stderr, "ERROR parser error code is NULL\n");
} else if (OB_ISNULL(inner_join) || OB_ISNULL(table_node)) {
*error_code = OB_PARSER_ERR_UNEXPECTED;
} else if (table_node->type_ == T_JOINED_TABLE && table_node->value_ != 1) {
// table_node is a join table and without a parenthese.
table_node->children_[1] = adjust_inner_join_inner(error_code, inner_join, table_node->children_[1]);
if (OB_PARSER_SUCCESS != *error_code) {
/* do nothing */
} else if (OB_ISNULL(table_node->children_[1])) {
*error_code = OB_PARSER_ERR_UNEXPECTED;
} else {
ret_node = table_node;
}
} else {
inner_join->children_[2] = table_node;
ret_node = inner_join;
}
return ret_node;
}

View File

@ -412,6 +412,7 @@ extern bool parsenode_equal(const ParseNode *node1, const ParseNode *node2, int
extern int64_t get_question_mark(ObQuestionMarkCtx *ctx, void *malloc_pool, const char *name); extern int64_t get_question_mark(ObQuestionMarkCtx *ctx, void *malloc_pool, const char *name);
extern int64_t get_question_mark_by_defined_name(ObQuestionMarkCtx *ctx, const char *name); extern int64_t get_question_mark_by_defined_name(ObQuestionMarkCtx *ctx, const char *name);
extern ParseNode *adjust_inner_join_inner(int *error_code, ParseNode *inner_join, ParseNode *table_node);
// compare ParseNode str_value_ to pattern // compare ParseNode str_value_ to pattern
// @param [in] node ParseNode // @param [in] node ParseNode

View File

@ -1211,4 +1211,35 @@ do {\
}\ }\
} while(0);\ } while(0);\
#define adjust_inner_join(result, ret_node, inner_join, table_node) \
do { \
ret_node = NULL; \
if (OB_ISNULL(inner_join) || OB_ISNULL(table_node)) { \
result->extra_errno_ = OB_PARSER_ERR_UNEXPECTED; \
yyerror(NULL, result, "inner join or table_node is NULL ptr\n"); \
YYABORT; \
} else if (T_JOINED_TABLE != inner_join->type_ || \
OB_ISNULL(inner_join->children_[0]) || \
OB_ISNULL(inner_join->children_[1]) || \
OB_NOT_NULL(inner_join->children_[2]) || \
OB_NOT_NULL(inner_join->children_[3]) || \
OB_NOT_NULL(inner_join->children_[4]) || \
!(T_JOIN_INNER == inner_join->children_[0]->type_ || \
T_STRAIGHT_JOIN == inner_join->children_[0]->type_)) { \
result->extra_errno_ = OB_PARSER_ERR_UNEXPECTED; \
yyerror(NULL, result, "inner join ptr is unexpected\n"); \
YYABORT; \
} else { \
ret_node = adjust_inner_join_inner(&result->extra_errno_, inner_join, table_node); \
if (OB_PARSER_SUCCESS != result->extra_errno_) { \
yyerror(NULL, result, "failde to adjust inner join inside\n"); \
YYABORT; \
} else if (OB_ISNULL(ret_node)) { \
result->extra_errno_ = OB_PARSER_ERR_UNEXPECTED; \
yyerror(NULL, result, "got null ret_node\n"); \
YYABORT; \
} \
} \
} while (0); \
#endif /* OCEANBASE_SRC_SQL_PARSER_SQL_PARSER_BASE_H_ */ #endif /* OCEANBASE_SRC_SQL_PARSER_SQL_PARSER_BASE_H_ */

View File

@ -101,49 +101,47 @@ extern void obsql_oracle_parse_fatal_error(int32_t errcode, yyscan_t yyscanner,
%nonassoc BASIC OUTLINE EXTENDED EXTENDED_NOADDR PARTITIONS PLANREGRESS %nonassoc BASIC OUTLINE EXTENDED EXTENDED_NOADDR PARTITIONS PLANREGRESS
%nonassoc PRETTY PRETTY_COLOR %nonassoc PRETTY PRETTY_COLOR
%nonassoc KILL_EXPR %nonassoc KILL_EXPR
%nonassoc CONNECTION QUERY %nonassoc CONNECTION QUERY
%nonassoc LOWER_COMMA %nonassoc LOWER_COMMA
%nonassoc REMAP %nonassoc REMAP
%nonassoc ',' WITH %nonassoc ',' WITH
%nonassoc OVERWRITE %nonassoc OVERWRITE
%left UNION EXCEPT MINUS %left UNION EXCEPT MINUS
%left INTERSECT %left INTERSECT
%left JOIN CROSS LEFT FULL RIGHT INNER WINDOW %left LOWER_ON /*on expr*/
%left SET_VAR %left JOIN CROSS LEFT FULL RIGHT INNER WINDOW ON USING OUTER NATURAL STRAIGHT_JOIN
%left SET_VAR
%left OR OR_OP %left OR OR_OP
%left XOR %left XOR
%left AND AND_OP %left AND AND_OP
%left BETWEEN CASE WHEN THEN ELSE %left BETWEEN CASE WHEN THEN ELSE
%nonassoc LOWER_THAN_COMP %nonassoc LOWER_THAN_COMP
%left COMP_EQ COM P_NSEQ COMP_GE COMP_GT COMP_LE COMP_LT COMP_NE IS LIKE IN REGEXP SOUNDS %left COMP_EQ COM P_NSEQ COMP_GE COMP_GT COMP_LE COMP_LT COMP_NE IS LIKE IN REGEXP SOUNDS
%nonassoc STRING_VALUE %nonassoc STRING_VALUE
%right ESCAPE /*for conflict for escape*/ %right ESCAPE /*for conflict for escape*/
%left '|' %left '|'
%left '&' %left '&'
%left SHIFT_LEFT SHIFT_RIGHT %left SHIFT_LEFT SHIFT_RIGHT
%left JSON_EXTRACT JSON_EXTRACT_UNQUOTED MEMBER %left JSON_EXTRACT JSON_EXTRACT_UNQUOTED MEMBER
%left '+' '-' %left '+' '-'
%left '*' '/' '%' MOD DIV POW %left '*' '/' '%' MOD DIV POW
%left '^' %left '^'
%nonassoc LOWER_THAN_NEG SAMPLE/* for simple_expr conflict*/ %nonassoc LOWER_THAN_NEG SAMPLE/* for simple_expr conflict*/
%left CNNOP %left CNNOP
%left NEG '~' %left NEG '~'
%nonassoc LOWER_PARENS %nonassoc LOWER_PARENS
//%nonassoc STRING_VALUE %left '(' ')'
%left '(' ')'
%nonassoc SQL_CACHE SQL_NO_CACHE HIGH_PRIORITY SQL_SMALL_RESULT SQL_BIG_RESULT SQL_BUFFER_RESULT CHARSET DATABASE_ID REPLICA_NUM/*for shift/reduce conflict between opt_query_expresion_option_list and SQL_CACHE*/ %nonassoc SQL_CACHE SQL_NO_CACHE HIGH_PRIORITY SQL_SMALL_RESULT SQL_BIG_RESULT SQL_BUFFER_RESULT CHARSET DATABASE_ID REPLICA_NUM/*for shift/reduce conflict between opt_query_expresion_option_list and SQL_CACHE*/
%nonassoc LOW_PRIORITY QUICK %nonassoc LOW_PRIORITY QUICK
%nonassoc HIGHER_PARENS TRANSACTION SIZE AUTO SKEWONLY DEFAULT AS/*for simple_expr conflict*/ %nonassoc HIGHER_PARENS TRANSACTION SIZE AUTO SKEWONLY DEFAULT AS/*for simple_expr conflict*/
%nonassoc TENANT /*for opt_tenant conflict*/ %nonassoc TENANT /*for opt_tenant conflict*/
%left '.' %left '.'
%right NOT NOT2 %right NOT NOT2
%right BINARY COLLATE %right BINARY COLLATE
%left INTERVAL %left INTERVAL
%nonassoc LOWER_KEY /* for unique key and unique and key*/ %nonassoc LOWER_KEY /* for unique key and unique and key*/
%nonassoc KEY /* for unique key and unique and key*/ %nonassoc KEY /* for unique key and unique and key*/
%nonassoc LOWER_ON /*on expr*/
%nonassoc ON /*on expr*/
%nonassoc LOWER_OVER %nonassoc LOWER_OVER
%nonassoc OVER %nonassoc OVER
%nonassoc LOWER_INTO %nonassoc LOWER_INTO
@ -434,7 +432,7 @@ END_P SET_VAR DELIMITER
%type <node> intnum_list %type <node> intnum_list
%type <node> qb_name_option qb_name_string qb_name_list multi_qb_name_list %type <node> qb_name_option qb_name_string qb_name_list multi_qb_name_list
%type <node> coalesce_strategy_list %type <node> coalesce_strategy_list
%type <node> join_condition inner_join_type opt_inner outer_join_type opt_outer natural_join_type except_full_outer_join_type opt_full_table_factor %type <node> join_condition inner_join_type except_full_outer_join_type opt_outer natural_join_type opt_full_table_factor
%type <ival> string_length_i opt_string_length_i opt_string_length_i_v2 opt_int_length_i opt_bit_length_i opt_datetime_fsp_i opt_unsigned_i opt_zerofill_i opt_year_i opt_time_func_fsp_i opt_cast_float_precision %type <ival> string_length_i opt_string_length_i opt_string_length_i_v2 opt_int_length_i opt_bit_length_i opt_datetime_fsp_i opt_unsigned_i opt_zerofill_i opt_year_i opt_time_func_fsp_i opt_cast_float_precision
%type <node> opt_float_precision opt_number_precision %type <node> opt_float_precision opt_number_precision
%type <node> opt_equal_mark opt_default_mark read_only_or_write not not2 opt_disk_alias %type <node> opt_equal_mark opt_default_mark read_only_or_write not not2 opt_disk_alias
@ -12007,6 +12005,39 @@ table_factor
{ {
$$ = $3; $$ = $3;
} }
| table_reference FULL %prec LOWER_ON
{
/* to resolve FULL as alias comflict */
if ($1->type_ == T_ORG) {
ParseNode *name_node = NULL;
make_name_node(name_node, result->malloc_pool_, "full");
$$ = new_node(result->malloc_pool_, T_ALIAS, $1->num_child_ + 1);
if (OB_UNLIKELY($$ == NULL)) {
yyerror(NULL, result, "No more space for malloc\n");
YYABORT_NO_MEMORY;
} else {
for (int i = 0; i <= $1->num_child_; ++i) {
if (i == 0) {
$$->children_[i] = $1->children_[i];
} else if (i == 1) {
$$->children_[i] = name_node;
} else {
$$->children_[i] = $1->children_[i - 1];
}
}
$$->sql_str_off_ = @1.first_column;
}
} else if ($1->type_ == T_ALIAS && $1->children_[1] != NULL &&
strlen($1->children_[1]->str_value_) == 0) {
ParseNode *name_node = NULL;
make_name_node(name_node, result->malloc_pool_, "full");
$1->children_[1] = name_node;
$$ = $1;
} else {
yyerror(&@2, result, "occur multi alias name\n");
YYERROR;
}
}
; ;
table_factor: table_factor:
@ -12053,14 +12084,15 @@ tbl_name
unname_node->sql_str_off_ = @2.first_column; unname_node->sql_str_off_ = @2.first_column;
$$->value_ = 1; //lateral $$->value_ = 1; //lateral
} }
| '(' table_references ')'
{
$$ = $2;
}
| json_table_expr | json_table_expr
{ {
$$ = $1; $$ = $1;
} }
| '(' table_references ')'
{
$$ = $2;
$$->value_ = 1; // value_ = 1 means with parentheses
}
; ;
tbl_name: tbl_name:
@ -13025,79 +13057,77 @@ joined_table:
/** /**
* ref: https://dev.mysql.com/doc/refman/8.0/en/join.html * ref: https://dev.mysql.com/doc/refman/8.0/en/join.html
*/ */
table_reference inner_join_type opt_full_table_factor %prec LOWER_ON table_reference inner_join_type table_reference %prec LOWER_ON
{ {
JOIN_MERGE_NODES($1, $3); JOIN_MERGE_NODES($1, $3);
malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $2, $1, $3, NULL, NULL); if ($3->value_ == 1) {
// $3 has parenthese, theere is no need to adjust
malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $2, $1, $3, NULL, NULL);
} else {
ParseNode *inner_join = NULL;
malloc_non_terminal_node(inner_join, result->malloc_pool_, T_JOINED_TABLE, 5, $2, $1, NULL, NULL, NULL);
adjust_inner_join(result, $$, inner_join, $3);
}
/*
consider following case: t1 join t2 join t3 on 1=1;
1. t1 join (t2 join t3 on 1 = 1);
2. (t1 join t2) join t3 on 1 = 1;
3. t1 join (t2 join t3) on 1 = 1;
the number 2 is what the query meaning, inner join should join from left to right even without a
join_condition. So multi inner join should be parsed as a left-deep true;
It reduces t2 join t3 on 1=1 firstly.
join_1
/ \
t2 t3
Then it reduces t1, which adds a new join on join_1. So the finial tree is a right-deep joined_tree.
join_2
/ \
t1 join_1
/ \
t2 t3
However, this isn't the meaning of query, which actually should be a left-deep tree:
join_1
/ \
join_2 t3
/ \
t1 t2
Then I adjust the right-deep tree to a left-deep tree, this is the actual meaning of the query.
*/
} }
| table_reference inner_join_type opt_full_table_factor ON expr | table_reference inner_join_type table_reference join_condition
{
JOIN_MERGE_NODES($1, $3);
malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $2, $1, $3, $5, NULL);
}
| table_reference inner_join_type opt_full_table_factor USING '(' column_list ')'
{
JOIN_MERGE_NODES($1, $3);
ParseNode *condition_node = NULL;
merge_nodes(condition_node, result, T_COLUMN_LIST, $6);
malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $2, $1, $3, condition_node, NULL);
}
| table_reference except_full_outer_join_type opt_full_table_factor join_condition
{ {
JOIN_MERGE_NODES($1, $3); JOIN_MERGE_NODES($1, $3);
malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $2, $1, $3, $4, NULL); malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $2, $1, $3, $4, NULL);
} }
| table_reference FULL JOIN opt_full_table_factor join_condition | table_reference except_full_outer_join_type table_reference join_condition
{
JOIN_MERGE_NODES($1, $3);
malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $2, $1, $3, $4, NULL);
}
| table_reference FULL JOIN table_reference join_condition
{ {
JOIN_MERGE_NODES($1, $4); JOIN_MERGE_NODES($1, $4);
malloc_terminal_node($$, result->malloc_pool_, T_JOIN_FULL); malloc_terminal_node($$, result->malloc_pool_, T_JOIN_FULL);
malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $$, $1, $4, $5, NULL); malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $$, $1, $4, $5, NULL);
} }
| table_reference FULL OUTER JOIN opt_full_table_factor join_condition | table_reference FULL OUTER JOIN table_reference join_condition
{ {
JOIN_MERGE_NODES($1, $5); JOIN_MERGE_NODES($1, $5);
malloc_terminal_node($$, result->malloc_pool_, T_JOIN_FULL); malloc_terminal_node($$, result->malloc_pool_, T_JOIN_FULL);
malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $$, $1, $5, $6, NULL); malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $$, $1, $5, $6, NULL);
} }
| table_reference FULL %prec LOWER_COMMA
{
if ($1->type_ == T_ORG) {
ParseNode *name_node = NULL;
make_name_node(name_node, result->malloc_pool_, "full");
$$ = new_node(result->malloc_pool_, T_ALIAS, $1->num_child_ + 1);
if (OB_UNLIKELY($$ == NULL)) {
yyerror(NULL, result, "No more space for malloc\n");
YYABORT_NO_MEMORY;
} else {
for (int i = 0; i <= $1->num_child_; ++i) {
if (i == 0) {
$$->children_[i] = $1->children_[i];
} else if (i == 1) {
$$->children_[i] = name_node;
} else {
$$->children_[i] = $1->children_[i - 1];
}
}
$$->sql_str_off_ = @1.first_column;
}
} else if ($1->type_ == T_ALIAS && $1->children_[1] != NULL &&
strlen($1->children_[1]->str_value_) == 0) {
ParseNode *name_node = NULL;
make_name_node(name_node, result->malloc_pool_, "full");
$1->children_[1] = name_node;
$$ = $1;
} else {
yyerror(&@2, result, "occur multi alias name\n");
YYERROR;
}
}
| table_reference natural_join_type opt_full_table_factor | table_reference natural_join_type opt_full_table_factor
{ {
JOIN_MERGE_NODES($1, $3); JOIN_MERGE_NODES($1, $3);
ParseNode *join_attr = NULL; ParseNode *join_attr = NULL;
malloc_terminal_node(join_attr, result->malloc_pool_, T_NATURAL_JOIN); malloc_terminal_node(join_attr, result->malloc_pool_, T_NATURAL_JOIN);
malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $2, $1, $3, NULL, join_attr); malloc_non_terminal_node($$, result->malloc_pool_, T_JOINED_TABLE, 5, $2, $1, $3, NULL, join_attr);
} }
; ;
@ -13142,13 +13172,22 @@ table_factor %prec LOWER_COMMA
; ;
natural_join_type: natural_join_type:
NATURAL outer_join_type NATURAL except_full_outer_join_type
{ {
$$ = $2 $$ = $2
} }
| NATURAL opt_inner JOIN | NATURAL FULL opt_outer JOIN
{
/* make bison mute */
(void)($3);
malloc_terminal_node($$, result->malloc_pool_, T_JOIN_FULL);
}
| NATURAL JOIN
{
malloc_terminal_node($$, result->malloc_pool_, T_JOIN_INNER);
}
| NATURAL INNER JOIN
{ {
(void)$2;
malloc_terminal_node($$, result->malloc_pool_, T_JOIN_INNER); malloc_terminal_node($$, result->malloc_pool_, T_JOIN_INNER);
} }
; ;
@ -13172,32 +13211,6 @@ JOIN
} }
; ;
opt_inner:
INNER { $$ = NULL; }
| /* EMPTY */ { $$ = NULL; }
;
outer_join_type:
FULL opt_outer JOIN
{
/* make bison mute */
(void)($2);
malloc_terminal_node($$, result->malloc_pool_, T_JOIN_FULL);
}
| LEFT opt_outer JOIN
{
/* make bison mute */
(void)($2);
malloc_terminal_node($$, result->malloc_pool_, T_JOIN_LEFT);
}
| RIGHT opt_outer JOIN
{
/* make bison mute */
(void)($2);
malloc_terminal_node($$, result->malloc_pool_, T_JOIN_RIGHT);
}
;
except_full_outer_join_type: except_full_outer_join_type:
LEFT opt_outer JOIN LEFT opt_outer JOIN
{ {