Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Metz
oceanbase
提交
0002ca3b
O
oceanbase
项目概览
Metz
/
oceanbase
与 Fork 源项目一致
Fork自
oceanbase / oceanbase
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
O
oceanbase
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
0002ca3b
编写于
2月 28, 2022
作者:
S
st0
提交者:
LINGuanRen
2月 28, 2022
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix function convert_tz bug
上级
86294613
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
267 addition
and
190 deletion
+267
-190
deps/oblib/src/lib/timezone/ob_time_convert.cpp
deps/oblib/src/lib/timezone/ob_time_convert.cpp
+2
-0
deps/oblib/src/lib/timezone/ob_time_convert.h
deps/oblib/src/lib/timezone/ob_time_convert.h
+2
-0
src/share/object/ob_obj_cast.cpp
src/share/object/ob_obj_cast.cpp
+19
-1
src/sql/engine/expr/ob_datum_cast.cpp
src/sql/engine/expr/ob_datum_cast.cpp
+16
-1
src/sql/engine/expr/ob_expr_convert_tz.cpp
src/sql/engine/expr/ob_expr_convert_tz.cpp
+90
-75
src/sql/engine/expr/ob_expr_convert_tz.h
src/sql/engine/expr/ob_expr_convert_tz.h
+9
-5
src/sql/engine/expr/ob_expr_least.cpp
src/sql/engine/expr/ob_expr_least.cpp
+24
-24
src/sql/engine/expr/ob_expr_least.h
src/sql/engine/expr/ob_expr_least.h
+28
-7
src/sql/engine/expr/ob_expr_relational_result_type.map
src/sql/engine/expr/ob_expr_relational_result_type.map
+62
-62
unittest/sql/optimizer/test_optimizer_default_stat.result
unittest/sql/optimizer/test_optimizer_default_stat.result
+8
-8
unittest/sql/optimizer/test_optimizer_select.result
unittest/sql/optimizer/test_optimizer_select.result
+7
-7
未找到文件。
deps/oblib/src/lib/timezone/ob_time_convert.cpp
浏览文件 @
0002ca3b
...
...
@@ -5566,6 +5566,7 @@ int ObTimeConverter::apply_datetime_for_time_rule(
return
ret
;
}
// for convert utc time to local time, use get_timezone_offset and no gap/overlap time exist.
OB_INLINE
int
ObTimeConverter
::
add_timezone_offset
(
const
ObTimeZoneInfo
*
tz_info
,
int64_t
&
value
)
{
int
ret
=
OB_SUCCESS
;
...
...
@@ -5580,6 +5581,7 @@ OB_INLINE int ObTimeConverter::add_timezone_offset(const ObTimeZoneInfo* tz_info
return
ret
;
}
// for convert local time to utc time, gap/overlap time may exist.
OB_INLINE
int
ObTimeConverter
::
sub_timezone_offset
(
const
ObTimeZoneInfo
*
tz_info
,
bool
is_timestamp
,
const
ObString
&
tz_abbr_str
,
int64_t
&
value
,
const
bool
is_oracle_mode
)
{
...
...
deps/oblib/src/lib/timezone/ob_time_convert.h
浏览文件 @
0002ca3b
...
...
@@ -144,6 +144,8 @@ extern const int64_t USECS_PER_MIN;
#define DATETIME_MAX_VAL 253402300799999999
#define DATE_MAX_VAL 2932896
#define DATETIME_MIN_VAL -62167132800000000
#define MYSQL_TIMESTAMP_MAX_VAL 253402214399999999
#define MYSQL_TIMESTAMP_MIN_VAL -62167046400000000
#define ORACLE_DATETIME_MIN_VAL -62135596800000000 // start from '0001-1-1 00:00:00'
#define TIME_MAX_HOUR 838
...
...
src/share/object/ob_obj_cast.cpp
浏览文件 @
0002ca3b
...
...
@@ -3661,6 +3661,24 @@ static int year_number(
return
ret
;
}
static
int
year_datetime
(
const
ObObjType
expect_type
,
ObObjCastParams
&
params
,
const
ObObj
&
in
,
ObObj
&
out
,
const
ObCastMode
cast_mode
)
{
int
ret
=
OB_SUCCESS
;
int64_t
int_value
=
0
;
ObObj
int64
;
if
(
OB_UNLIKELY
(
ObYearTC
!=
in
.
get_type_class
()
||
ObDateTimeTC
!=
ob_obj_type_class
(
expect_type
)))
{
ret
=
OB_ERR_UNEXPECTED
;
LOG_ERROR
(
"invalid input type"
,
K
(
ret
),
K
(
in
),
K
(
expect_type
));
}
else
if
(
OB_FAIL
(
ObTimeConverter
::
year_to_int
(
in
.
get_year
(),
int_value
)))
{
LOG_WARN
(
"year to int failed"
,
K
(
ret
));
}
else
if
(
FALSE_IT
(
int64
.
set_int
(
int_value
)))
{
}
else
if
(
OB_FAIL
(
int_datetime
(
expect_type
,
params
,
int64
,
out
,
cast_mode
)))
{
LOG_WARN
(
"int_datetime failed"
,
K
(
ret
));
}
return
ret
;
}
static
int
year_date
(
const
ObObjType
expect_type
,
ObObjCastParams
&
params
,
const
ObObj
&
in
,
ObObj
&
out
,
const
ObCastMode
cast_mode
)
{
...
...
@@ -6824,7 +6842,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = {
year_float
,
/*float*/
year_double
,
/*double*/
year_number
,
/*number*/
cast_not_support
,
/*datetime*/
year_datetime
,
/*datetime*/
year_date
,
/*date*/
cast_not_support
,
/*time*/
cast_identity
,
/*year*/
...
...
src/sql/engine/expr/ob_datum_cast.cpp
浏览文件 @
0002ca3b
...
...
@@ -3565,6 +3565,21 @@ CAST_FUNC_NAME(year, string)
return
ret
;
}
CAST_FUNC_NAME
(
year
,
datetime
)
{
EVAL_ARG
()
{
uint8_t
in_val
=
child_res
->
get_uint8
();
int64_t
val_int
=
0
;
if
(
OB_FAIL
(
common_year_int
(
expr
,
ObIntType
,
in_val
,
val_int
)))
{
LOG_WARN
(
"common_year_int failed"
,
K
(
ret
),
K
(
in_val
));
}
else
if
(
OB_FAIL
(
common_int_datetime
(
expr
,
val_int
,
ctx
,
res_datum
)))
{
LOG_WARN
(
"common_int_datetime failed"
,
K
(
ret
),
K
(
val_int
));
}
}
return
ret
;
}
CAST_FUNC_NAME
(
year
,
date
)
{
EVAL_ARG
()
...
...
@@ -8045,7 +8060,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = {
year_float
,
/*float*/
year_double
,
/*double*/
year_number
,
/*number*/
cast_not_support
,
/*datetime*/
year_datetime
,
/*datetime*/
year_date
,
/*date*/
cast_not_support
,
/*time*/
cast_eval_arg
,
/*year*/
...
...
src/sql/engine/expr/ob_expr_convert_tz.cpp
浏览文件 @
0002ca3b
...
...
@@ -26,43 +26,6 @@ ObExprConvertTZ::ObExprConvertTZ(common::ObIAllocator &alloc)
:
ObFuncExprOperator
(
alloc
,
T_FUN_SYS_CONVERT_TZ
,
"convert_TZ"
,
3
,
NOT_ROW_DIMENSION
)
{}
int
ObExprConvertTZ
::
cg_expr
(
ObExprCGCtx
&
expr_cg_ctx
,
const
ObRawExpr
&
raw_expr
,
ObExpr
&
expr
)
const
{
int
ret
=
OB_SUCCESS
;
UNUSED
(
expr_cg_ctx
);
UNUSED
(
raw_expr
);
CK
(
3
==
expr
.
arg_cnt_
);
CK
(
OB_NOT_NULL
(
expr
.
args_
)
&&
OB_NOT_NULL
(
expr
.
args_
[
0
])
&&
OB_NOT_NULL
(
expr
.
args_
[
1
])
&&
OB_NOT_NULL
(
expr
.
args_
[
2
]));
CK
(
ObDateTimeType
==
expr
.
args_
[
0
]
->
datum_meta_
.
type_
);
CK
(
ObDateTimeType
==
expr
.
datum_meta_
.
type_
);
CK
(
ObVarcharType
==
expr
.
args_
[
1
]
->
datum_meta_
.
type_
);
CK
(
ObVarcharType
==
expr
.
args_
[
2
]
->
datum_meta_
.
type_
);
OX
(
expr
.
eval_func_
=
ObExprConvertTZ
::
eval_convert_tz
);
return
ret
;
}
int
ObExprConvertTZ
::
eval_convert_tz
(
const
ObExpr
&
expr
,
ObEvalCtx
&
ctx
,
ObDatum
&
res
)
{
int
ret
=
OB_SUCCESS
;
ObDatum
*
timestamp
=
NULL
;
ObDatum
*
time_zone_s
=
NULL
;
ObDatum
*
time_zone_d
=
NULL
;
if
(
OB_FAIL
(
expr
.
eval_param_value
(
ctx
,
timestamp
,
time_zone_s
,
time_zone_d
)))
{
LOG_WARN
(
"calc param value failed"
,
K
(
ret
));
}
else
if
(
OB_UNLIKELY
(
timestamp
->
is_null
()
||
time_zone_s
->
is_null
()
||
time_zone_d
->
is_null
()))
{
res
.
set_null
();
}
else
{
int64_t
timestamp_data
=
timestamp
->
get_datetime
();
if
(
OB_FAIL
(
calc_convert_tz
(
timestamp_data
,
time_zone_s
->
get_string
(),
time_zone_d
->
get_string
(),
ctx
.
exec_ctx_
.
get_my_session
())))
{
LOG_WARN
(
"calc convert tz zone failed"
,
K
(
ret
));
}
else
{
res
.
set_datetime
(
timestamp_data
);
}
}
return
ret
;
}
int
ObExprConvertTZ
::
calc_result_type3
(
ObExprResType
&
type
,
ObExprResType
&
input1
,
ObExprResType
&
input2
,
ObExprResType
&
input3
,
common
::
ObExprTypeCtx
&
type_ctx
)
const
{
...
...
@@ -73,6 +36,9 @@ int ObExprConvertTZ::calc_result_type3(ObExprResType &type, ObExprResType &input
ret
=
OB_ERR_UNEXPECTED
;
LOG_WARN
(
"session is null"
,
K
(
ret
));
}
else
{
int16_t
scale1
=
MIN
(
input1
.
get_scale
(),
MAX_SCALE_FOR_TEMPORAL
);
scale1
=
(
SCALE_UNKNOWN_YET
==
scale1
)
?
MAX_SCALE_FOR_TEMPORAL
:
scale1
;
type
.
set_scale
(
scale1
);
type
.
set_datetime
();
input1
.
set_calc_type
(
ObDateTimeType
);
input2
.
set_calc_type
(
ObVarcharType
);
...
...
@@ -91,40 +57,48 @@ int ObExprConvertTZ::calc_result3(common::ObObj &result, const common::ObObj &in
result
.
set_null
();
}
else
{
int64_t
timestamp_data
=
input1
.
get_datetime
();
if
(
OB_FAIL
(
calc_convert_tz
(
timestamp_data
,
input2
.
get_string
(),
input3
.
get_string
(),
expr_ctx
.
my_session_
)))
{
if
(
OB_FAIL
(
calc_convert_tz
(
timestamp_data
,
input2
.
get_string
(),
input3
.
get_string
(),
expr_ctx
.
my_session_
,
result
)))
{
LOG_WARN
(
"convert time zone failed"
,
K
(
ret
));
}
else
{
result
.
set_datetime
(
timestamp_data
);
}
}
return
ret
;
}
int
ObExprConvertTZ
::
find_time_zone_pos
(
const
ObString
&
tz_name
,
const
ObTimeZoneInfo
&
tz_info
,
ObTimeZoneInfoPos
*&
tz_info_pos
)
template
<
typename
T
>
int
ObExprConvertTZ
::
calc_convert_tz
(
int64_t
timestamp_data
,
const
ObString
&
tz_str_s
,
// source time zone (input2)
const
ObString
&
tz_str_d
,
// destination time zone (input3)
ObSQLSessionInfo
*
session
,
T
&
result
)
{
int
ret
=
OB_SUCCESS
;
tz_info_pos
=
NULL
;
ObTZInfoMap
*
tz_info_map
=
NULL
;
if
(
OB_ISNULL
(
tz_info_map
=
const_cast
<
ObTZInfoMap
*>
(
tz_info
.
get_tz_info_map
())))
{
ret
=
OB_ERR_UNEXPECTED
;
LOG_WARN
(
"tz_info_map is NULL"
,
K
(
ret
));
}
else
if
(
OB_FAIL
(
tz_info_map
->
get_tz_info_by_name
(
tz_name
,
tz_info_pos
)))
{
LOG_WARN
(
"fail to get_tz_info_by_name"
,
K
(
tz_name
),
K
(
ret
));
tz_info_map
->
id_map_
.
revert
(
tz_info_pos
);
tz_info_pos
=
NULL
;
int32_t
offset_s
=
0
;
int32_t
offset_d
=
0
;
if
(
OB_FAIL
(
ObExprConvertTZ
::
parse_string
(
timestamp_data
,
tz_str_s
,
session
,
false
)))
{
LOG_WARN
(
"source time zone parse failed"
,
K
(
ret
),
K
(
tz_str_s
));
}
else
if
(
OB_FAIL
(
ObExprConvertTZ
::
parse_string
(
timestamp_data
,
tz_str_d
,
session
,
true
)))
{
LOG_WARN
(
"source time zone parse failed"
,
K
(
ret
),
K
(
tz_str_d
));
}
if
(
OB_FAIL
(
ret
))
{
ret
=
OB_SUCCESS
;
result
.
set_null
();
}
else
{
tz_info_pos
->
set_error_on_overlap_time
(
tz_info
.
is_error_on_overlap_time
());
// need to test overlap time
int64_t
res_value
=
timestamp_data
+
(
static_cast
<
int64_t
>
(
offset_d
-
offset_s
))
*
1000000
;
if
(
OB_UNLIKELY
(
res_value
<
MYSQL_TIMESTAMP_MIN_VAL
||
res_value
>
MYSQL_TIMESTAMP_MAX_VAL
))
{
result
.
set_null
();
}
else
{
result
.
set_datetime
(
res_value
);
}
}
return
ret
;
}
int
ObExprConvertTZ
::
parse_string
(
int64_t
&
timestamp_data
,
const
ObString
&
tz_str
,
ObSQLSessionInfo
*
session
,
int32_t
&
offset
)
int64_t
&
timestamp_data
,
const
ObString
&
tz_str
,
ObSQLSessionInfo
*
session
,
const
bool
input_utc_time
)
{
int
ret
=
OB_SUCCESS
;
int
ret_more
=
0
;
int32_t
offset
=
0
;
if
(
OB_FAIL
(
ObTimeConverter
::
str_to_offset
(
tz_str
,
offset
,
ret_more
,
false
/* oracle_mode */
,
true
/* need_check_valid */
)))
{
LOG_WARN
(
"direct str_to_offset failed"
);
...
...
@@ -139,48 +113,89 @@ int ObExprConvertTZ::parse_string(
if
(
OB_ERR_UNKNOWN_TIME_ZONE
==
ret
&&
OB_SUCCESS
!=
ret_more
)
{
ret
=
ret_more
;
}
}
else
if
(
OB_FAIL
(
calc
(
timestamp_data
,
*
target_tz_pos
,
offset
)))
{
}
else
if
(
OB_FAIL
(
calc
(
timestamp_data
,
*
target_tz_pos
,
input_utc_time
)))
{
LOG_WARN
(
"calc failed"
,
K
(
ret
),
K
(
timestamp_data
));
}
}
else
{
LOG_WARN
(
"str to offset failed"
,
K
(
ret
));
}
}
else
{
timestamp_data
+=
(
input_utc_time
?
1
:
-
1
)
*
offset
*
USECS_PER_SEC
;
LOG_DEBUG
(
"str to offset succeed"
,
K
(
tz_str
),
K
(
offset
));
}
return
ret
;
}
int
ObExprConvertTZ
::
calc_convert_tz
(
int64_t
&
timestamp_data
,
const
ObString
&
tz_str_s
,
// source time zone (input2)
const
ObString
&
tz_str_d
,
// destination time zone (input3)
ObSQLSessionInfo
*
session
)
int
ObExprConvertTZ
::
find_time_zone_pos
(
const
ObString
&
tz_name
,
const
ObTimeZoneInfo
&
tz_info
,
ObTimeZoneInfoPos
*&
tz_info_pos
)
{
int
ret
=
OB_SUCCESS
;
int32_t
offset_s
=
0
;
int32_t
offset_d
=
0
;
if
(
OB_FAIL
(
ObExprConvertTZ
::
parse_string
(
timestamp_data
,
tz_str_s
,
session
,
offset_s
)))
{
LOG_WARN
(
"source time zone parse failed"
,
K
(
tz_str_s
));
}
else
if
(
OB_FAIL
(
ObExprConvertTZ
::
parse_string
(
timestamp_data
,
tz_str_d
,
session
,
offset_d
)))
{
LOG_WARN
(
"source time zone parse failed"
,
K
(
tz_str_d
));
tz_info_pos
=
NULL
;
ObTZInfoMap
*
tz_info_map
=
NULL
;
if
(
OB_ISNULL
(
tz_info_map
=
const_cast
<
ObTZInfoMap
*>
(
tz_info
.
get_tz_info_map
())))
{
ret
=
OB_ERR_UNEXPECTED
;
LOG_WARN
(
"tz_info_map is NULL"
,
K
(
ret
));
}
else
if
(
OB_FAIL
(
tz_info_map
->
get_tz_info_by_name
(
tz_name
,
tz_info_pos
)))
{
LOG_WARN
(
"fail to get_tz_info_by_name"
,
K
(
tz_name
),
K
(
ret
));
tz_info_map
->
id_map_
.
revert
(
tz_info_pos
);
tz_info_pos
=
NULL
;
}
else
{
t
imestamp_data
=
timestamp_data
+
(
static_cast
<
int64_t
>
(
offset_d
-
offset_s
))
*
1000000
;
t
z_info_pos
->
set_error_on_overlap_time
(
tz_info
.
is_error_on_overlap_time
())
;
}
return
ret
;
}
int
ObExprConvertTZ
::
calc
(
int64_t
&
timestamp_data
,
const
ObTimeZoneInfoPos
&
tz_info_pos
,
int32_t
&
offset_sec
)
int
ObExprConvertTZ
::
calc
(
int64_t
&
timestamp_data
,
const
ObTimeZoneInfoPos
&
tz_info_pos
,
const
bool
input_utc_time
)
{
int
ret
=
OB_SUCCESS
;
offset_sec
=
0
;
int32_t
tz_id
=
tz_info_pos
.
get_tz_id
();
int32_t
tran_type_id
=
0
;
ObString
tz_abbr_str
;
if
(
OB_FAIL
(
tz_info_pos
.
get_timezone_offset
(
timestamp_data
,
offset_sec
,
tz_abbr_str
,
tran_type_id
)))
{
// the result value is in offset_sec
LOG_WARN
(
"get timezone sub offset failed"
,
K
(
ret
));
const
int64_t
input_value
=
timestamp_data
;
if
(
input_utc_time
)
{
if
(
OB_FAIL
(
ObTimeConverter
::
timestamp_to_datetime
(
input_value
,
&
tz_info_pos
,
timestamp_data
)))
{
LOG_WARN
(
"add timezone offset to utc time failed"
,
K
(
ret
),
K
(
timestamp_data
));
}
}
else
{
LOG_DEBUG
(
"at time zone base calc"
,
K
(
timestamp_data
),
K
(
tz_id
),
K
(
tran_type_id
));
if
(
OB_FAIL
(
ObTimeConverter
::
datetime_to_timestamp
(
input_value
,
&
tz_info_pos
,
timestamp_data
)))
{
LOG_WARN
(
"sub timezone offset fail"
,
K
(
ret
));
}
}
LOG_DEBUG
(
"convert tz calc"
,
K
(
timestamp_data
),
K
(
input_utc_time
));
return
ret
;
}
int
ObExprConvertTZ
::
cg_expr
(
ObExprCGCtx
&
expr_cg_ctx
,
const
ObRawExpr
&
raw_expr
,
ObExpr
&
expr
)
const
{
int
ret
=
OB_SUCCESS
;
UNUSED
(
expr_cg_ctx
);
UNUSED
(
raw_expr
);
CK
(
3
==
expr
.
arg_cnt_
);
CK
(
OB_NOT_NULL
(
expr
.
args_
)
&&
OB_NOT_NULL
(
expr
.
args_
[
0
])
&&
OB_NOT_NULL
(
expr
.
args_
[
1
])
&&
OB_NOT_NULL
(
expr
.
args_
[
2
]));
CK
(
ObDateTimeType
==
expr
.
args_
[
0
]
->
datum_meta_
.
type_
);
CK
(
ObDateTimeType
==
expr
.
datum_meta_
.
type_
);
CK
(
ObVarcharType
==
expr
.
args_
[
1
]
->
datum_meta_
.
type_
);
CK
(
ObVarcharType
==
expr
.
args_
[
2
]
->
datum_meta_
.
type_
);
OX
(
expr
.
eval_func_
=
ObExprConvertTZ
::
eval_convert_tz
);
return
ret
;
}
int
ObExprConvertTZ
::
eval_convert_tz
(
const
ObExpr
&
expr
,
ObEvalCtx
&
ctx
,
ObDatum
&
res
)
{
int
ret
=
OB_SUCCESS
;
ObDatum
*
timestamp
=
NULL
;
ObDatum
*
time_zone_s
=
NULL
;
ObDatum
*
time_zone_d
=
NULL
;
if
(
OB_FAIL
(
expr
.
eval_param_value
(
ctx
,
timestamp
,
time_zone_s
,
time_zone_d
)))
{
LOG_WARN
(
"calc param value failed"
,
K
(
ret
));
}
else
if
(
OB_UNLIKELY
(
timestamp
->
is_null
()
||
time_zone_s
->
is_null
()
||
time_zone_d
->
is_null
()))
{
res
.
set_null
();
}
else
{
int64_t
timestamp_data
=
timestamp
->
get_datetime
();
if
(
OB_FAIL
(
calc_convert_tz
(
timestamp_data
,
time_zone_s
->
get_string
(),
time_zone_d
->
get_string
(),
ctx
.
exec_ctx_
.
get_my_session
(),
res
)))
{
LOG_WARN
(
"calc convert tz zone failed"
,
K
(
ret
));
}
}
return
ret
;
}
...
...
src/sql/engine/expr/ob_expr_convert_tz.h
浏览文件 @
0002ca3b
...
...
@@ -37,12 +37,16 @@ public:
static
int
find_time_zone_pos
(
const
ObString
&
tz_name
,
const
ObTimeZoneInfo
&
tz_info
,
ObTimeZoneInfoPos
*&
tz_info_pos
);
static
int
calc_convert_tz
(
int64_t
&
timestamp_data
,
const
ObString
&
tz_str_s
,
//source time zone (input2)
template
<
typename
T
>
static
int
calc_convert_tz
(
int64_t
timestamp_data
,
const
ObString
&
tz_str_s
,
//source time zone (input2)
const
ObString
&
tz_str_d
,
//destination time zone (input3)
ObSQLSessionInfo
*
session
);
static
int
calc
(
int64_t
&
timestamp_data
,
const
ObTimeZoneInfoPos
&
tz_info_pos
,
int32_t
&
offset_sec
);
static
int
parse_string
(
int64_t
&
timestamp_data
,
const
ObString
&
tz_str
,
ObSQLSessionInfo
*
session
,
int32_t
&
offset
);
ObSQLSessionInfo
*
session
,
T
&
result
);
static
int
calc
(
int64_t
&
timestamp_data
,
const
ObTimeZoneInfoPos
&
tz_info_pos
,
const
bool
input_utc_time
);
static
int
parse_string
(
int64_t
&
timestamp_data
,
const
ObString
&
tz_str
,
ObSQLSessionInfo
*
session
,
const
bool
input_utc_time
);
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN
(
ObExprConvertTZ
);
...
...
src/sql/engine/expr/ob_expr_least.cpp
浏览文件 @
0002ca3b
...
...
@@ -139,30 +139,19 @@ int ObExprBaseLeastGreatest::calc_result_typeN_mysql(
ObExprOperator
::
calc_result_flagN
(
type
,
types
,
real_param_num
);
// don't cast parameter is all parameters are IntTC or UIntTC.
bool
all_integer
=
true
;
bool
big_int_result
=
false
;
for
(
int
i
=
0
;
i
<
real_param_num
&&
all_integer
;
++
i
)
{
ObObjType
type
=
types
[
i
].
get_type
();
if
(
!
ob_is_integer_type
(
type
))
{
if
(
!
ob_is_integer_type
(
type
)
&&
ObNullType
!=
type
)
{
all_integer
=
false
;
}
else
if
(
ObIntType
==
type
||
ObUInt64Type
==
type
||
ObUInt32Type
==
type
)
{
big_int_result
=
true
;
}
}
if
(
all_integer
)
{
if
(
big_int_result
)
{
type
.
set_type
(
ObIntType
);
}
else
{
type
.
set_type
(
ObInt32Type
);
}
}
else
{
const
ObLengthSemantics
default_length_semantics
=
(
OB_NOT_NULL
(
type_ctx
.
get_session
())
?
type_ctx
.
get_session
()
->
get_actual_nls_length_semantics
()
:
LS_BYTE
);
if
(
OB_FAIL
(
calc_result_meta_for_comparison
(
type
,
types
,
real_param_num
,
type_ctx
.
get_coll_type
(),
default_length_semantics
)))
{
LOG_WARN
(
"calc result meta for comparison failed"
);
}
const
ObLengthSemantics
default_length_semantics
=
(
OB_NOT_NULL
(
type_ctx
.
get_session
())
?
type_ctx
.
get_session
()
->
get_actual_nls_length_semantics
()
:
LS_BYTE
);
if
(
OB_FAIL
(
calc_result_meta_for_comparison
(
type
,
types
,
real_param_num
,
type_ctx
.
get_coll_type
(),
default_length_semantics
)))
{
LOG_WARN
(
"calc result meta for comparison failed"
);
}
if
(
!
all_integer
)
{
if
(
!
all_integer
||
!
type
.
is_integer_type
()
)
{
// compatible with MySQL. compare type and result type may be different.
// resolver makes two copies of parameters. First for comparison and second for output result.
for
(
int64_t
i
=
0
;
i
<
real_param_num
;
i
++
)
{
...
...
@@ -215,14 +204,25 @@ int ObExprBaseLeastGreatest::calc(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& e
}
// compare all params.
if
(
all_integer
)
{
int64_t
minmax_int
=
expr
.
locate_param_datum
(
ctx
,
cmp_param_start
).
get_int
();
for
(
int
i
=
cmp_param_start
+
1
;
i
<=
cmp_param_end
;
++
i
)
{
int64_t
cur_int
=
expr
.
locate_param_datum
(
ctx
,
i
).
get_int
();
if
((
!
least
&&
minmax_int
<
cur_int
)
||
(
least
&&
minmax_int
>
cur_int
))
{
minmax_int
=
cur_int
;
if
(
ob_is_int_tc
(
expr
.
datum_meta_
.
type_
))
{
int64_t
minmax_value
=
expr
.
locate_param_datum
(
ctx
,
cmp_param_start
).
get_int
();
for
(
int
i
=
cmp_param_start
+
1
;
i
<=
cmp_param_end
;
++
i
)
{
int64_t
new_value
=
expr
.
locate_param_datum
(
ctx
,
i
).
get_int
();
if
(
least
!=
(
minmax_value
<
new_value
))
{
minmax_value
=
new_value
;
}
}
expr_datum
.
set_int
(
minmax_value
);
}
else
{
uint64_t
minmax_value
=
expr
.
locate_param_datum
(
ctx
,
cmp_param_start
).
get_uint
();
for
(
int
i
=
cmp_param_start
+
1
;
i
<=
cmp_param_end
;
++
i
)
{
uint64_t
new_value
=
expr
.
locate_param_datum
(
ctx
,
i
).
get_uint
();
if
(
least
!=
(
minmax_value
<
new_value
))
{
minmax_value
=
new_value
;
}
}
expr_datum
.
set_uint
(
minmax_value
);
}
expr_datum
.
set_int
(
minmax_int
);
}
else
{
int
res_idx
=
cmp_param_start
;
ObDatum
*
minmax_param
=
static_cast
<
ObDatum
*>
(
&
expr
.
locate_param_datum
(
ctx
,
res_idx
));
...
...
src/sql/engine/expr/ob_expr_least.h
浏览文件 @
0002ca3b
...
...
@@ -22,13 +22,34 @@ public:
explicit
ObExprBaseLeastGreatest
(
common
::
ObIAllocator
&
alloc
,
ObExprOperatorType
type
,
const
char
*
name
,
int32_t
param_num
);
virtual
~
ObExprBaseLeastGreatest
();
int
calc_result_typeN_oracle
(
ObExprResType
&
type
,
ObExprResType
*
types_stack
,
int64_t
param_num
,
common
::
ObExprTypeCtx
&
type_ctx
)
const
;
int
calc_result_typeN_mysql
(
ObExprResType
&
type
,
ObExprResType
*
types_stack
,
int64_t
param_num
,
common
::
ObExprTypeCtx
&
type_ctx
)
const
;
void
set_param_type
(
const
ObExprResType
&
type
,
ObExprResType
*
types
,
int64_t
param_num
)
const
;
static
int
calc
(
const
ObExpr
&
expr
,
ObEvalCtx
&
ctx
,
ObDatum
&
expr_datum
,
bool
least
);
int
calc_result_typeN_oracle
(
ObExprResType
&
type
,
ObExprResType
*
types_stack
,
int64_t
param_num
,
common
::
ObExprTypeCtx
&
type_ctx
)
const
;
int
calc_result_typeN_mysql
(
ObExprResType
&
type
,
ObExprResType
*
types_stack
,
int64_t
param_num
,
common
::
ObExprTypeCtx
&
type_ctx
)
const
;
void
set_param_type
(
const
ObExprResType
&
type
,
ObExprResType
*
types
,
int64_t
param_num
)
const
;
static
int
calc
(
const
ObExpr
&
expr
,
ObEvalCtx
&
ctx
,
ObDatum
&
expr_datum
,
bool
least
);
// left < right: return true, else return false.
static
inline
bool
cmp_integer
(
const
ObDatum
&
l_datum
,
const
bool
l_is_int
,
const
ObDatum
&
r_datum
,
const
bool
r_is_int
)
{
bool
ret_bool
=
true
;
if
(
l_is_int
&&
r_is_int
)
{
ret_bool
=
l_datum
.
get_int
()
<
r_datum
.
get_int
();
}
else
if
(
!
l_is_int
&&
!
r_is_int
)
{
ret_bool
=
l_datum
.
get_uint
()
<
r_datum
.
get_uint
();
}
else
if
(
l_is_int
&&
!
r_is_int
)
{
ret_bool
=
l_datum
.
get_int
()
<
r_datum
.
get_uint
();
}
else
{
ret_bool
=
l_datum
.
get_uint
()
<
r_datum
.
get_int
();
}
return
ret_bool
;
}
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN
(
ObExprBaseLeastGreatest
);
...
...
src/sql/engine/expr/ob_expr_relational_result_type.map
浏览文件 @
0002ca3b
...
...
@@ -57,13 +57,13 @@ static ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] =
ObInt32Type, /* TinyIntType */
ObInt32Type, /* SmallIntType */
ObInt32Type, /* MediumIntType */
ObInt
32
Type, /* Int32Type */
ObIntType, /* Int32Type */
ObIntType, /* IntType */
ObInt32Type, /* UTinyIntType */
ObInt32Type, /* USmallIntType */
ObInt32Type, /* UMediumIntType */
ObInt
32
Type, /* UInt32Type */
Ob
IntType,
/* UIntType */
ObIntType, /* UInt32Type */
Ob
NumberType,
/* UIntType */
ObDoubleType, /* FloatType */
ObDoubleType, /* DoubleType */
ObDoubleType, /* UFloatType */
...
...
@@ -109,13 +109,13 @@ static ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] =
ObInt32Type, /* TinyIntType */
ObInt32Type, /* SmallIntType */
ObInt32Type, /* MediumIntType */
ObInt
32
Type, /* Int32Type */
ObIntType, /* Int32Type */
ObIntType, /* IntType */
ObInt32Type, /* UTinyIntType */
ObInt32Type, /* USmallIntType */
ObInt32Type, /* UMediumIntType */
ObInt
32
Type, /* UInt32Type */
Ob
IntType,
/* UIntType */
ObIntType, /* UInt32Type */
Ob
NumberType,
/* UIntType */
ObDoubleType, /* FloatType */
ObDoubleType, /* DoubleType */
ObDoubleType, /* UFloatType */
...
...
@@ -161,13 +161,13 @@ static ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] =
ObInt32Type, /* TinyIntType */
ObInt32Type, /* SmallIntType */
ObInt32Type, /* MediumIntType */
ObInt
32
Type, /* Int32Type */
ObIntType, /* Int32Type */
ObIntType, /* IntType */
ObInt32Type, /* UTinyIntType */
ObInt32Type, /* USmallIntType */
ObInt32Type, /* UMediumIntType */
ObInt
32
Type, /* UInt32Type */
Ob
IntType,
/* UIntType */
ObIntType, /* UInt32Type */
Ob
NumberType,
/* UIntType */
ObDoubleType, /* FloatType */
ObDoubleType, /* DoubleType */
ObDoubleType, /* UFloatType */
...
...
@@ -210,16 +210,16 @@ static ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] =
/*Int32Type*/
{
ObDoubleType, /* NullType */
ObInt
32
Type, /* TinyIntType */
ObInt
32
Type, /* SmallIntType */
ObInt
32
Type, /* MediumIntType */
ObInt
32
Type, /* Int32Type */
ObIntType, /* TinyIntType */
ObIntType, /* SmallIntType */
ObIntType, /* MediumIntType */
ObIntType, /* Int32Type */
ObIntType, /* IntType */
ObInt
32
Type, /* UTinyIntType */
ObInt
32
Type, /* USmallIntType */
ObInt
32
Type, /* UMediumIntType */
ObInt
32
Type, /* UInt32Type */
Ob
Int
Type, /* UIntType */
ObIntType, /* UTinyIntType */
ObIntType, /* USmallIntType */
ObIntType, /* UMediumIntType */
ObIntType, /* UInt32Type */
Ob
Number
Type, /* UIntType */
ObDoubleType, /* FloatType */
ObDoubleType, /* DoubleType */
ObDoubleType, /* UFloatType */
...
...
@@ -262,16 +262,16 @@ static ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] =
/*IntType*/
{
ObDoubleType, /* NullType */
ObIntType,
/* TinyIntType */
ObIntType,
/* SmallIntType */
ObIntType,
/* MediumIntType */
ObIntType, /* TinyIntType */
ObIntType, /* SmallIntType */
ObIntType, /* MediumIntType */
ObIntType, /* Int32Type */
ObIntType, /* IntType */
ObIntType,
/* UTinyIntType */
ObIntType,
/* USmallIntType */
ObIntType,
/* UMediumIntType */
ObIntType, /* UTinyIntType */
ObIntType, /* USmallIntType */
ObIntType, /* UMediumIntType */
ObIntType, /* UInt32Type */
Ob
Int
Type, /* UIntType */
Ob
Number
Type, /* UIntType */
ObDoubleType, /* FloatType */
ObDoubleType, /* DoubleType */
ObDoubleType, /* UFloatType */
...
...
@@ -317,13 +317,13 @@ static ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] =
ObInt32Type, /* TinyIntType */
ObInt32Type, /* SmallIntType */
ObInt32Type, /* MediumIntType */
ObInt
32
Type, /* Int32Type */
ObIntType, /* Int32Type */
ObIntType, /* IntType */
ObInt32Type, /* UTinyIntType */
ObInt32Type, /* USmallIntType */
ObInt32Type, /* UMediumIntType */
Ob
Int32
Type, /* UInt32Type */
Ob
Int
Type, /* UIntType */
Ob
U
Int32Type, /* UTinyIntType */
Ob
U
Int32Type, /* USmallIntType */
Ob
U
Int32Type, /* UMediumIntType */
Ob
UInt64
Type, /* UInt32Type */
Ob
UInt64
Type, /* UIntType */
ObDoubleType, /* FloatType */
ObDoubleType, /* DoubleType */
ObDoubleType, /* UFloatType */
...
...
@@ -369,13 +369,13 @@ static ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] =
ObInt32Type, /* TinyIntType */
ObInt32Type, /* SmallIntType */
ObInt32Type, /* MediumIntType */
ObInt
32
Type, /* Int32Type */
ObIntType, /* Int32Type */
ObIntType, /* IntType */
ObInt32Type, /* UTinyIntType */
ObInt32Type, /* USmallIntType */
ObInt32Type, /* UMediumIntType */
Ob
Int32
Type, /* UInt32Type */
Ob
Int
Type, /* UIntType */
Ob
U
Int32Type, /* UTinyIntType */
Ob
U
Int32Type, /* USmallIntType */
Ob
U
Int32Type, /* UMediumIntType */
Ob
UInt64
Type, /* UInt32Type */
Ob
UInt64
Type, /* UIntType */
ObDoubleType, /* FloatType */
ObDoubleType, /* DoubleType */
ObDoubleType, /* UFloatType */
...
...
@@ -421,13 +421,13 @@ static ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] =
ObInt32Type, /* TinyIntType */
ObInt32Type, /* SmallIntType */
ObInt32Type, /* MediumIntType */
ObInt
32
Type, /* Int32Type */
ObIntType, /* Int32Type */
ObIntType, /* IntType */
ObInt32Type, /* UTinyIntType */
ObInt32Type, /* USmallIntType */
ObInt32Type, /* UMediumIntType */
Ob
Int32
Type, /* UInt32Type */
Ob
Int
Type, /* UIntType */
Ob
U
Int32Type, /* UTinyIntType */
Ob
U
Int32Type, /* USmallIntType */
Ob
U
Int32Type, /* UMediumIntType */
Ob
UInt64
Type, /* UInt32Type */
Ob
UInt64
Type, /* UIntType */
ObDoubleType, /* FloatType */
ObDoubleType, /* DoubleType */
ObDoubleType, /* UFloatType */
...
...
@@ -470,16 +470,16 @@ static ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] =
/*UInt32Type*/
{
ObDoubleType, /* NullType */
ObInt
32
Type, /* TinyIntType */
ObInt
32
Type, /* SmallIntType */
ObInt
32
Type, /* MediumIntType */
ObInt
32
Type, /* Int32Type */
ObIntType, /* TinyIntType */
ObIntType, /* SmallIntType */
ObIntType, /* MediumIntType */
ObIntType, /* Int32Type */
ObIntType, /* IntType */
Ob
Int32
Type, /* UTinyIntType */
Ob
Int32
Type, /* USmallIntType */
Ob
Int32
Type, /* UMediumIntType */
Ob
Int32
Type, /* UInt32Type */
Ob
Int
Type, /* UIntType */
Ob
UInt64
Type, /* UTinyIntType */
Ob
UInt64
Type, /* USmallIntType */
Ob
UInt64
Type, /* UMediumIntType */
Ob
UInt64
Type, /* UInt32Type */
Ob
UInt64
Type, /* UIntType */
ObDoubleType, /* FloatType */
ObDoubleType, /* DoubleType */
ObDoubleType, /* UFloatType */
...
...
@@ -522,16 +522,16 @@ static ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] =
/*UIntType*/
{
ObDoubleType, /* NullType */
Ob
IntType,
/* TinyIntType */
Ob
IntType,
/* SmallIntType */
Ob
IntType,
/* MediumIntType */
Ob
Int
Type, /* Int32Type */
Ob
Int
Type, /* IntType */
Ob
IntType,
/* UTinyIntType */
Ob
IntType,
/* USmallIntType */
Ob
IntType,
/* UMediumIntType */
Ob
Int
Type, /* UInt32Type */
Ob
Int
Type, /* UIntType */
Ob
NumberType,
/* TinyIntType */
Ob
NumberType,
/* SmallIntType */
Ob
NumberType,
/* MediumIntType */
Ob
Number
Type, /* Int32Type */
Ob
Number
Type, /* IntType */
Ob
UInt64Type,
/* UTinyIntType */
Ob
UInt64Type,
/* USmallIntType */
Ob
UInt64Type,
/* UMediumIntType */
Ob
UInt64
Type, /* UInt32Type */
Ob
UInt64
Type, /* UIntType */
ObDoubleType, /* FloatType */
ObDoubleType, /* DoubleType */
ObDoubleType, /* UFloatType */
...
...
unittest/sql/optimizer/test_optimizer_default_stat.result
浏览文件 @
0002ca3b
...
...
@@ -9946,9 +9946,9 @@ SQL: select a1.c2 from t1 left join t2 a1 on (a1.c1= t1.c1) where least(t1.c2, a
===============================================================
|ID|OPERATOR |NAME |EST. ROWS|COST |
---------------------------------------------------------------
|0 |PX COORDINATOR | |100000 |19
28520
|
|1 | EXCHANGE OUT DISTR |:EX10001|100000 |1
909588
|
|2 | MERGE JOIN | |100000 |1
909588
|
|0 |PX COORDINATOR | |100000 |19
03402
|
|1 | EXCHANGE OUT DISTR |:EX10001|100000 |1
884470
|
|2 | MERGE JOIN | |100000 |1
884470
|
|3 | SORT | |500000 |1458906|
|4 | PX PARTITION ITERATOR | |500000 |309262 |
|5 | TABLE SCAN |t1 |500000 |309262 |
...
...
@@ -10032,7 +10032,7 @@ SQL: select a2.c2, t1.c2, a1.c2 from t1 left join t2 a1 on (a1.c1 = t1.c1), t2
==================================================================
|ID|OPERATOR |NAME |EST. ROWS|COST |
------------------------------------------------------------------
|0 |HASH JOIN | |450000000|
269601090
|
|0 |HASH JOIN | |450000000|
307293132
|
|1 | PX COORDINATOR | |300000 |213977 |
|2 | EXCHANGE OUT DISTR |:EX10000|300000 |185579 |
|3 | PX PARTITION ITERATOR | |300000 |185579 |
...
...
@@ -10090,7 +10090,7 @@ SQL: select f_acc.c2, a1.c2, a2.c2 from t2 left join t2 f1 on (f1.c1 = 1 and t2.
===========================================================
|ID|OPERATOR |NAME |EST. ROWS|COST |
-----------------------------------------------------------
|0 |HASH JOIN | |29403 |6
66559
|
|0 |HASH JOIN | |29403 |6
74223
|
|1 | NESTED-LOOP JOIN CARTESIAN | |30 |440690|
|2 | PX COORDINATOR | |1 |53 |
|3 | EXCHANGE OUT DISTR |:EX10000|1 |52 |
...
...
@@ -10179,7 +10179,7 @@ SQL: select f_acc.c2, a1.c2, a2.c2 from t2 left join t2 f1 on (f1.c1 =1 and f1.c
==========================================================
|ID|OPERATOR |NAME |EST. ROWS|COST |
----------------------------------------------------------
|0 |NESTED-LOOP JOIN CARTESIAN| |2970000 |28
23104
|
|0 |NESTED-LOOP JOIN CARTESIAN| |2970000 |28
39849
|
|1 | NESTED-LOOP JOIN | |2970 |440056 |
|2 | PX COORDINATOR | |1 |53 |
|3 | EXCHANGE OUT DISTR |:EX10000|1 |52 |
...
...
@@ -10188,8 +10188,8 @@ SQL: select f_acc.c2, a1.c2, a2.c2 from t2 left join t2 f1 on (f1.c1 =1 and f1.c
|6 | EXCHANGE OUT DISTR |:EX20000|300000 |185579 |
|7 | PX PARTITION ITERATOR | |300000 |185579 |
|8 | TABLE SCAN |t2 |300000 |185579 |
|9 | MATERIAL | |1000 |
188297
|
|10| NESTED-LOOP JOIN | |1000 |
187562
|
|9 | MATERIAL | |1000 |
205042
|
|10| NESTED-LOOP JOIN | |1000 |
204307
|
|11| PX COORDINATOR | |1 |53 |
|12| EXCHANGE OUT DISTR |:EX30000|1 |52 |
|13| TABLE GET |a1 |1 |52 |
...
...
unittest/sql/optimizer/test_optimizer_select.result
浏览文件 @
0002ca3b
...
...
@@ -11222,9 +11222,9 @@ SQL: select a1.c2 from t1 left join t2 a1 on (a1.c1= t1.c1) where least(t1.c2, a
============================================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
------------------------------------------------------------
|0 |PX COORDINATOR | |100 |15
56
|
|1 | EXCHANGE OUT DISTR |:EX10001|100 |15
37
|
|2 | MERGE JOIN | |100 |15
37
|
|0 |PX COORDINATOR | |100 |15
31
|
|1 | EXCHANGE OUT DISTR |:EX10001|100 |15
12
|
|2 | MERGE JOIN | |100 |15
12
|
|3 | SORT | |500 |1074|
|4 | PX PARTITION ITERATOR | |500 |342 |
|5 | TABLE SCAN |t1 |500 |342 |
...
...
@@ -11308,7 +11308,7 @@ SQL: select a2.c2, t1.c2, a1.c2 from t1 left join t2 a1 on (a1.c1 = t1.c1), t2
=============================================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
-------------------------------------------------------------
|0 |HASH JOIN | |450 |26
21
|
|0 |HASH JOIN | |450 |26
74
|
|1 | PX COORDINATOR | |300 |227 |
|2 | EXCHANGE OUT DISTR |:EX10000|300 |198 |
|3 | PX PARTITION ITERATOR | |300 |198 |
...
...
@@ -11457,7 +11457,7 @@ SQL: select f_acc.c2, a1.c2, a2.c2 from t2 left join t2 f1 on (f1.c1 =1 and f1.c
=======================================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
-------------------------------------------------------
|0 |NESTED-LOOP JOIN CARTESIAN| |3 |7
67
|
|0 |NESTED-LOOP JOIN CARTESIAN| |3 |7
84
|
|1 | NESTED-LOOP JOIN | |3 |505 |
|2 | PX COORDINATOR | |1 |53 |
|3 | EXCHANGE OUT DISTR |:EX10000|1 |52 |
...
...
@@ -11466,8 +11466,8 @@ SQL: select f_acc.c2, a1.c2, a2.c2 from t2 left join t2 f1 on (f1.c1 =1 and f1.c
|6 | EXCHANGE OUT DISTR |:EX20000|300 |198 |
|7 | PX PARTITION ITERATOR | |300 |198 |
|8 | TABLE SCAN |t2 |300 |198 |
|9 | MATERIAL | |1 |2
61
|
|10| NESTED-LOOP JOIN | |1 |2
60
|
|9 | MATERIAL | |1 |2
78
|
|10| NESTED-LOOP JOIN | |1 |2
77
|
|11| PX COORDINATOR | |1 |53 |
|12| EXCHANGE OUT DISTR |:EX30000|1 |52 |
|13| TABLE GET |a1 |1 |52 |
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录