From 4b63299a625a3030713fcef598fa1bf938e95059 Mon Sep 17 00:00:00 2001 From: fuxiaofeng Date: Fri, 21 Mar 2025 18:00:03 +0800 Subject: [PATCH 01/12] add local build --- build/Makefile.sh | 2 +- build/compile_opensource_new.sh | 8 +- build/local_install.sh | 150 ++++++++++++++++++++++++++++++++ pkg/install/funclib.py | 2 +- pkg/install/install.py | 18 ++-- pkg/install/installdb.sh | 1 + 6 files changed, 167 insertions(+), 14 deletions(-) create mode 100644 build/local_install.sh diff --git a/build/Makefile.sh b/build/Makefile.sh index f47f7029..d8f266a9 100644 --- a/build/Makefile.sh +++ b/build/Makefile.sh @@ -745,7 +745,7 @@ func_download_3rdparty() if [[ "${WORKSPACE}" == *"regress"* ]]; then DOWNLOAD_PATH=$DFT_WORKSPACE"/CantianKernel" else - DOWNLOAD_PATH=${WORKSPACE}"/cantian" + DOWNLOAD_PATH=${CTDB_CODE_PATH} fi cd ${DOWNLOAD_PATH} diff --git a/build/compile_opensource_new.sh b/build/compile_opensource_new.sh index 10fc5c70..6b0eef47 100644 --- a/build/compile_opensource_new.sh +++ b/build/compile_opensource_new.sh @@ -15,9 +15,11 @@ echo $DFT_WORKSPACE " " $WORKSPACE if [[ "$WORKSPACE" == *"regress"* ]]; then echo $DFT_WORKSPACE " eq " $WORKSPACE else - export OPEN_SOURCE=${WORKSPACE}/cantian/open_source - export LIBRARY=${WORKSPACE}/cantian/library - export PLATFORM=${WORKSPACE}/cantian/platform + CURRENT_PATH=$(dirname $(readlink -f $0)) + CODE_PATH=$(cd "${CURRENT_PATH}/.."; pwd) + export OPEN_SOURCE=${CODE_PATH}/open_source + export LIBRARY=${CODE_PATH}/library + export PLATFORM=${CODE_PATH}/platform fi #pcre diff --git a/build/local_install.sh b/build/local_install.sh new file mode 100644 index 00000000..b26ffa77 --- /dev/null +++ b/build/local_install.sh @@ -0,0 +1,150 @@ +#!/bin/bash + + +CURRENT_PATH=$(dirname $(readlink -f $0)) +CODE_PATH=$(cd "${CURRENT_PATH}/.."; pwd) +WORK_DIR=$(cd "${CURRENT_PATH}/../../"; pwd) +BUILD_ARGS="" +PATCH="" # 是否在cantian中创建元数据 +BUILD_TYPE="release" +USER="cantiandba" + +function prepare() { + echo "Prepare env start." + yum install -y libaio-devel openssl openssl-devel \ + ndctl-devel ncurses ncurses-devel libtirpc-devel \ + expect ant bison iputils iproute wget\ + libtirpc-devel make gcc gcc-c++ gdb gdb-gdbserver\ + python3 python3-devel git net-tools cmake automake\ + byacc libtool --skip-broken + echo "Prepare env success." +} + +function cantian_patch() { + escaped_variable=$(echo "${WORK_DIR}" | sed 's/\//\\\//g') + sed -i "s/\/home\/regress\/CantianKernel/${escaped_variable}\/cantian/g" ${WORK_DIR}/cantian/pkg/install/install.py + sed -i "s/\/home\/regress/${escaped_variable}/g" ${CODE_PATH}/pkg/install/Common.py + sed -i "s/\/home\/regress/${escaped_variable}/g" ${CODE_PATH}/pkg/install/funclib.py + sed -i "s/192.168.86.1/127.0.0.1/g" ${CODE_PATH}/pkg/install/funclib.py +} + +function compile() { + cantian_patch + export local_build=true + cd ${CODE_PATH}/build || exit 1 + sh Makefile.sh package-${BUILD_TYPE} ${BUILD_ARGS} + if [[ $? -ne 0 ]]; then + echo "build_cantian failed." + exit 1 + fi +} + +function clean() { + kill -9 $(pidof cantiand) > /dev/null 2>&1 + kill -9 $(pidof cms) > /dev/null 2>&1 + rm -rf ${WORK_DIR}/cantian_data/* /home/${USER}/install /home/${USER}/data /data/data/* + sed -i "/${USER}/d" /home/${USER}/.bashrc +} + +function install() { + id "${USER}" + if [[ $? -ne 0 ]]; then + echo "add user ${USER}." + useradd -m -s /bin/bash ${USER} + echo "${USER}:${USER}" | chpasswd + fi + touch /.dockerenv + clean + mkdir -p "${WORK_DIR}"/cantian_data -m 755 + chown -R ${USER}:${USER} "${WORK_DIR}"/cantian_data + cd ${CODE_PATH}/Cantian-DATABASE-*-64bit || exit 1 + mkdir -p /home/${USER}/logs + run_mode=cantiand_in_cluster + python3 install.py -U ${USER}:${USER} -R /home/${USER}/install \ + -D /home/${USER}/data -l /home/${USER}/logs/install.log \ + -M ${run_mode} -Z _LOG_LEVEL=255 -N 0 -W 192.168.0.1 -g \ + withoutroot -d -c -Z _SYS_PASSWORD=huawei@1234 -Z SESSIONS=1000 + if [[ $? -ne 0 ]]; then + echo "install cantian failed." + exit 1 + fi +} + +function usage() { + echo 'Usage: sh local_install.sh compile [OPTION]' + echo 'Options:' + echo ' -b, --build_type= Build type, default is release.' + echo ' -u, --user= User name, default is cantiandba.' + echo ' -h, --help Display thishelp and exit.' +} + +function parse_params() +{ + ARGS=$(getopt -o b:u: --long build_type:,user:, -n "$0" -- "$@") + if [ $? != 0 ]; then + echo "Terminating..." + exit 1 + fi + eval set -- "${ARGS}" + while true + do + case "$1" in + -b | --build_type) + BUILD_TYPE=$2 + shift 2 + ;; + -u | --user) + USER=$2 + shift 2 + ;; + --) + shift + break + ;; + -h) + usage + exit 1 + ;; + esac + done +} + +function help() { + echo 'Usage: sh local_install.sh [OPTION]' + echo 'Options:' + echo ' prepare Prepare compile and install dependencies.' + echo ' compile Compile cantian.' + echo ' install Install and start cantian.' + echo ' clean Uninstall and clean env.' +} + +function main() +{ + mode=$1 + shift + parse_params "$@" + case $mode in + prepare) + prepare + exit 0 + ;; + compile) + compile + exit 0 + ;; + install) + install + exit 0 + ;; + clean) + clean + exit 0 + ;; + *) + help + exit 1 + ;; + esac +} + +main "$@" \ No newline at end of file diff --git a/pkg/install/funclib.py b/pkg/install/funclib.py index 6cefd50c..2dfde827 100644 --- a/pkg/install/funclib.py +++ b/pkg/install/funclib.py @@ -200,7 +200,7 @@ class DefaultConfigValue(object): "CLUSTER_DATABASE": "TRUE", "_DOUBLEWRITE": "FALSE", "TEMP_BUFFER_SIZE": "1G", - "DATA_BUFFER_SIZE": "8G", + "DATA_BUFFER_SIZE": "1G", "SHARED_POOL_SIZE": "1G", "LOG_BUFFER_COUNT": 16, "LOG_BUFFER_SIZE": "64M", diff --git a/pkg/install/install.py b/pkg/install/install.py index 69c455de..139d5c5a 100644 --- a/pkg/install/install.py +++ b/pkg/install/install.py @@ -2724,7 +2724,7 @@ class Installer: if g_opts.install_user_privilege == "withoutroot": cmd = "%s/bin/ctencrypt -e PBKDF2" % self.installPath else: - cmd = (""" su - '%s' -c "%s/bin/ctencrypt -e PBKDF2" """ + cmd = (""" su - '%s' -c "source ~/.bashrc && %s/bin/ctencrypt -e PBKDF2" """ % (self.user, self.installPath)) g_opts.db_passwd = g_opts.db_passwd if len(plain_passwd.strip()) == 0 else plain_passwd.strip() values = [g_opts.db_passwd, g_opts.db_passwd] @@ -2943,7 +2943,7 @@ class Installer: cmd = "%s/bin/ctencrypt -r -d '%s'" % (self.installPath, self.data) else: - cmd = (""" su - '%s' -c "%s/bin/ctencrypt -r -d '%s'" """ + cmd = (""" su - '%s' -c "source ~/.bashrc && %s/bin/ctencrypt -r -d '%s'" """ % (self.user, self.installPath, self.data)) ret_code, stdout, stderr = _exec_popen(cmd, [passwd, passwd]) if ret_code: @@ -3441,12 +3441,12 @@ class Installer: cmd, [g_opts.db_passwd]) else: if self.enableSysdbaLogin: - cmd = ("su - '%s' -c \"%s/bin/ctsql / as sysdba " + cmd = ("su - '%s' -c \"source ~/.bashrc && %s/bin/ctsql / as sysdba " "-q -D %s -f \"%s\" \"" % (self.user, self.installPath, self.data, sql_file)) return_code, stdout_data, stderr_data = _exec_popen(cmd) else: - cmd = ("su - '%s' -c \"%s/bin/ctsql %s@%s:%s -q -f \"%s\"\"" % ( + cmd = ("su - '%s' -c \"source ~/.bashrc && %s/bin/ctsql %s@%s:%s -q -f \"%s\"\"" % ( self.user, self.installPath, g_opts.db_user, @@ -3519,12 +3519,12 @@ class Installer: cmd, [g_opts.db_passwd]) else: if self.enableSysdbaLogin: - cmd = ("su - '%s' -c \"%s/bin/ctsql / as sysdba " + cmd = ("su - '%s' -c \"source ~/.bashrc && %s/bin/ctsql / as sysdba " "-q -D %s -c \\\"%s\\\" \"" % (self.user, self.installPath, self.data, sql)) return_code, stdout_data, stderr_data = _exec_popen(cmd) else: - cmd = ("su - '%s' -c \"%s/bin/ctsql %s@%s:%s -q" + cmd = ("su - '%s' -c \"source ~/.bashrc && %s/bin/ctsql %s@%s:%s -q" " -c \\\"%s\\\"\"" % (self.user, self.installPath, g_opts.db_user, @@ -3697,7 +3697,7 @@ class Installer: if g_opts.install_user_privilege == "withoutroot": cmd = "%s/bin/ctencrypt -g" % self.installPath else: - cmd = "su - '%s' -c \"%s/bin/ctencrypt -g \"" % (self.user, self.installPath) + cmd = "su - '%s' -c \"source ~/.bashrc && %s/bin/ctencrypt -g \"" % (self.user, self.installPath) ret_code, stdout, stderr = _exec_popen(cmd) if ret_code: raise OSError("Failed to generate encrypted keys. Error: %s" @@ -3732,7 +3732,7 @@ class Installer: if g_opts.install_user_privilege == "withoutroot": cmd = "%s/bin/ctencrypt -g -o '%s' " % (self.installPath, f_factor1) else: - cmd = ("su - '%s' -c \"%s/bin/ctencrypt -g -o '%s' \"" + cmd = ("su - '%s' -c \"source ~/.bashrc && %s/bin/ctencrypt -g -o '%s' \"" % (self.user, self.installPath, f_factor1)) ret_code, stdout, stderr = _exec_popen(cmd) if ret_code: @@ -3767,7 +3767,7 @@ class Installer: cmd = ("""%s/bin/ctencrypt -e AES256 -f %s -k %s """ % (self.installPath, key_, work_key)) else: - cmd = ("su - '%s' -c \"%s/bin/ctencrypt -e AES256" + cmd = ("su - '%s' -c \"source ~/.bashrc && %s/bin/ctencrypt -e AES256" " -f '%s' -k '%s' \"" % (self.user, self.installPath, key_, work_key)) values = [ssl_passwd, ssl_passwd] diff --git a/pkg/install/installdb.sh b/pkg/install/installdb.sh index d3c33a37..39335abf 100644 --- a/pkg/install/installdb.sh +++ b/pkg/install/installdb.sh @@ -2,6 +2,7 @@ # # This library is using the variables listed in cfg/cluster.ini, and value come from install.py#set_cluster_conf # +source ~/.bashrc running_mode=$(grep '"M_RUNING_MODE"' /opt/cantian/action/cantian/install_config.json | cut -d '"' -f 4) single_mode="multiple" if [ "$running_mode" = "cantiand_with_mysql" ] || -- Gitee From 052776ae5aa198c5471c54f2d4e60f16d12cf0c9 Mon Sep 17 00:00:00 2001 From: lijieac Date: Mon, 24 Mar 2025 20:17:08 +0800 Subject: [PATCH 02/12] feat: add the explain --- pkg/src/ctsql/CMakeLists.txt | 3 + pkg/src/ctsql/ctsql_stmt.c | 66 ++- pkg/src/ctsql/ctsql_stmt.h | 1 + .../ctsql/executor/explain/expl_executor.c | 307 ++++++++++ .../ctsql/executor/explain/expl_executor.h | 39 ++ pkg/src/ctsql/executor/explain/expl_plan.c | 539 ++++++++++++++++++ pkg/src/ctsql/executor/explain/expl_plan.h | 105 ++++ pkg/src/ctsql/parser/ctsql_parser.c | 29 +- pkg/src/ctsql/parser/ctsql_parser.h | 7 +- pkg/src/ctsql/parser/dcl_parser.c | 3 +- pkg/src/ctsql/parser/dcl_parser.h | 2 +- pkg/src/ctsql/parser/dml_parser.c | 20 +- pkg/src/ctsql/parser/dml_parser.h | 3 +- pkg/src/ctsql/parser_ddl/ddl_parser.c | 5 +- pkg/src/ctsql/parser_ddl/ddl_parser.h | 2 +- 15 files changed, 1095 insertions(+), 36 deletions(-) create mode 100644 pkg/src/ctsql/executor/explain/expl_executor.c create mode 100644 pkg/src/ctsql/executor/explain/expl_executor.h create mode 100644 pkg/src/ctsql/executor/explain/expl_plan.c create mode 100644 pkg/src/ctsql/executor/explain/expl_plan.h diff --git a/pkg/src/ctsql/CMakeLists.txt b/pkg/src/ctsql/CMakeLists.txt index 08b95af1..b74cba7a 100644 --- a/pkg/src/ctsql/CMakeLists.txt +++ b/pkg/src/ctsql/CMakeLists.txt @@ -5,6 +5,7 @@ include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/catalog" "${CMAKE_CURRENT_SOURCE_DIR}/executor" + "${CMAKE_CURRENT_SOURCE_DIR}/executor/explain" "${CMAKE_CURRENT_SOURCE_DIR}/json" "${CMAKE_CURRENT_SOURCE_DIR}/node" "${CMAKE_CURRENT_SOURCE_DIR}/function" @@ -25,6 +26,7 @@ set(LIBRARY_OUTPUT_PATH ${CANTIANDB_LIB}) aux_source_directory(. SQL_SRC) aux_source_directory(./catalog SQL_CATALOG_SRC) aux_source_directory(./executor SQL_EXECUTOR_SRC) +aux_source_directory(./executor/explain SQL_EXECUTOR_EXPLAIN_SRC) aux_source_directory(./json SQL_JSON_SRC) aux_source_directory(./node SQL_NODE_SRC) aux_source_directory(./function SQL_FUNCTION_SRC) @@ -50,6 +52,7 @@ set(SQL_ALL_SRC ${SQL_SRC} ${SQL_CATALOG_SRC} ${SQL_EXECUTOR_SRC} + ${SQL_EXECUTOR_EXPLAIN_SRC} ${SQL_NODE_SRC} ${SQL_FUNCTION_SRC} ${SQL_JSON_SRC} diff --git a/pkg/src/ctsql/ctsql_stmt.c b/pkg/src/ctsql/ctsql_stmt.c index f06d2217..54d58226 100644 --- a/pkg/src/ctsql/ctsql_stmt.c +++ b/pkg/src/ctsql/ctsql_stmt.c @@ -36,6 +36,7 @@ #include "ctsql_select.h" #include "ddl_column_parser.h" #include "pl_executor.h" +#include "expl_executor.h" #ifdef TIME_STATISTIC #include "cm_statistic.h" @@ -65,6 +66,8 @@ extern "C" { (stmt)->session->sql_id = __sql_id__; \ } while (0) +#define EXPLAIN_HEAD "QUERY PLAN" + void sql_init_stmt(session_t *session, sql_stmt_t *stmt, uint32 stmt_id) { sql_context_t *context = (session->disable_soft_parse) ? stmt->context : NULL; @@ -1112,6 +1115,21 @@ static inline status_t sql_execute_dml_and_send(sql_stmt_t *stmt) return CT_SUCCESS; } +static inline status_t sql_execute_expl_and_send(sql_stmt_t *stmt) +{ + if (my_sender(stmt)->send_exec_begin(stmt) != CT_SUCCESS) { + return CT_ERROR; + } + + if (expl_execute(stmt) != CT_SUCCESS) { + return CT_ERROR; + } + + my_sender(stmt)->send_exec_end(stmt); + + return CT_SUCCESS; +} + static status_t sql_init_trigger_list_core(sql_stmt_t *stmt) { if (vmc_alloc(&stmt->vmc, sizeof(galist_t), (void **)&stmt->trigger_list) != CT_SUCCESS) { @@ -1271,7 +1289,9 @@ status_t sql_execute(sql_stmt_t *stmt) } /* do execute */ - if (SQL_TYPE(stmt) < CTSQL_TYPE_DML_CEIL) { + if (stmt->is_explain) { + status = sql_execute_expl_and_send(stmt); + } else if (SQL_TYPE(stmt) < CTSQL_TYPE_DML_CEIL) { status = sql_execute_dml_and_send(stmt); } else if (SQL_TYPE(stmt) == CTSQL_TYPE_ANONYMOUS_BLOCK) { status = ple_exec_anonymous_block(stmt); @@ -3407,6 +3427,32 @@ static void sql_set_column_attr(rs_column_t *rs_col, cs_column_def_t *col_def, t } } +status_t sql_send_parsed_stmt_explain(sql_stmt_t *stmt) +{ + cs_column_def_t *col_def = NULL; + cs_packet_t *send_pack = stmt->session->send_pack; + + uint32 column_def_offset = 0; + CT_RETURN_IFERR(cs_reserve_space(send_pack, sizeof(cs_column_def_t), &column_def_offset)); + col_def = (cs_column_def_t *)CS_RESERVE_ADDR(send_pack, column_def_offset); + MEMS_RETURN_IFERR(memset_sp(col_def, sizeof(cs_column_def_t), 0, sizeof(cs_column_def_t))); + + col_def->size = CT_MAX_COLUMN_SIZE; + col_def->datatype = CT_TYPE_STRING - CT_TYPE_BASE; + col_def->name_len = strlen(EXPLAIN_HEAD); + + uint32 column_name_offset = 0; + CT_RETURN_IFERR(cs_reserve_space(send_pack, col_def->name_len, &column_name_offset)); + char *name = (char *)CS_RESERVE_ADDR(send_pack, column_name_offset); + uint32 align_len = CM_ALIGN4(col_def->name_len); + MEMS_RETURN_IFERR(memcpy_sp(name, align_len, EXPLAIN_HEAD, col_def->name_len)); + if (col_def->name_len < align_len) { + name[col_def->name_len] = '\0'; + } + + return CT_SUCCESS; +} + status_t sql_send_parsed_stmt_normal(sql_stmt_t *stmt, uint16 columnCount) { rs_column_t *rs_col = NULL; @@ -3524,14 +3570,13 @@ static status_t sql_send_parsed_stmt_pl(sql_stmt_t *stmt) return status; } -void sql_set_ack_column_count(sql_stmt_t *stmt, cs_prepare_ack_t *prepare_ack) +uint16 sql_get_ack_column_count(sql_stmt_t *stmt) { if (stmt->is_explain) { - prepare_ack->column_count = 1; - } else { - sql_context_t *ctx = (sql_context_t *)stmt->context; - prepare_ack->column_count = (ctx->rs_columns == NULL) ? 0 : ctx->rs_columns->count; + return 1; } + sql_context_t *ctx = (sql_context_t *)stmt->context; + return (ctx->rs_columns == NULL) ? 0 : ctx->rs_columns->count; } static status_t sql_send_param_info_impl(sql_stmt_t *stmt, galist_t *params_list) @@ -3592,8 +3637,8 @@ static status_t sql_send_params_info(sql_stmt_t *stmt, cs_prepare_ack_t *prepare status_t sql_send_parsed_stmt(sql_stmt_t *stmt) { - cs_prepare_ack_t *prepare_ack = NULL; uint32 ack_offset; + cs_prepare_ack_t *prepare_ack = NULL; cs_packet_t *send_pack = stmt->session->send_pack; CT_BIT_RESET(send_pack->head->flags, CS_FLAG_WITH_TS); @@ -3605,9 +3650,8 @@ status_t sql_send_parsed_stmt(sql_stmt_t *stmt) CT_THROW_ERROR(ERR_INVALID_CURSOR); return CT_ERROR; } - prepare_ack->stmt_type = ACK_STMT_TYPE(stmt->lang_type, stmt->context->type); - sql_set_ack_column_count(stmt, prepare_ack); + prepare_ack->column_count = sql_get_ack_column_count(stmt); // Do not optimize the temporary variables column_count, // because the message expansion may cause the ack address to change, @@ -3615,7 +3659,9 @@ status_t sql_send_parsed_stmt(sql_stmt_t *stmt) uint16 column_count = prepare_ack->column_count; CT_RETURN_IFERR(sql_send_params_info(stmt, prepare_ack)); - { + if (stmt->is_explain) { + CT_RETURN_IFERR(sql_send_parsed_stmt_explain(stmt)); + } else { CT_RETURN_IFERR(sql_send_parsed_stmt_normal(stmt, column_count)); } diff --git a/pkg/src/ctsql/ctsql_stmt.h b/pkg/src/ctsql/ctsql_stmt.h index d83cfa34..46e37b23 100644 --- a/pkg/src/ctsql/ctsql_stmt.h +++ b/pkg/src/ctsql/ctsql_stmt.h @@ -94,6 +94,7 @@ typedef enum en_lang_type { LANG_DDL = 3, LANG_PL = 4, LANG_EXPLAIN = 5, + LANG_MAX, } lang_type_t; typedef struct st_sql_lob_info { diff --git a/pkg/src/ctsql/executor/explain/expl_executor.c b/pkg/src/ctsql/executor/explain/expl_executor.c new file mode 100644 index 00000000..df535a17 --- /dev/null +++ b/pkg/src/ctsql/executor/explain/expl_executor.c @@ -0,0 +1,307 @@ +/* ------------------------------------------------------------------------- + * This file is part of the Cantian project. + * Copyright (c) 2025 Huawei Technologies Co.,Ltd. + * + * Cantian is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * 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 PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * ctsql_distinct.h + * + * + * IDENTIFICATION + * src/ctsql/executor/ctsql_distinct.h + * + * ------------------------------------------------------------------------- + */ + +#include "ctsql_stmt.h" +#include "dml_executor.h" + +#include "expl_plan.h" +#include "expl_executor.h" + +#define EXPL_FMT_ALIGN_SIZE 3 // eg. "ID | Operation | ..." +#define EXPL_FMT_COL_OFFSET 2 // eg. '| ' + +static status_t expl_pre_execute(sql_stmt_t *stmt, sql_cursor_t **cursor) +{ + CT_RETURN_IFERR(sql_alloc_cursor(stmt, cursor)); + (*cursor)->is_open = true; + + CT_RETURN_IFERR(mtrl_create_segment(&stmt->mtrl, MTRL_SEGMENT_RS, NULL, &(*cursor)->mtrl.rs.sid)); + CT_RETURN_IFERR(mtrl_open_segment(&stmt->mtrl, (*cursor)->mtrl.rs.sid)); + + return CT_SUCCESS; +} + +static status_t expl_init_expl_helper(sql_stmt_t *stmt, expl_helper_t *helper, uint32 mtrl_id) +{ + expl_helper_init(helper); + + CT_RETURN_IFERR(sql_push(stmt, CT_MAX_ROW_SIZE, (void **)&(helper->row_buf))); + CT_RETURN_IFERR(sql_push(stmt, CT_MAX_ROW_SIZE, (void **)&(helper->tmp_buf.str))); + helper->mtrl_id = mtrl_id; + + return CT_SUCCESS; +} + +status_t expl_send_explain_row(sql_stmt_t *stmt, sql_cursor_t *cursor, char *row_buf, char *info, bool32 *is_full) +{ + row_assist_t ra; + MEMS_RETURN_IFERR(memset_s(row_buf, CT_MAX_ROW_SIZE, 0, CT_MAX_ROW_SIZE)); + + row_init(&ra, row_buf, CT_MAX_ROW_SIZE, 1); + CT_RETURN_IFERR(row_put_str(&ra, info)); + CT_RETURN_IFERR(my_sender(stmt)->send_row_data(stmt, row_buf, is_full)); + + sql_inc_rows(stmt, cursor); + return CT_SUCCESS; +} + +static uint32 expl_get_explain_width(expl_helper_t *helper) +{ + uint32 width = 1; + for (uint32 i = 0; i < EXPL_COL_TYPE_MAX; i++) { + width += helper->fmt_sizes[i] + EXPL_FMT_ALIGN_SIZE; + } + + if (width > CT_MAX_ROW_SIZE - 1) { + width = CT_MAX_ROW_SIZE - 1; + } + helper->width = width; + + return width; +} + +static status_t expl_send_explain_divider(sql_stmt_t *stmt, sql_cursor_t *cursor, uint32 width, bool32 *is_full) +{ + char *row_buf = NULL; + char *divider = NULL; + + CT_RETURN_IFERR(sql_push(stmt, CT_MAX_ROW_SIZE, (void **)&row_buf)); + CT_RETURN_IFERR(sql_push(stmt, CT_MAX_ROW_SIZE, (void **)÷r)); + + MEMS_RETURN_IFERR(memset_s(divider, CT_MAX_ROW_SIZE, '-', width)); + divider[width + 1] = '\0'; + + CT_RETURN_IFERR(expl_send_explain_row(stmt, cursor, row_buf, divider, is_full)); + return CT_SUCCESS; +} + +static status_t expl_send_explain_head(sql_stmt_t *stmt, sql_cursor_t *cursor, expl_helper_t *helper) +{ + char *info = NULL; + bool32 is_full = CT_FALSE; + text_t *col_name = NULL; + + CTSQL_SAVE_STACK(stmt); + CT_RETURN_IFERR(sql_push(stmt, CT_MAX_ROW_SIZE, (void **)&info)); + uint32 width = expl_get_explain_width(helper); + // send divider + CT_RETURN_IFERR(expl_send_explain_divider(stmt, cursor, width, &is_full)); + + // send column info + uint32 offset = 0; + MEMS_RETURN_IFERR(memset_s(info, CT_MAX_ROW_SIZE, ' ', width - 1)); + info[offset++] = '|'; + for (int32 i = 0; i < EXPL_COL_TYPE_MAX; i++) { + offset++; + if (offset + helper->fmt_sizes[i] >= CT_MAX_ROW_SIZE - 1) { + break; + } + col_name = expl_get_explcol_name(i); + MEMS_RETURN_IFERR(memcpy_s(&info[offset], CT_MAX_ROW_SIZE - offset, col_name->str, col_name->len)); + offset += helper->fmt_sizes[i] + 1; + info[offset++] = '|'; + } + info[offset] = '\0'; + CT_RETURN_IFERR(expl_send_explain_row(stmt, cursor, helper->row_buf, info, &is_full)); + + // send divider + CT_RETURN_IFERR(expl_send_explain_divider(stmt, cursor, width, &is_full)); + CTSQL_RESTORE_STACK(stmt); + + return CT_SUCCESS; +} + +static status_t expl_send_explain_tail(sql_stmt_t *stmt, sql_cursor_t *cursor, expl_helper_t *helper) +{ + bool32 is_full = CT_FALSE; + + CTSQL_SAVE_STACK(stmt); + // send divider + CT_RETURN_IFERR(expl_send_explain_divider(stmt, cursor, helper->width, &is_full)); + CTSQL_RESTORE_STACK(stmt); + + return CT_SUCCESS; +} + +bool32 check_rs_page_in_segment(mtrl_context_t *mtrl, mtrl_segment_t *segment, uint32 vmid) +{ + if (segment->vm_list.count <= 2) { + return (vmid == segment->vm_list.first || vmid == segment->vm_list.last); + } + + vm_ctrl_t *ctrl = NULL; + uint32 cur_id = segment->vm_list.first; + for (int32 i = 2; i < segment->vm_list.count; i++) { + ctrl = vm_get_ctrl(mtrl->pool, cur_id); + if (ctrl->next == vmid) { + return CT_TRUE; + } + cur_id = ctrl->next; + } + return CT_FALSE; +} + +status_t expl_fmt_column_content(mtrl_row_t *row, char *content, uint32 offset, uint16 fmt_size, uint32 col_id) +{ + uint16 col_len = row->lens[col_id]; + char *col_data = row->data + row->offsets[col_id]; + + content[offset] = '|'; + if (col_len == CT_NULL_VALUE_LEN || col_len == 0) { + return CT_SUCCESS; + } + col_len = (col_len > fmt_size) ? fmt_size : col_len; + + MEMS_RETURN_IFERR(memcpy_s(content + offset + EXPL_FMT_COL_OFFSET, fmt_size, col_data, col_len)); + return CT_SUCCESS; +} + +status_t expl_fmt_table_content(sql_stmt_t *stmt, sql_cursor_t *cursor, expl_helper_t *helper, char *content) +{ + uint32 offset = 0; + uint32 *fmt_sizes = helper->fmt_sizes; + mtrl_row_t *row = &cursor->mtrl.cursor.row; + + (void)memset_s(content, CT_MAX_ROW_SIZE, ' ', CT_MAX_ROW_SIZE); + for (uint32 i = 0; i < EXPL_COL_TYPE_MAX; i++) { + if (offset + fmt_sizes[i] + EXPL_FMT_ALIGN_SIZE > CT_MAX_ROW_SIZE - 2) { + break; + } + + if (expl_fmt_column_content(row, content, offset, (uint16)fmt_sizes[i], i) != CT_SUCCESS) { + break; + } + offset += fmt_sizes[i] + EXPL_FMT_ALIGN_SIZE; + } + content[offset] = '|'; + content[offset + 1] = '\0'; + + return CT_SUCCESS; +} + +status_t expl_fmt_explain_content(sql_stmt_t *stmt, sql_cursor_t *cursor, expl_helper_t *helper, expl_fmt_func_t fmt_func) +{ + char *row_buf = NULL; + char *content = NULL; + bool32 is_full = CT_FALSE; + mtrl_cursor_t *mtrl_cursor = &cursor->mtrl.cursor; + + CTSQL_SAVE_STACK(stmt); + CT_RETURN_IFERR(sql_push(stmt, CT_MAX_ROW_SIZE, (void **)&row_buf)); + CT_RETURN_IFERR(sql_push(stmt, CT_MAX_ROW_SIZE, (void **)&content)); + + while (1) { + CT_RETURN_IFERR(mtrl_fetch_rs(&stmt->mtrl, mtrl_cursor, CT_TRUE)); + if (mtrl_cursor->eof) { + break; + } + + CT_RETURN_IFERR(fmt_func(stmt, cursor, helper, content)); + CT_RETURN_IFERR(expl_send_explain_row(stmt, cursor, row_buf, content, &is_full)); + if (is_full) { + break; + } + } + CTSQL_RESTORE_STACK(stmt); + + return CT_SUCCESS; +} + +status_t expl_send_explain_table(sql_stmt_t *stmt, sql_cursor_t *cursor, expl_helper_t *helper) +{ + // header + CT_RETURN_IFERR(expl_send_explain_head(stmt, cursor, helper)); + if (!check_rs_page_in_segment(&stmt->mtrl, stmt->mtrl.segments[cursor->mtrl.rs.sid], cursor->mtrl.cursor.rs_vmid)) { + return CT_SUCCESS; + } + + // content + CT_RETURN_IFERR(expl_fmt_explain_content(stmt, cursor, helper, expl_fmt_table_content)); + if (!cursor->mtrl.cursor.eof) { + return CT_SUCCESS; + } + + // tail + CT_RETURN_IFERR(expl_send_explain_tail(stmt, cursor, helper)); + return CT_SUCCESS; +} + +status_t expl_init_executors(sql_stmt_t *stmt, sql_cursor_t *cursor, expl_helper_t *helper) +{ + CT_RETURN_IFERR(expl_init_expl_helper(stmt, helper, cursor->mtrl.rs.sid)); + return CT_SUCCESS; +} + +status_t expl_execute_executors(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan) +{ + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, plan, 0)); + return CT_SUCCESS; +} + +status_t expl_send_explain_rows(sql_stmt_t *stmt, sql_cursor_t *cursor, expl_helper_t *helper) +{ + CT_RETURN_IFERR(expl_send_explain_table(stmt, cursor, helper)); + return CT_SUCCESS; +} + +static status_t expl_execute_explain_plan(sql_stmt_t *stmt, sql_cursor_t *cursor, plan_node_t *plan) +{ + expl_helper_t helper = { 0 }; + + CTSQL_SAVE_STACK(stmt); + // explain-executors init + CT_RETURN_IFERR(expl_init_executors(stmt, cursor, &helper)); + + // explain-executors execute + CT_RETURN_IFERR(expl_execute_executors(stmt, &helper, plan)); + + mtrl_close_segment(&stmt->mtrl, cursor->mtrl.rs.sid); + + mtrl_open_rs_cursor(&stmt->mtrl, cursor->mtrl.rs.sid, &cursor->mtrl.cursor); + + // get explain result and write to response package + CT_RETURN_IFERR(expl_send_explain_rows(stmt, cursor, &helper)); + + CTSQL_RESTORE_STACK(stmt); + + return CT_SUCCESS; +} + +status_t expl_execute(sql_stmt_t *stmt) +{ + plan_node_t *node = (plan_node_t *)sql_get_plan(stmt); + CT_RETVALUE_IFTRUE(node == NULL,CT_ERRNO); + + sql_cursor_t *cursor = NULL; + CT_RETURN_IFERR(expl_pre_execute(stmt, &cursor)); + sql_init_ssa_cursor_maps(cursor, CT_MAX_SUBSELECT_EXPRS); + + CTSQL_SAVE_STACK(stmt); + expl_execute_explain_plan(stmt, cursor, node); + CTSQL_RESTORE_STACK(stmt); + + return CT_SUCCESS; +} + diff --git a/pkg/src/ctsql/executor/explain/expl_executor.h b/pkg/src/ctsql/executor/explain/expl_executor.h new file mode 100644 index 00000000..86ea3ca9 --- /dev/null +++ b/pkg/src/ctsql/executor/explain/expl_executor.h @@ -0,0 +1,39 @@ +/* ------------------------------------------------------------------------- + * This file is part of the Cantian project. + * Copyright (c) 2025 Huawei Technologies Co.,Ltd. + * + * Cantian is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * 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 PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * ctsql_distinct.h + * + * + * IDENTIFICATION + * src/ctsql/executor/ctsql_distinct.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __EXPL_EXECUTOR_H__ +#define __EXPL_EXECUTOR_H__ + +#include "cm_defs.h" +#include "cm_memory.h" +#include "cm_row.h" + +#include "cm_list.h" +#include "expl_plan.h" + +status_t expl_execute(sql_stmt_t *stmt); + + +#endif diff --git a/pkg/src/ctsql/executor/explain/expl_plan.c b/pkg/src/ctsql/executor/explain/expl_plan.c new file mode 100644 index 00000000..57856484 --- /dev/null +++ b/pkg/src/ctsql/executor/explain/expl_plan.c @@ -0,0 +1,539 @@ +/* ------------------------------------------------------------------------- + * This file is part of the Cantian project. + * Copyright (c) 2025 Huawei Technologies Co.,Ltd. + * + * Cantian is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * 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 PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * ctsql_distinct.h + * + * + * IDENTIFICATION + * src/ctsql/executor/ctsql_distinct.h + * + * ------------------------------------------------------------------------- + */ + +#include "cm_row.h" +#include "cm_text.h" +#include "expl_plan.h" + +#define EXPL_SGL_INDENT_SIZE 2 + +status_t expl_format_plan_node(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth); + +static inline status_t expl_row_put_text_data(expl_helper_t *helper, expl_col_type_t type, text_t *row_data) +{ + helper->fmt_sizes[type] = MAX(helper->fmt_sizes[type], row_data->len); + return row_put_text(&helper->ra, row_data); +} + +static status_t expl_format_plan_id(expl_helper_t *helper) +{ + char buff[CT_MAX_INT32_STRLEN + 1] = { 0 }; + int32 row_id = helper->row_helper.id++; + int32 len = snprintf_s(buff, CT_MAX_INT32_STRLEN + 1, CT_MAX_INT32_STRLEN, "%lld", row_id); + if (SECUREC_UNLIKELY(len == -1)) { + return CT_ERROR; + } + + text_t rowid_str = { buff, len }; + return expl_row_put_text_data(helper, EXPL_COL_TYPE_ID, &rowid_str); +} + +static status_t expl_expand_text(text_t *in, text_t *out, uint32 depth) +{ + uint32 indent_size = MIN(CT_MAX_DFLT_VALUE_LEN - 1, depth * EXPL_SGL_INDENT_SIZE); + if (indent_size != 0) { + (void)memset_s(out->str, CT_MAX_DFLT_VALUE_LEN - 1, ' ', indent_size); + } + + uint32 text_size = MIN(CT_MAX_DFLT_VALUE_LEN - indent_size - 1, in->len); + if (text_size != 0) { + (void)memcpy_s(out->str + indent_size, CT_MAX_DFLT_VALUE_LEN - indent_size - 1, in->str, text_size); + } + + out->len = indent_size + text_size; + + return CT_SUCCESS; +} + +static status_t expl_format_plan_operation(expl_helper_t *helper) +{ + status_t ret = expl_expand_text(helper->row_helper.operation, &helper->tmp_buf, helper->depth); + if (ret != CT_SUCCESS) { + // todo : errlog... + return ret; + } + + return expl_row_put_text_data(helper, EXPL_COL_TYPE_OPERATION, &helper->tmp_buf); +} + +static status_t expl_format_plan_owner(expl_helper_t *helper) +{ + if (helper->row_helper.owner == NULL) { + return row_put_null(&helper->ra); + } + + return expl_row_put_text_data(helper, EXPL_COL_TYPE_OWNER, helper->row_helper.owner); +} + +static status_t expl_format_plan_name(expl_helper_t *helper) +{ + row_helper_t *row_helper = &helper->row_helper; + if (row_helper->name == NULL && row_helper->alias == NULL) { + return row_put_null(&helper->ra); + } + + char buff[CT_MAX_DFLT_VALUE_LEN] = { 0 }; + text_t *name = row_helper->name; + uint32 offset = 0; + if (name != NULL && name->str != NULL && name->len > 0) { + MEMS_RETURN_IFERR(memcpy_s(buff, CT_MAX_DFLT_VALUE_LEN, name->str, name->len)); + offset = name->len; + } + + text_t *alias = row_helper->alias; + if (alias != NULL && alias->str != NULL && alias->len > 0) { + if (offset != 0) { + MEMS_RETURN_IFERR(memcpy_s(buff + offset, CT_MAX_DFLT_VALUE_LEN - offset, " ", 1)); + offset++; + } + MEMS_RETURN_IFERR(memcpy_s(buff + offset, CT_MAX_DFLT_VALUE_LEN - offset, alias->str, alias->len)); + offset += alias->len; + } + + text_t new_name = { buff, offset }; + return expl_row_put_text_data(helper, EXPL_COL_TYPE_TABLE, &new_name); +} + +static status_t expl_format_plan_rows(expl_helper_t *helper) +{ + if (!(CBO_ON)) { + return row_put_null(&helper->ra); + } + + char buff[CT_MAX_INT64_STRLEN + 1] = { 0 }; + int32 len = snprintf_s(buff, CT_MAX_INT64_STRLEN + 1, CT_MAX_INT64_STRLEN, "%lld", helper->row_helper.rows); + if (SECUREC_UNLIKELY(len == -1)) { + return CT_ERROR; + } + + text_t rows_str = { buff, len }; + return expl_row_put_text_data(helper, EXPL_COL_TYPE_ROWS, &rows_str); +} + +static status_t expl_format_plan_cost(expl_helper_t *helper) +{ + if (!(CBO_ON)) { + return row_put_null(&helper->ra); + } + + char buff[CT_MAX_INT64_STRLEN + 1] = { 0 }; + int64 cost = (int64)helper->row_helper.cost; + int32 len = snprintf_s(buff, CT_MAX_INT64_STRLEN + 1, CT_MAX_INT64_STRLEN, "%lld", cost); + if (SECUREC_UNLIKELY(len == -1)) { + return CT_ERROR; + } + + text_t cost_str = { buff, len }; + return expl_row_put_text_data(helper, EXPL_COL_TYPE_COST, &cost_str); +} + +static status_t expl_format_plan_bytes(expl_helper_t *helper) +{ + return row_put_null(&helper->ra); +} + +static status_t expl_format_plan_remarks(expl_helper_t *helper) +{ + return row_put_null(&helper->ra); +} + +expl_column_t g_expl_columns[] = { + { EXPL_COL_TYPE_ID, {"Id", 2}, 4, expl_format_plan_id }, + { EXPL_COL_TYPE_OPERATION, {"Operation", 9}, 20, expl_format_plan_operation }, + { EXPL_COL_TYPE_OWNER, {"Owner", 5}, 10, expl_format_plan_owner }, + { EXPL_COL_TYPE_TABLE, {"Name", 4}, 10, expl_format_plan_name }, + { EXPL_COL_TYPE_ROWS, {"Rows", 4}, 10, expl_format_plan_rows }, + { EXPL_COL_TYPE_COST, {"Cost", 4}, 10, expl_format_plan_cost }, + { EXPL_COL_TYPE_BYTES, {"Bytes", 5}, 10, expl_format_plan_bytes }, + { EXPL_COL_TYPE_REMARK, {"Remark", 6}, 10, expl_format_plan_remarks } +}; + +text_t *expl_get_explcol_name(uint32 idx) +{ + if (idx >= EXPL_COL_TYPE_MAX) { + return NULL; + } + return &g_expl_columns[idx].name; +} + +void row_helper_init(row_helper_t *helper, plan_node_t *plan, text_t *operation, text_t *owner, text_t *name, + text_t *alias) +{ + helper->operation = operation; + helper->owner = owner; + helper->name = name; + helper->alias = alias; + + helper->rows = plan->rows; + helper->cost = plan->cost; +} + +void expl_helper_init(expl_helper_t *helper) +{ + (void)memset_s(helper, sizeof(expl_helper_t), 0, sizeof(expl_helper_t)); + for (int32 i = 0; i < EXPL_COL_TYPE_MAX; i++) { + helper->fmt_sizes[i] = g_expl_columns[i].fmt_size; + } +} + +status_t expl_format_plan_node_row(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth, char *oper_str, + text_t *owner, text_t *name, text_t *alias) +{ + text_t oper = { oper_str, strlen(oper_str) }; + helper->depth = depth; + row_helper_init(&helper->row_helper, plan, &oper, owner, name, alias); + row_init(&helper->ra, helper->row_buf, CT_MAX_ROW_SIZE, EXPL_COL_TYPE_MAX); + + for (int32 i = 0; i < EXPL_COL_TYPE_MAX; i++) { + expl_column_func_t expl_column_func = g_expl_columns[i].expl_column_func; + CT_RETURN_IFERR(expl_column_func(helper)); + } + return mtrl_insert_row(&stmt->mtrl, helper->mtrl_id, helper->row_buf, &helper->row_id); +} + +status_t expl_format_expr_node_plan(visit_assist_t *va, expr_node_t **node) +{ + expl_helper_t *helper = (expl_helper_t *)va->param0; + if ((*node)->type != EXPR_NODE_SELECT) { + return CT_SUCCESS; + } + + va->result0 = CT_TRUE; + // Just to obtain whether there is a selectstatement in the expr + if (va->result1 == CT_FALSE) { + return CT_SUCCESS; + } + uint32 ssa_id = (*node)->value.v_obj.id; + sql_select_t *select = (sql_select_t *)sql_array_get(helper->ssa, ssa_id); + plan_node_t *plan = select->plan; + + if (plan->type != PLAN_NODE_SELECT || plan == sql_get_plan(va->stmt)) { + return CT_SUCCESS; + } + return expl_format_plan_node(va->stmt, helper, plan->select_p.next, va->result2); +} + +status_t expl_format_expr_tree_plan(sql_stmt_t *stmt, expl_helper_t *helper, expr_tree_t *expr, uint32 depth) +{ + visit_assist_t va = {0}; + sql_init_visit_assist(&va, stmt, NULL); + va.excl_flags = VA_EXCL_PRIOR; + va.param0 = (void *)helper; + va.result0 = CT_FALSE; // selectstatement in the expr + va.result1 = CT_TRUE; // TRUE: execute, FALSE: not execute + va.result2 = depth; + + return visit_expr_tree(&va, expr, expl_format_expr_node_plan); +} + +status_t expl_format_cond_node_plan(sql_stmt_t *stmt, expl_helper_t *helper, cond_node_t *cond, uint32 depth, + bool32 *has_select) +{ + visit_assist_t va = {0}; + sql_init_visit_assist(&va, stmt, NULL); + va.excl_flags = VA_EXCL_PRIOR; + va.param0 = (void *)helper; + va.result0 = CT_FALSE; // selectstatement in the expr + va.result1 = (has_select == NULL); // TRUE: execute, FALSE: not execute; + va.result2 = depth; + + CT_RETURN_IFERR(visit_cond_node(&va, cond, expl_format_expr_node_plan)); + if (has_select != NULL) { + *has_select = va.result0; + } + + return CT_SUCCESS; +} + +status_t expl_format_default_plan_node(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return CT_SUCCESS; +} + +status_t expl_format_rs_col_plan(sql_stmt_t *stmt, expl_helper_t *helper, sql_query_t *query, uint32 depth) +{ + rs_column_t *rs_col = NULL; + for (uint32 i = 0; i < query->rs_columns->count; i++) { + rs_col = (rs_column_t *)cm_galist_get(query->rs_columns, i); + if (rs_col->type != RS_COL_CALC) { + continue; + } + CT_RETURN_IFERR(expl_format_expr_tree_plan(stmt, helper, rs_col->expr, depth)); + } + return CT_SUCCESS; +} + +status_t expl_format_query_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + // store + sql_query_t *query = helper->query; + sql_array_t *ssa = helper->ssa; + + // current node iter info + helper->query = plan->query.ref; + helper->ssa = &plan->query.ref->ssa; + + CT_RETURN_IFERR(expl_format_rs_col_plan(stmt, helper, plan->query.ref, depth)); + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, plan->query.next, depth)); + + // restore + helper->ssa = ssa; + helper->query = query; + + return CT_SUCCESS; +} + +status_t expl_format_select_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + bool32 is_subselect = (sql_get_plan(stmt) != plan); + char *oper = is_subselect ? "SUBSELECT" : "SELECT STATEMENT"; + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, NULL, NULL, NULL)); + + return expl_format_plan_node(stmt, helper, plan->select_p.next, depth + 1); +} + +status_t expl_format_user_rowid_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + // todo + sql_table_t *table = plan->scan_p.table; + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS BY ROWID", + &table->user.value, &table->name.value, &table->alias.value)); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth + 1, "ROWID SCAN", + &table->user.value, &table->name.value, &table->alias.value)); + // todo + return CT_SUCCESS; +} + +status_t expl_format_normal_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + text_t owner = {0}; + text_t name = {0}; + sql_table_t *table = plan->scan_p.table; + knl_dictionary_t *dc = &table->entry->dc; + + if ((dc->is_sysnonym == CT_TRUE) && (dc->type == DICT_TYPE_TABLE || + dc->type == DICT_TYPE_TEMP_TABLE_TRANS || + dc->type == DICT_TYPE_TEMP_TABLE_SESSION || + dc->type == DICT_TYPE_TABLE_NOLOGGING)) { + dc_entry_t *entry = DC_ENTRY(dc); + owner.str = entry->user->desc.name; + owner.len = (uint32)strlen(owner.str); + name.str = entry->name; + name.len = (uint32)strlen(name.str); + } else { + owner = *(text_t *)&plan->scan_p.table->user; + name = *(text_t *)&plan->scan_p.table->name; + } + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS FULL", + &table->user.value, &table->name.value, &table->alias.value)); + return CT_SUCCESS; +} + +status_t expl_format_view_as_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + sql_table_t *table = plan->scan_p.table; + plan_node_t *select_plan = table->select_ctx->plan; + plan_node_t *next_plan = select_plan->select_p.next; + + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "VIEW", + &table->user.value, &table->name.value, &table->alias.value)); + + return expl_format_plan_node(stmt, helper, next_plan, depth + 1); +} + +status_t expl_format_subselect_as_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + char *oper = NULL; + plan_node_t *next_plan = NULL; + sql_table_t *table = plan->scan_p.table; + plan_node_t *select_plan = table->select_ctx->plan; + + if (select_plan->select_p.next->type == PLAN_NODE_VM_VIEW_MTRL) { + oper = "VN VIEW"; + next_plan = select_plan->select_p.next->vm_view_p.next; + } else { + oper = "SUBSELECT"; + next_plan = select_plan->select_p.next; + } + + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, + &table->user.value, &table->name.value, &table->alias.value)); + + return expl_format_plan_node(stmt, helper, next_plan, depth + 1); +} + +status_t expl_format_func_as_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + sql_table_t *table = plan->scan_p.table; + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS FULL", + &table->user.value, &table->name.value, &table->alias.value)); + return CT_SUCCESS; +} + +status_t expl_format_with_as_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + sql_table_t *table = plan->scan_p.table; + plan_node_t *select_plan = table->select_ctx->plan; + + if (select_plan->select_p.next->type == PLAN_NODE_WITHAS_MTRL) { + withas_mtrl_plan_t *withas_p = &select_plan->select_p.next->withas_p; + return expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS FULL", + NULL, &withas_p->name, &table->alias.value); + } + + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS FULL", + &table->user.value, &table->name.value, &table->alias.value)); + return CT_SUCCESS; +} + +status_t expl_format_scan_plan_deep(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + sql_table_t *table = plan->scan_p.table; + + if (plan->scan_p.rowid_set != NULL && plan->scan_p.rowid_set->type == RANGE_LIST_NORMAL) { + return expl_format_user_rowid_scan_plan(stmt, helper, plan, depth); + } else if (plan->scan_p.table->index != NULL) { + // todo: index scan + return CT_SUCCESS; + } + + sql_table_type_t type = table->type; + switch (type) { + case NORMAL_TABLE: + return expl_format_normal_table_scan_plan(stmt, helper, plan, depth); + case VIEW_AS_TABLE: + return expl_format_view_as_table_scan_plan(stmt, helper, plan, depth); + case SUBSELECT_AS_TABLE: + return expl_format_subselect_as_table_scan_plan(stmt, helper, plan, depth); + case FUNC_AS_TABLE: + return expl_format_func_as_table_scan_plan(stmt, helper, plan, depth); + case JOIN_AS_TABLE: + return expl_format_normal_table_scan_plan(stmt, helper, plan, depth); + case WITH_AS_TABLE: + return expl_format_with_as_table_scan_plan(stmt, helper, plan, depth); + case JSON_TABLE: + return expl_format_func_as_table_scan_plan(stmt, helper, plan, depth); + } + return CT_SUCCESS; +} + +status_t expl_format_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + sql_query_t *query = helper->query; + sql_table_t *table = plan->scan_p.table; + bool32 has_subselect = CT_FALSE; + bool32 has_indx_subselect = CT_FALSE; + + if (query != NULL && query->cond != NULL) { + CT_RETURN_IFERR(expl_format_cond_node_plan(stmt, helper, query->cond->root, depth, &has_subselect)); + } + if (table != NULL && table->index_cond_pruning) { + CT_RETURN_IFERR(expl_format_cond_node_plan(stmt, helper, table->cond->root, depth, &has_indx_subselect)); + } + if (has_subselect || has_indx_subselect) { + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth++, "KERNEL FILTER", NULL, NULL, NULL)); + } + + CT_RETURN_IFERR(expl_format_scan_plan_deep(stmt, helper, plan, depth)); + + if (has_subselect) { + CT_RETURN_IFERR(expl_format_cond_node_plan(stmt, helper, query->cond->root, depth, NULL)); + } + if (has_indx_subselect) { + CT_RETURN_IFERR(expl_format_cond_node_plan(stmt, helper, table->cond->root, depth, NULL)); + } + + return CT_SUCCESS; +} + +status_t expl_format_union_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + // pass througth + return CT_SUCCESS; +} + +status_t expl_format_union_all_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + // pass througth + return CT_SUCCESS; +} + +static expl_plan_t g_expl_plan_funcs[] = { + { PLAN_NODE_QUERY, expl_format_query_plan }, + { PLAN_NODE_UNION, expl_format_union_plan }, + { PLAN_NODE_UNION_ALL, expl_format_union_all_plan }, + { PLAN_NODE_MINUS, expl_format_default_plan_node }, + { PLAN_NODE_HASH_MINUS, expl_format_default_plan_node }, + { PLAN_NODE_MERGE, expl_format_default_plan_node }, + { PLAN_NODE_INSERT, expl_format_default_plan_node }, + { PLAN_NODE_DELETE, expl_format_default_plan_node }, + { PLAN_NODE_UPDATE, expl_format_default_plan_node }, + { PLAN_NODE_SELECT, expl_format_select_plan }, + { PLAN_NODE_JOIN, expl_format_default_plan_node }, + { PLAN_NODE_SORT_GROUP, expl_format_default_plan_node }, + { PLAN_NODE_MERGE_SORT_GROUP, expl_format_default_plan_node }, + { PLAN_NODE_HASH_GROUP, expl_format_default_plan_node }, + { PLAN_NODE_INDEX_GROUP, expl_format_default_plan_node }, + { PLAN_NODE_QUERY_SORT, expl_format_default_plan_node }, + { PLAN_NODE_SELECT_SORT, expl_format_default_plan_node }, + { PLAN_NODE_AGGR, expl_format_default_plan_node }, + { PLAN_NODE_INDEX_AGGR, expl_format_default_plan_node }, + { PLAN_NODE_SORT_DISTINCT, expl_format_default_plan_node }, + { PLAN_NODE_HASH_DISTINCT, expl_format_default_plan_node }, + { PLAN_NODE_INDEX_DISTINCT, expl_format_default_plan_node }, + { PLAN_NODE_HAVING, expl_format_default_plan_node }, + { PLAN_NODE_SCAN, expl_format_scan_plan }, + { PLAN_NODE_QUERY_LIMIT, expl_format_default_plan_node }, + { PLAN_NODE_SELECT_LIMIT, expl_format_default_plan_node }, + { PLAN_NODE_CONNECT, expl_format_default_plan_node }, + { PLAN_NODE_FILTER, expl_format_default_plan_node }, + { PLAN_NODE_WINDOW_SORT, expl_format_default_plan_node }, + { PLAN_NODE_REMOTE_SCAN, expl_format_default_plan_node }, + { PLAN_NODE_GROUP_MERGE, expl_format_default_plan_node }, + { PLAN_NODE_HASH_GROUP_PAR, expl_format_default_plan_node }, + { PLAN_NODE_HASH_MTRL, expl_format_default_plan_node }, + { PLAN_NODE_CONCATE, expl_format_default_plan_node }, + { PLAN_NODE_QUERY_SORT_PAR, expl_format_default_plan_node }, + { PLAN_NODE_QUERY_SIBL_SORT, expl_format_default_plan_node }, + { PLAN_NODE_GROUP_CUBE, expl_format_default_plan_node }, + { PLAN_NODE_HASH_GROUP_PIVOT, expl_format_default_plan_node }, + { PLAN_NODE_UNPIVOT, expl_format_default_plan_node }, + { PLAN_NODE_ROWNUM, expl_format_default_plan_node }, + { PLAN_NODE_FOR_UPDATE, expl_format_default_plan_node }, + { PLAN_NODE_WITHAS_MTRL, expl_format_default_plan_node }, + { PLAN_NODE_CONNECT_MTRL, expl_format_default_plan_node }, + { PLAN_NODE_CONNECT_HASH, expl_format_default_plan_node }, + { PLAN_NODE_VM_VIEW_MTRL, expl_format_default_plan_node } +}; + +status_t expl_format_plan_node(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + CM_ASSERT(plan->type <= sizeof(g_expl_plan_funcs)/sizeof(expl_plan_t)); + CM_ASSERT(plan->type == g_expl_plan_funcs[plan->type - PLAN_NODE_QUERY].type); + CM_ASSERT(g_expl_plan_funcs[plan->type - PLAN_NODE_QUERY].explain_plan_func != NULL); + + return g_expl_plan_funcs[plan->type - PLAN_NODE_QUERY].explain_plan_func(stmt, helper, plan, depth); +} + diff --git a/pkg/src/ctsql/executor/explain/expl_plan.h b/pkg/src/ctsql/executor/explain/expl_plan.h new file mode 100644 index 00000000..097f2da2 --- /dev/null +++ b/pkg/src/ctsql/executor/explain/expl_plan.h @@ -0,0 +1,105 @@ +/* ------------------------------------------------------------------------- + * This file is part of the Cantian project. + * Copyright (c) 2025 Huawei Technologies Co.,Ltd. + * + * Cantian is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * 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 PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * ctsql_distinct.h + * + * + * IDENTIFICATION + * src/ctsql/executor/ctsql_distinct.h + * + * ------------------------------------------------------------------------- + */ + + #ifndef __EXPL_PLAN_H__ + #define __EXPL_PLAN_H__ + +#include "cm_memory.h" +#include "cm_row.h" +#include "cm_defs.h" +#include "cm_list.h" +#include "ctsql_plan_defs.h" +#include "ctsql_stmt.h" +#include "srv_instance.h" + +typedef enum { + EXPL_COL_TYPE_ID, + EXPL_COL_TYPE_OPERATION, + EXPL_COL_TYPE_OWNER, + EXPL_COL_TYPE_TABLE, + EXPL_COL_TYPE_ROWS, + EXPL_COL_TYPE_COST, + EXPL_COL_TYPE_BYTES, + EXPL_COL_TYPE_REMARK, + EXPL_COL_TYPE_MAX +} expl_col_type_t; + +typedef struct st_row_helper { + int32 id; // Id + text_t *operation; // Operation + text_t *owner; // Owner + text_t *name; // Table name + text_t *alias; // Table name alias + int64 rows; // Rows + double cost; // Cost + int64 bytes; // bytes + int64 remark; // remark +} row_helper_t; + +typedef struct st_expl_helper { + mtrl_rowid_t row_id; + uint32 mtrl_id; + + row_assist_t ra; + char *row_buf; + text_t tmp_buf; // for operation + + row_helper_t row_helper; // for format; + uint32 fmt_sizes[EXPL_COL_TYPE_MAX]; // format sizes for every column + int32 depth; // depth + + sql_cursor_t *cursor; + sql_query_t *query; // reference sql query context + sql_array_t *ssa; // SubSelect Array for subselect expr + + // format + uint32 width; +} expl_helper_t; + +typedef status_t (*expl_column_func_t)(expl_helper_t *helper); + +typedef struct st_expl_column { + expl_col_type_t type; + text_t name; + uint32 fmt_size; // default format size + expl_column_func_t expl_column_func; +} expl_column_t; + + +typedef status_t (*expl_plan_func_t)(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth); + +typedef struct st_expl_plan { + plan_node_type_t type; + //text_t operation; // default operation; + expl_plan_func_t explain_plan_func; +} expl_plan_t; + +typedef status_t (*expl_fmt_func_t)(sql_stmt_t *stmt, sql_cursor_t *cursor, expl_helper_t *helper, char *content); + +void expl_helper_init(expl_helper_t *helper); +text_t *expl_get_explcol_name(uint32 idx); +status_t expl_format_plan_node(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth); + +#endif diff --git a/pkg/src/ctsql/parser/ctsql_parser.c b/pkg/src/ctsql/parser/ctsql_parser.c index c1eaf7ae..c3869538 100644 --- a/pkg/src/ctsql/parser/ctsql_parser.c +++ b/pkg/src/ctsql/parser/ctsql_parser.c @@ -280,26 +280,23 @@ lang_type_t sql_diag_lang_type(sql_stmt_t *stmt, sql_text_t *sql, word_t *leader } } +sql_parser_t g_sql_parser[] = { + {LANG_DML, sql_parse_dml}, + {LANG_DCL, sql_parse_dcl}, + {LANG_DDL, sql_parse_ddl}, + {LANG_PL, sql_parse_pl}, + {LANG_PL, sql_parse_explain} +}; + static status_t sql_parse_by_lang_type(sql_stmt_t *stmt, sql_text_t *sql_text, word_t *leader_word) { status_t status; - switch (stmt->lang_type) { - case LANG_DML: - status = sql_parse_dml(stmt, leader_word->id); - break; - case LANG_DDL: - status = sql_parse_ddl(stmt, leader_word->id); - break; - case LANG_DCL: - status = sql_parse_dcl(stmt, leader_word->id); - break; - case LANG_PL: - status = sql_parse_pl(stmt, leader_word); - break; - default: - CT_SRC_THROW_ERROR(sql_text->loc, ERR_SQL_SYNTAX_ERROR, "key word expected"); - status = CT_ERROR; + if (stmt->lang_type < LANG_MAX && stmt->lang_type != LANG_INVALID) { + status = g_sql_parser[stmt->lang_type - LANG_DML].sql_parse(stmt, leader_word); + } else { + CT_SRC_THROW_ERROR(sql_text->loc, ERR_SQL_SYNTAX_ERROR, "key word expected"); + status = CT_ERROR; } text_t sql_log_text = stmt->session->sql_audit.sql; diff --git a/pkg/src/ctsql/parser/ctsql_parser.h b/pkg/src/ctsql/parser/ctsql_parser.h index 457a2c97..a8e5b7fd 100644 --- a/pkg/src/ctsql/parser/ctsql_parser.h +++ b/pkg/src/ctsql/parser/ctsql_parser.h @@ -33,10 +33,11 @@ extern "C" { #endif +typedef status_t (*sql_parse_stmt)(sql_stmt_t *stmt, word_t *leader); + typedef struct st_sql_parser { - memory_context_t *context; - text_t user; - lex_t lex; + lang_type_t type; + sql_parse_stmt sql_parse; } sql_parser_t; status_t sql_parse(sql_stmt_t *stmt, text_t *sql, source_location_t *loc); diff --git a/pkg/src/ctsql/parser/dcl_parser.c b/pkg/src/ctsql/parser/dcl_parser.c index d38f4ec8..a9b5241b 100644 --- a/pkg/src/ctsql/parser/dcl_parser.c +++ b/pkg/src/ctsql/parser/dcl_parser.c @@ -915,9 +915,10 @@ status_t sql_parse_route(sql_stmt_t *stmt) } #endif -status_t sql_parse_dcl(sql_stmt_t *stmt, key_wid_t key_wid) +status_t sql_parse_dcl(sql_stmt_t *stmt, word_t *leader_word) { status_t status; + key_wid_t key_wid = leader_word->id; stmt->session->sql_audit.audit_type = SQL_AUDIT_DCL; status = sql_alloc_context(stmt); diff --git a/pkg/src/ctsql/parser/dcl_parser.h b/pkg/src/ctsql/parser/dcl_parser.h index 76d5732b..da74c057 100644 --- a/pkg/src/ctsql/parser/dcl_parser.h +++ b/pkg/src/ctsql/parser/dcl_parser.h @@ -29,7 +29,7 @@ extern "C" { #endif -status_t sql_parse_dcl(sql_stmt_t *stmt, key_wid_t key_wid); +status_t sql_parse_dcl(sql_stmt_t *stmt, word_t *leader_word); #ifdef __cplusplus } diff --git a/pkg/src/ctsql/parser/dml_parser.c b/pkg/src/ctsql/parser/dml_parser.c index 9c927bd8..9ca4cae5 100644 --- a/pkg/src/ctsql/parser/dml_parser.c +++ b/pkg/src/ctsql/parser/dml_parser.c @@ -337,8 +337,9 @@ status_t sql_parse_anonymous_directly(sql_stmt_t *stmt, word_t *leader, sql_text return CT_SUCCESS; } -status_t sql_parse_dml(sql_stmt_t *stmt, key_wid_t key_wid) +status_t sql_parse_dml(sql_stmt_t *stmt, word_t *leader_word) { + key_wid_t key_wid = leader_word->id; CT_LOG_DEBUG_INF("Begin parse DML, SQL = %s", T2S(&stmt->session->lex->text.value)); cm_atomic_inc(&g_instance->library_cache_info[stmt->lang_type].hits); // maybe need load entity from proc$ @@ -352,6 +353,23 @@ status_t sql_parse_dml(sql_stmt_t *stmt, key_wid_t key_wid) return CT_SUCCESS; } +status_t sql_parse_explain(sql_stmt_t *stmt, word_t *leader_word) +{ + lex_t *lex = stmt->session->lex; + sql_text_t *sql = lex->curr_text; + + CT_RETURN_IFERR(lex_skip_comments(lex, NULL)); + + stmt->lang_type = sql_diag_lang_type(stmt, sql, leader_word); + if (stmt->lang_type != LANG_DML) { + CT_LOG_DEBUG_ERR("the type: %d can not explain", stmt->lang_type); + return CT_ERROR; + } + status_t ret = sql_parse_dml(stmt, leader_word); + stmt->is_explain = CT_TRUE; + return ret; +} + status_t sql_create_rowid_rs_column(sql_stmt_t *stmt, uint32 id, sql_table_type_t type, galist_t *list) { rs_column_t *rs_column = NULL; diff --git a/pkg/src/ctsql/parser/dml_parser.h b/pkg/src/ctsql/parser/dml_parser.h index 9241b4cd..0fda96d7 100644 --- a/pkg/src/ctsql/parser/dml_parser.h +++ b/pkg/src/ctsql/parser/dml_parser.h @@ -50,7 +50,8 @@ typedef enum en_sql_special_word { } sql_special_word_t; status_t sql_create_list(sql_stmt_t *stmt, galist_t **list); -status_t sql_parse_dml(sql_stmt_t *stmt, key_wid_t key_wid); +status_t sql_parse_dml(sql_stmt_t *stmt, word_t *leader_word); +status_t sql_parse_explain(sql_stmt_t *stmt, word_t *leader); status_t sql_parse_view_subselect(sql_stmt_t *stmt, text_t *sql, sql_select_t **select_ctx, source_location_t *loc); bool32 sql_has_ltt(sql_stmt_t *stmt, text_t *sql_text); bool32 sql_check_ctx(sql_stmt_t *stmt, sql_context_t *ctx); diff --git a/pkg/src/ctsql/parser_ddl/ddl_parser.c b/pkg/src/ctsql/parser_ddl/ddl_parser.c index d175efdf..5bc8ea73 100644 --- a/pkg/src/ctsql/parser_ddl/ddl_parser.c +++ b/pkg/src/ctsql/parser_ddl/ddl_parser.c @@ -809,15 +809,16 @@ status_t sql_parse_comment(sql_stmt_t *stmt) return status; } -status_t sql_parse_ddl(sql_stmt_t *stmt, key_wid_t wid) +status_t sql_parse_ddl(sql_stmt_t *stmt, word_t *leader_word) { status_t status; + key_wid_t key_wid = leader_word->id; text_t origin_sql = stmt->session->lex->text.value; stmt->session->sql_audit.audit_type = SQL_AUDIT_DDL; CT_RETURN_IFERR(sql_alloc_context(stmt)); CT_RETURN_IFERR(sql_create_list(stmt, &stmt->context->ref_objects)); - switch (wid) { + switch (key_wid) { case KEY_WORD_CREATE: status = sql_parse_create(stmt); break; diff --git a/pkg/src/ctsql/parser_ddl/ddl_parser.h b/pkg/src/ctsql/parser_ddl/ddl_parser.h index 9b08e0e5..88ed191e 100644 --- a/pkg/src/ctsql/parser_ddl/ddl_parser.h +++ b/pkg/src/ctsql/parser_ddl/ddl_parser.h @@ -55,7 +55,7 @@ typedef struct st_seqence_info { bool32 nocyc_flag; } sql_seqence_info_t; -status_t sql_parse_ddl(sql_stmt_t *stmt, key_wid_t wid); +status_t sql_parse_ddl(sql_stmt_t *stmt, word_t *leader_word); status_t sql_parse_drop(sql_stmt_t *sql_stmt); status_t sql_parse_truncate(sql_stmt_t *stmt); status_t sql_parse_flashback(sql_stmt_t *stmt); -- Gitee From 0156211376373b12f17f4326aa776ee8316e0ca1 Mon Sep 17 00:00:00 2001 From: lys <120677277@qq.com> Date: Mon, 10 Mar 2025 14:48:33 +0800 Subject: [PATCH 03/12] optimize logically framework --- build/include/config.h | 2 +- pkg/src/ctsql/optimizer/ctsql_transform.c | 125 ++++++++++++++++++++++ pkg/src/ctsql/optimizer/ctsql_transform.h | 23 +++- pkg/src/ctsql/parser/dml_parser.c | 4 + 4 files changed, 151 insertions(+), 3 deletions(-) diff --git a/build/include/config.h b/build/include/config.h index 33e36cf9..44986f4b 100644 --- a/build/include/config.h +++ b/build/include/config.h @@ -12,4 +12,4 @@ #define DD_GETDBVERSION cantiand_get_dbversion #define DD_GETENCRYVERSION ctencrypt_getDBVersion #define DD_CT_LIB_VER_APINAME ctconn_get_dbversion -#define DD_GETCTSQLVERSION ctsql_get_dbversion \ No newline at end of file +#define DD_GETCTSQLVERSION ctsql_get_dbversion diff --git a/pkg/src/ctsql/optimizer/ctsql_transform.c b/pkg/src/ctsql/optimizer/ctsql_transform.c index 095f784c..cb370683 100644 --- a/pkg/src/ctsql/optimizer/ctsql_transform.c +++ b/pkg/src/ctsql/optimizer/ctsql_transform.c @@ -37,6 +37,17 @@ extern "C" { #endif + +static transform_sql_t g_transformers[] = { + {CTSQL_TYPE_NONE, sql_transform_dummy }, + {CTSQL_TYPE_SELECT, ctsql_optimize_logic_select }, + {CTSQL_TYPE_UPDATE, sql_transform_dummy }, + {CTSQL_TYPE_INSERT, sql_transform_dummy }, + {CTSQL_TYPE_DELETE, sql_transform_dummy }, + {CTSQL_TYPE_MERGE, sql_transform_dummy }, + {CTSQL_TYPE_REPLACE, sql_transform_dummy }, + }; + typedef status_t (*sql_optimizer_func_t)(sql_stmt_t *stmt, sql_query_t *query); typedef struct st_sql_optimizer { @@ -44,6 +55,16 @@ typedef struct st_sql_optimizer { sql_optimizer_func_t optimizer; } sql_optimizer_t; +status_t sql_transform_dummy(sql_stmt_t *stmt, void *entry) +{ + text_t *ctsql = (text_t *)&stmt->session->lex->text; + if (ctsql) { + CT_LOG_DEBUG_INF("transfrom sql nothing to do, SQL is %s.", T2S(ctsql)); + } + + return CT_SUCCESS; +} + status_t create_new_table_4_rewrite(sql_stmt_t *stmt, sql_query_t *query, sql_select_t *subslct) { sql_table_t *table = NULL; @@ -343,6 +364,110 @@ status_t sql_set_old_query_block_name(sql_stmt_t *stmt, sql_query_t *query, new_ return CT_SUCCESS; } +status_t ctsql_optimize_logically(sql_stmt_t *stmt) +{ + uint32 count = sizeof(g_transformers) / sizeof(transform_sql_t) - 1; + uint32 index = (uint32)stmt->context->type; + // SAVE_AND_RESET_NODE_STACK(stmt); + if (index <= count) { + CT_RETURN_IFERR(g_transformers[index].tranform(stmt, stmt->context->entry)); + } + // SQL_RESTORE_NODE_STACK(stmt); + return CT_SUCCESS; +} + +status_t ctsql_transform_one_rule(sql_stmt_t *stmt, sql_query_t *query, const char* rule_name, + sql_tranform_rule_func_t proc) +{ + if (proc(stmt, query) == CT_SUCCESS) { + CT_LOG_DEBUG_INF("Succeed to transform rule:%s", rule_name); + return CT_SUCCESS; + } + return CT_ERROR; +} + +// predicate delivery +status_t ct_transf_predicate_delivery(sql_stmt_t *stmt, sql_query_t *query) +{ + return CT_SUCCESS; +} + +status_t ctsql_apply_rule_set(sql_stmt_t *stmt, sql_query_t *query) +{ + // 1. transform to delete unusable orderby. + // transform predicate delivery. + CTSQL_APPLY_RULE(stmt, query, ct_transf_predicate_delivery); + return CT_SUCCESS; +} + +status_t ctsql_tranform_subselect_in_expr(sql_stmt_t *stmt, sql_query_t *query) +{ + sql_array_t *ssa = &query->ssa; + sql_select_t *select = NULL; + uint32 index = 0; + while (index < ssa->count) { + select = (sql_select_t*)sql_array_get(ssa, index++); + CT_RETURN_IFERR(ctsql_optimize_logic_select_node(stmt, select->root)); + } + + return CT_SUCCESS; +} + +static inline bool32 ctsql_check_subselect_if_as_table(sql_table_t *table) +{ + if ((table->type == SUBSELECT_AS_TABLE || table->type == VIEW_AS_TABLE) + && table->subslct_tab_usage == SUBSELECT_4_NORMAL_JOIN) { + return CT_TRUE; + } + + return CT_FALSE; +} +status_t ctsql_tranform_subselect_as_table(sql_stmt_t *stmt, sql_query_t *query) +{ + sql_array_t *tables = &query->tables; + sql_table_t *tab = NULL; + uint32 index = 0; + while (index < tables->count) { + tab = (sql_table_t*)sql_array_get(tables, index++); + if (ctsql_check_subselect_if_as_table(tab)) { + CT_RETURN_IFERR(ctsql_optimize_logic_select_node(stmt, tab->select_ctx->root)); + } + } + + return CT_SUCCESS; +} + +status_t ctsql_transform_query(sql_stmt_t *stmt, sql_query_t *query) +{ + + if (ctsql_apply_rule_set(stmt, query)) { + CT_LOG_DEBUG_ERR("Failed to apply rule set."); + return CT_ERROR; + } + + // transform subselect in expressions. + CT_RETURN_IFERR(ctsql_tranform_subselect_in_expr(stmt, query)); + // transform subselect in 'from table'. + CT_RETURN_IFERR(ctsql_tranform_subselect_as_table(stmt, query)); + + return CT_SUCCESS; +} + +status_t ctsql_optimize_logic_select_node(sql_stmt_t *stmt, select_node_t *node) +{ + if (node->type == SELECT_NODE_QUERY) { + return ctsql_transform_query(stmt, node->query); + } + CT_RETURN_IFERR(ctsql_optimize_logic_select_node(stmt, node->left)); + return ctsql_optimize_logic_select_node(stmt, node->right); +} + +status_t ctsql_optimize_logic_select(sql_stmt_t *stmt, void *entry) +{ + select_node_t *node = ((sql_select_t*)entry)->root; + return ctsql_optimize_logic_select_node(stmt, node); +} + #ifdef __cplusplus } #endif diff --git a/pkg/src/ctsql/optimizer/ctsql_transform.h b/pkg/src/ctsql/optimizer/ctsql_transform.h index d2bed9ac..caf93211 100644 --- a/pkg/src/ctsql/optimizer/ctsql_transform.h +++ b/pkg/src/ctsql/optimizer/ctsql_transform.h @@ -65,6 +65,17 @@ extern "C" { #define SQL_IS_DUAL_TABLE(table) \ ((table)->type == NORMAL_TABLE && (table)->entry->dc.oid == 10 && (table)->entry->dc.uid == 0) +typedef status_t (*sql_tranform_rule_func_t)(sql_stmt_t *stmt, sql_query_t *query); +status_t ctsql_transform_one_rule(sql_stmt_t *stmt, sql_query_t *query, const char* rule_name, + sql_tranform_rule_func_t proc); + +#define CTSQL_APPLY_RULE(s, q, p) do {\ + if (ctsql_transform_one_rule(s, q, #p, p)) {\ + CT_LOG_DEBUG_ERR("Failed to transform one rule=%s", #p); \ + }\ + } while (0); + + typedef enum en_new_query_type { QUERY_TYPE_OR_EXPAND = 0, QUERY_TYPE_SUBQRY_TO_TAB, @@ -78,8 +89,16 @@ typedef struct st_new_qb_info { text_t suffix; } new_qb_info_t; -status_t sql_transform(sql_stmt_t *stmt); -status_t sql_transform_select(sql_stmt_t *stmt, select_node_t *node); +typedef status_t (*sql_tranform_func_t)(sql_stmt_t *stmt, void *entry); +status_t sql_transform_dummy(sql_stmt_t *stmt, void *entry); +typedef struct st_transform_sql { + sql_type_t type; + sql_tranform_func_t tranform; +} transform_sql_t; + +status_t ctsql_optimize_logically(sql_stmt_t *stmt); +status_t ctsql_optimize_logic_select(sql_stmt_t *stmt, void *entry); +status_t ctsql_optimize_logic_select_node(sql_stmt_t *stmt, select_node_t *node); status_t phase_1_transform_query(sql_stmt_t *stmt, sql_query_t *query); status_t phase_2_transform_query(sql_stmt_t *stmt, sql_query_t *query); status_t try_chged_2_nest_loop(sql_stmt_t *stmt, sql_join_node_t *join_node); diff --git a/pkg/src/ctsql/parser/dml_parser.c b/pkg/src/ctsql/parser/dml_parser.c index 9c927bd8..d52de79f 100644 --- a/pkg/src/ctsql/parser/dml_parser.c +++ b/pkg/src/ctsql/parser/dml_parser.c @@ -113,9 +113,13 @@ static status_t sql_create_dml_context(sql_stmt_t *stmt, sql_text_t *sql, key_wi status_t sql_create_dml(sql_stmt_t *stmt, sql_text_t *sql, key_wid_t key_wid) { CT_RETURN_IFERR(sql_create_dml_context(stmt, sql, key_wid)); + CT_RETURN_IFERR(sql_verify(stmt)); + check_table_stats(stmt); + CT_RETURN_IFERR(ctsql_optimize_logically(stmt)); + return sql_create_dml_plan(stmt); } -- Gitee From 2f344b5b4dffcb0f37996ff873264cddef9d9557 Mon Sep 17 00:00:00 2001 From: lys <120677277@qq.com> Date: Thu, 27 Mar 2025 09:25:46 +0800 Subject: [PATCH 04/12] add comment for transform frame --- build/conf/git_message.in | 13 ++++++++----- build/include/config.h | 11 +++++------ pkg/src/ctsql/optimizer/ctsql_transform.c | 22 +++++++++++++++++++++- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/build/conf/git_message.in b/build/conf/git_message.in index 56c3217e..45622bd4 100644 --- a/build/conf/git_message.in +++ b/build/conf/git_message.in @@ -1,5 +1,8 @@ -git_id=0d24758 -gitVersion=0d2475835d8f619cc36c5deeddd62df24d71104e -merge_time=Wed Feb 21 10:17:26 2024 +0800 -driver_commit_id=c2755f6 -ctsql_commit_id=d4238c4 +git_id=01562113 +gitVersion=0156211376373b12f17f4326aa776ee8316e0ca1 +merge_time=Mon Mar 10 14:48:33 2025 +0800 +cantian_merge_time=Mon Mar 10 14:48:33 2025 +0800 +driver_commit_id=9855c2e1 +ctsql_commit_id=726d7d94 +mysqlGitVersion=bb8ca31a830ed32e29840fd55ada21504be6802b +mysql_merge_time=Thu Jun 6 13:45:13 2024 +0000 diff --git a/build/include/config.h b/build/include/config.h index 44986f4b..fc90eaa9 100644 --- a/build/include/config.h +++ b/build/include/config.h @@ -1,14 +1,13 @@ #define VERSION_DESCRIP Cantian -#define VERSION_MYSQLIP Mysql #define DRIVER_VERSION_DESCRIP Cantian -#define CTSQL_VERSION_DESCRIP +#define CTSQL_VERSION_DESCRIP #define PACK_PREFIX Cantian #define PROJECT_NAME CantianDB -#define PROJECT_VERSION 24.0.0 +#define PROJECT_VERSION 25.06 -#define DD_CT_LIB_VERSION static char* str_CT_LIB_VERSION="Cantian Debug 24.0.0 " -#define DD_CT_DRIVER_VERSION static char* str_CT_DRIVER_VERSION="Cantian Debug " -#define DD_CT_CTSQL_VERSION static char* str_CT_CTSQL_VERSION="Cantian Debug " +#define DD_CT_LIB_VERSION static char* str_CT_LIB_VERSION="Cantian Debug 25.06 01562113" +#define DD_CT_DRIVER_VERSION static char* str_CT_DRIVER_VERSION="Cantian Debug 9855c2e1" +#define DD_CT_CTSQL_VERSION static char* str_CT_CTSQL_VERSION="Cantian Debug 726d7d94" #define DD_GETDBVERSION cantiand_get_dbversion #define DD_GETENCRYVERSION ctencrypt_getDBVersion #define DD_CT_LIB_VER_APINAME ctconn_get_dbversion diff --git a/pkg/src/ctsql/optimizer/ctsql_transform.c b/pkg/src/ctsql/optimizer/ctsql_transform.c index cb370683..a28669c6 100644 --- a/pkg/src/ctsql/optimizer/ctsql_transform.c +++ b/pkg/src/ctsql/optimizer/ctsql_transform.c @@ -395,8 +395,28 @@ status_t ct_transf_predicate_delivery(sql_stmt_t *stmt, sql_query_t *query) status_t ctsql_apply_rule_set(sql_stmt_t *stmt, sql_query_t *query) { // 1. transform to delete unusable orderby. - // transform predicate delivery. + // 2. transform or condition. + // 3. transform predicate delivery. CTSQL_APPLY_RULE(stmt, query, ct_transf_predicate_delivery); + // 4. transform to eliminate no usable distinct. + // 5. transform to eliminate projection column. + // 6. transform to erase sub-select table + //CTSQL_APPLY_RULE(stmt, query, ct_transf_select_erase); + // 7. transform to push down connectby. + // 8. transform in 2 exist. + // 9. transform sub-select to table. + // 10. transform sub-select by winMagic. + // 11. transform sub_select by hash mtrl. + // 12. transform cartesian join(push down grouped aggregation). + // 13. transform to eliminate outer join. + // 14. transform to optimize connectby. + // 15. transfrom predicate delivery. + // 16. transform to push down orderby. + // 17. transform to optimize sort groupby. + // 18. transform cube group. + // 19. transform condition order. + // 20. binding parameters peek. + return CT_SUCCESS; } -- Gitee From 1c8edc887a03c01f8ceadf2938a98d4e6129c2df Mon Sep 17 00:00:00 2001 From: lys <120677277@qq.com> Date: Thu, 27 Mar 2025 15:07:35 +0800 Subject: [PATCH 05/12] rm git version files --- build/conf/git_message.in | 8 -------- build/include/config.h | 14 -------------- 2 files changed, 22 deletions(-) delete mode 100644 build/conf/git_message.in delete mode 100644 build/include/config.h diff --git a/build/conf/git_message.in b/build/conf/git_message.in deleted file mode 100644 index 45622bd4..00000000 --- a/build/conf/git_message.in +++ /dev/null @@ -1,8 +0,0 @@ -git_id=01562113 -gitVersion=0156211376373b12f17f4326aa776ee8316e0ca1 -merge_time=Mon Mar 10 14:48:33 2025 +0800 -cantian_merge_time=Mon Mar 10 14:48:33 2025 +0800 -driver_commit_id=9855c2e1 -ctsql_commit_id=726d7d94 -mysqlGitVersion=bb8ca31a830ed32e29840fd55ada21504be6802b -mysql_merge_time=Thu Jun 6 13:45:13 2024 +0000 diff --git a/build/include/config.h b/build/include/config.h deleted file mode 100644 index fc90eaa9..00000000 --- a/build/include/config.h +++ /dev/null @@ -1,14 +0,0 @@ -#define VERSION_DESCRIP Cantian -#define DRIVER_VERSION_DESCRIP Cantian -#define CTSQL_VERSION_DESCRIP -#define PACK_PREFIX Cantian -#define PROJECT_NAME CantianDB -#define PROJECT_VERSION 25.06 - -#define DD_CT_LIB_VERSION static char* str_CT_LIB_VERSION="Cantian Debug 25.06 01562113" -#define DD_CT_DRIVER_VERSION static char* str_CT_DRIVER_VERSION="Cantian Debug 9855c2e1" -#define DD_CT_CTSQL_VERSION static char* str_CT_CTSQL_VERSION="Cantian Debug 726d7d94" -#define DD_GETDBVERSION cantiand_get_dbversion -#define DD_GETENCRYVERSION ctencrypt_getDBVersion -#define DD_CT_LIB_VER_APINAME ctconn_get_dbversion -#define DD_GETCTSQLVERSION ctsql_get_dbversion -- Gitee From d3e55960a8f2abf0ee4ea95765cf8e296a5d7f00 Mon Sep 17 00:00:00 2001 From: lys <120677277@qq.com> Date: Thu, 27 Mar 2025 17:03:40 +0800 Subject: [PATCH 06/12] fix version file --- build/conf/git_message.in | 5 +++++ build/include/config.h | 15 +++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 build/conf/git_message.in create mode 100644 build/include/config.h diff --git a/build/conf/git_message.in b/build/conf/git_message.in new file mode 100644 index 00000000..56c3217e --- /dev/null +++ b/build/conf/git_message.in @@ -0,0 +1,5 @@ +git_id=0d24758 +gitVersion=0d2475835d8f619cc36c5deeddd62df24d71104e +merge_time=Wed Feb 21 10:17:26 2024 +0800 +driver_commit_id=c2755f6 +ctsql_commit_id=d4238c4 diff --git a/build/include/config.h b/build/include/config.h new file mode 100644 index 00000000..33e36cf9 --- /dev/null +++ b/build/include/config.h @@ -0,0 +1,15 @@ +#define VERSION_DESCRIP Cantian +#define VERSION_MYSQLIP Mysql +#define DRIVER_VERSION_DESCRIP Cantian +#define CTSQL_VERSION_DESCRIP +#define PACK_PREFIX Cantian +#define PROJECT_NAME CantianDB +#define PROJECT_VERSION 24.0.0 + +#define DD_CT_LIB_VERSION static char* str_CT_LIB_VERSION="Cantian Debug 24.0.0 " +#define DD_CT_DRIVER_VERSION static char* str_CT_DRIVER_VERSION="Cantian Debug " +#define DD_CT_CTSQL_VERSION static char* str_CT_CTSQL_VERSION="Cantian Debug " +#define DD_GETDBVERSION cantiand_get_dbversion +#define DD_GETENCRYVERSION ctencrypt_getDBVersion +#define DD_CT_LIB_VER_APINAME ctconn_get_dbversion +#define DD_GETCTSQLVERSION ctsql_get_dbversion \ No newline at end of file -- Gitee From 731e97d664d5c5dd9ecf986759823aa7e4e41c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=86=8A=E5=B0=8F=E5=86=9B?= Date: Sat, 29 Mar 2025 10:22:38 +0800 Subject: [PATCH 07/12] join commit 1 --- pkg/src/ctsql/ctsql_context.h | 64 +++++++++ pkg/src/ctsql/optimizer/ctsql_transform.c | 15 +++ pkg/src/ctsql/plan/ctsql_plan_defs.h | 3 + pkg/src/ctsql/plan/plan_join.c | 153 +++++++++++++++++++++- pkg/src/ctsql/plan/plan_join_bitmap.c | 115 ++++++++++++++++ pkg/src/ctsql/plan/plan_join_bitmap.h | 55 ++++++++ 6 files changed, 402 insertions(+), 3 deletions(-) create mode 100644 pkg/src/ctsql/plan/plan_join_bitmap.c create mode 100644 pkg/src/ctsql/plan/plan_join_bitmap.h diff --git a/pkg/src/ctsql/ctsql_context.h b/pkg/src/ctsql/ctsql_context.h index 2db1f567..2e88cdd3 100644 --- a/pkg/src/ctsql/ctsql_context.h +++ b/pkg/src/ctsql/ctsql_context.h @@ -35,6 +35,7 @@ #include "ctsql_statistics.h" #include "cm_lex.h" #include "cm_bilist.h" +#include "plan_join_bitmap.h" #ifdef __cplusplus extern "C" { @@ -1152,6 +1153,67 @@ typedef struct st_cbo_filter_info { bool32 is_ready; } cbo_filter_info_t; +typedef struct st_join_path{ + sql_join_node_t *join_node; + double cost; + double rows; + uint32 relids; + sql_join_type_t join_type; + join_oper_t join_method; + cond_tree_t *join_cond; + cond_tree_t *filter; + struct st_join_path *outer; + struct st_join_path *inner; + bool32 is_required; +} join_path_t; + +typedef struct st_tbl_join_info { + sql_join_type_t join_type; + join_tbl_bitmap_t table_ids; // bitmap of table ids +} tbl_join_info_t; + +typedef struct st_tbl_join_info_node { + bilist_node_t bilist_node; + tbl_join_info_t join_info; +} tbl_join_info_node_t; + +typedef struct st_special_join_info { + join_tbl_bitmap_t min_lefthand; /* base relids in minimum LHS for join */ + join_tbl_bitmap_t min_righthand; /* base relids in minimum RHS for join */ + join_tbl_bitmap_t syn_lefthand; /* base relids syntactically within LHS */ + join_tbl_bitmap_t syn_righthand; /* base relids syntactically within RHS */ + sql_join_type_t jointype; /* always INNER, LEFT, FULL, SEMI, or ANTI */ + bool lhs_strict; /* joinclause is strict for some LHS rel */ + bool delay_upper_joins; /* can't commute with upper RHS */ + bool varratio_cached; /* decide chach selec or not. */ + bool is_straight_join; /* set true if is straight_join*/ +} special_join_info_t; + +typedef struct st_sql_join_table_node { + bilist_node_t bilist_node; + sql_join_table_t *join_table; +} sql_join_table_node_t; + +typedef enum join_table_type_t { + BASE_TABLE, + JOIN_TABLE +} join_table_type_t; + +typedef struct st_join_path { + int cost; +}join_path_t; + +typedef struct st_sql_join_table { + join_table_type_t table_type; + double rows; + int encode_width; + bilist_t join_path; + join_path_t *cheapest_startup_path; + join_path_t *cheapest_total_path; + join_tbl_bitmap_t table_ids; // bitmap of table_ids + bilist_t join_info; +}sql_join_table_t; + // /////////////////////////////////////////////////////////////////////////////////// typedef struct st_sql_table { uint32 id; @@ -1215,6 +1277,8 @@ typedef struct st_sql_table { bool32 is_jsonb_table : 1; // indicates index cond of this table has been pruned bool32 reserved : 18; + bilist_t join_info; + tf_scan_flag_t tf_scan_flag; // Parallel Scan Indicator scan_part_info_t *scan_part_info; galist_t *for_update_cols; diff --git a/pkg/src/ctsql/optimizer/ctsql_transform.c b/pkg/src/ctsql/optimizer/ctsql_transform.c index 095f784c..aa97b666 100644 --- a/pkg/src/ctsql/optimizer/ctsql_transform.c +++ b/pkg/src/ctsql/optimizer/ctsql_transform.c @@ -140,6 +140,21 @@ status_t sql_get_table_join_cond(sql_stmt_t *stmt, sql_array_t *l_tables, sql_ar join_cond->table1 = left_table->id; join_cond->table2 = right_table->id; cm_bilist_add_tail(&join_cond->bilist_node, join_conds); + + if (left_table->join_info.count == 0) { + cm_bilist_init(&left_table->join_info); + } + if (right_table->join_info.count == 0) { + cm_bilist_init(&right_table->join_info); + } + tbl_join_info_node_t *left_join_node = NULL, *right_join_node = NULL; + CT_RETURN_IFERR(sql_stack_alloc(stmt, sizeof(tbl_join_info_node_t), (void **)&left_join_node)); + CT_RETURN_IFERR(sql_stack_alloc(stmt, sizeof(tbl_join_info_node_t), (void **)&right_join_node)); + sql_bitmap_union_singleton(join_cond->table1, join_cond->table2, &left_join_node->join_info.table_ids); + sql_bitmap_union_singleton(join_cond->table1, join_cond->table2, &right_join_node->join_info.table_ids); + cm_bilist_add_tail(&left_join_node->bilist_node, &left_table->join_info); + cm_bilist_add_tail(&right_join_node->bilist_node, &right_table->join_info); + CT_RETURN_IFERR(sql_stack_alloc(stmt, sizeof(join_cond_t), (void **)&join_cond)); cm_galist_init(&join_cond->cmp_nodes, stmt, sql_stack_alloc); } diff --git a/pkg/src/ctsql/plan/ctsql_plan_defs.h b/pkg/src/ctsql/plan/ctsql_plan_defs.h index 046f5d22..9f3c8418 100644 --- a/pkg/src/ctsql/plan/ctsql_plan_defs.h +++ b/pkg/src/ctsql/plan/ctsql_plan_defs.h @@ -497,6 +497,9 @@ typedef struct st_plan_assist { uint32 scan_part_cnt; // only use part table plan_node_t **filter_node_pptr; pointer_t join_card_map; + + bilist_t *join_tbl_level; + uint32 join_cur_level; } plan_assist_t; typedef enum en_column_match_mode { diff --git a/pkg/src/ctsql/plan/plan_join.c b/pkg/src/ctsql/plan/plan_join.c index 1e23fc61..dd1da882 100644 --- a/pkg/src/ctsql/plan/plan_join.c +++ b/pkg/src/ctsql/plan/plan_join.c @@ -788,6 +788,154 @@ static status_t sql_create_join_tree(sql_stmt_t *stmt, plan_assist_t *pa, join_a return CT_SUCCESS; } +static bool find_join_rel(sql_stmt_t *stmt, join_tbl_bitmap_t *join_tables_ids, sql_table_t *join_tbl) +{ + //todo: find join rel in hash table + return CT_FALSE; +} + +static status_t build_join_tbl(sql_stmt_t *stmt, plan_assist_t *pa, join_tbl_bitmap_t *join_tables_ids, sql_join_table_t *table1, sql_join_table_t *table2, special_join_info_t sjoininfo, sql_join_table_t *join_tbl) +{ + if (find_join_rel(stmt, join_tables_ids, join_tbl) == CT_TRUE) { + return CT_SUCCESS; + } + join_tbl->table_type = JOIN_TABLE; + sql_bitmap_copy(join_tables_ids, &join_tbl->table_ids); + join_tbl->rows = 0; + cm_bilist_init(&join_tbl->join_path); + join_tbl->cheapest_startup_path = NULL; + join_tbl->cheapest_total_path = NULL; + cm_bilist_init(&join_tbl->join_info); + + //todo: build join target list + //build_joinrel_target_list + + //build_joinrel_joinlist(RelOptInfo * joinrel, RelOptInfo * outer_rel, RelOptInfo * inner_rel); //get join_tbl->join_info + + //todo: set join size estimate + + //todo: add to hash table + + if (pa->join_tbl_level) { + sql_join_table_node_t *table_node = NULL; //sql_join_table_t is brief of sql_table_t + CT_RETURN_IFERR(sql_stack_alloc(stmt, sizeof(sql_join_table_node_t), (void **)&table_node)); + table_node->join_table = join_tbl; + cm_bilist_add_tail(&table_node->bilist_node, pa->join_tbl_level[pa->join_cur_level]); + } + return CT_SUCCESS; + +} + +static status_t sql_make_join_relation(sql_stmt_t *stmt, plan_assist_t *pa, join_assist_t *join_ass, + sql_join_node_t **join_root, sql_join_table_t *table1, sql_join_table_t *table2) +{ + join_tbl_bitmap_t join_tables_ids; + sql_bitmap_union(&table1->table_ids, &table2->table_ids, &join_tables_ids); + + //todo: check validity of table1、table2, and determine join type. + + //generate join info + special_join_info_t sjoininfo; + sjoininfo.min_lefthand = table1->table_ids; + sjoininfo.min_righthand = table2->table_ids; + sjoininfo.syn_lefthand = table1->table_ids; + sjoininfo.syn_righthand = table2->table_ids; + sjoininfo.jointype = JOIN_TYPE_INNER; //todo + + sql_join_table_t *join_tbl = NULL; + CT_RETURN_IFERR(sql_alloc_mem(stmt->context, sizeof(sql_join_table_t), (void **)&join_tbl)); + CT_RETURN_IFERR(build_join_tbl(stmt, pa, &join_tables_ids, table1, table2, sjoininfo, &join_tbl)); + + + +} + +static bool sql_have_relevant_join_relation(sql_join_table_t *table1, sql_join_table_t *table2) +{ + bilist_t *join_list = NULL; + join_tbl_bitmap_t *other_tables; + + if (table1->join_info.count <= table2->join_info.count) { + join_list = &table1->join_info; + other_tables = &table2->table_ids; + } else { + join_list = &table2->join_info; + other_tables = &table1->table_ids; + } + bilist_node_t *node = cm_bilist_head(join_list); + for (; node != NULL; node = BINODE_NEXT(node)) { + tbl_join_info_node_t *tmp_join_info = BILIST_NODE_OF(tbl_join_info_node_t, node, bilist_node); + if (sql_bitmap_overlap(&tmp_join_info->join_info.table_ids, other_tables) == CT_TRUE) { + return CT_TRUE; // there is join relation between table1 and table2 + } + } + return CT_FALSE; +} + +static status_t sql_make_rels_by_clause_joins(sql_stmt_t *stmt, plan_assist_t *pa, join_assist_t *join_ass, + sql_join_node_t **join_root, sql_join_table_node_t *old_table_node, bilist_node_t *other_tables) +{ + bilist_node_t *other_node = other_tables; + while (other_node) { + sql_join_table_node_t *other_table_node = BILIST_NODE_OF(sql_join_table_node_t, other_node, bilist_node); + sql_join_table_t *other_table = other_table_node->join_table; + + if (sql_bitmap_overlap(&old_table_node->join_table->table_ids, &other_table->table_ids) == CT_TRUE) { + continue; + } + if (sql_have_relevant_join_relation(old_table_node->join_table, other_table) == CT_FALSE) { + continue; + } + sql_make_join_relation(stmt, pa, join_ass, join_root, old_table_node->join_table, other_table); + } + return CT_SUCCESS; +} + +static status_t sql_search_one_level(sql_stmt_t *stmt, plan_assist_t *pa, join_assist_t *join_ass, + sql_join_node_t **join_root) +{ + uint32 level = pa->join_cur_level; + bilist_node_t *pre_level_node = cm_bilist_head(&pa->join_tbl_level[level-1]); + + for (; pre_level_node != NULL; pre_level_node = BINODE_NEXT(pre_level_node)) { + sql_join_table_node_t *old_table = BILIST_NODE_OF(sql_join_table_node_t, pre_level_node, bilist_node); + + bilist_node_t * other_tables = NULL; + if (level == 1) { + other_tables = pre_level_node->next; + } else { + other_tables = cm_bilist_head(pa->join_tbl_level[0]); + } + CT_RETURN_IFERR(sql_make_rels_by_clause_joins(stmt, pa, join_ass, join_root, old_table, other_tables)); + } +} + +static status_t sql_create_join_tree_new(sql_stmt_t *stmt, plan_assist_t *pa, join_assist_t *join_ass, + sql_join_node_t **join_root) +{ + CT_RETURN_IFERR(sql_alloc_mem(stmt->context, sizeof((pa->table_count) * sizeof(bilist_t*)), (void **)&pa->join_tbl_level)); + for (uint32 i = 0; i < pa->table_count; i++) { + cm_bilist_init(&pa->join_tbl_level[i]); + } + + for (uint32 i = 0; i < pa->table_count; i++) { + sql_join_table_node_t *table_node = NULL; //sql_join_table_t is brief of sql_table_t + CT_RETURN_IFERR(sql_stack_alloc(stmt, sizeof(sql_join_table_node_t), (void **)&table_node)); + sql_bitmap_make_singleton(pa->tables[i]->id, &table_node->join_table->table_ids); + table_node->join_table->table_type = BASE_TABLE; + table_node->join_table->join_info = pa->tables[i]->join_info; + cm_bilist_add_tail(&table_node->bilist_node, pa->join_tbl_level[0]); + } + + for (uint32 level = 1; level <= pa->table_count; level++) { + pa->join_cur_level = level; + CT_RETURN_IFERR(sql_search_one_level(stmt, pa, join_ass, join_root)); + + //sql_get_cheapest_path(); + } + return CT_SUCCESS; +} + static inline cond_tree_t *sql_get_right_table_cond(sql_join_node_t *join_node) { if (join_node->type <= JOIN_TYPE_INNER) { @@ -1289,9 +1437,8 @@ status_t sql_build_join_tree(sql_stmt_t *stmt, plan_assist_t *plan_ass, sql_join CT_RETURN_IFERR( sql_get_table_join_cond(plan_ass->stmt, &plan_ass->query->tables, &plan_ass->query->tables, plan_ass->cond, &plan_ass->join_conds)); - { - CT_RETURN_IFERR(sql_create_join_tree(stmt, plan_ass, &join_ass, join_root)); - } + CT_RETURN_IFERR(sql_create_join_tree(stmt, plan_ass, &join_ass, join_root)); + CT_RETURN_IFERR(sql_create_join_tree_new(stmt, plan_ass, &join_ass, join_root)); } SQL_RESTORE_NODE_STACK(stmt); CTSQL_RESTORE_STACK(stmt); diff --git a/pkg/src/ctsql/plan/plan_join_bitmap.c b/pkg/src/ctsql/plan/plan_join_bitmap.c new file mode 100644 index 00000000..148d85d1 --- /dev/null +++ b/pkg/src/ctsql/plan/plan_join_bitmap.c @@ -0,0 +1,115 @@ +/* ------------------------------------------------------------------------- + * This file is part of the Cantian project. + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * Cantian is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * 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 PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * plan_join.c + * + * + * IDENTIFICATION + * src/ctsql/plan/plan_join_bitmap.c + * + * ------------------------------------------------------------------------- + */ +#include "srv_instance.h" +#include "table_parser.h" +#include "ctsql_transform.h" +#include "ctsql_plan_defs.h" +#include "plan_join.h" +#include "plan_rbo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static void sql_bitmap_make_singleton(uint32 table_id, join_tbl_bitmap_t* tables_bms) +{ + uint32 wordnum, bitnum; + + wordnum = table_id / 64; + bitnum = table_id % 64; + tables_bms->num = wordnum + 1; + tables_bms->ids[wordnum] = (1 << bitnum); + return; +} + +static void sql_bitmap_copy(join_tbl_bitmap_t *a, join_tbl_bitmap_t *result) +{ + if (a == NULL) { + result = a; + return; + } + for (uint32 i = 0; i < MAX_JOIN_TABLE_GROUP; i++) { //init + result->num[i] = 0; + } + result->num = a->num; + for (uint32 i = 0; i < a->num; i++) { + result->ids[i] = a->num[i]; + } +} + +static void sql_bitmap_union_singleton(uint32 a, uint32 b, join_tbl_bitmap_t* result) +{ + join_tbl_bitmap_t bitmap_a; + join_tbl_bitmap_t bitmap_b; + sql_bitmap_make_singleton(a, &bitmap_a); + sql_bitmap_make_singleton(b, &bitmap_b); + + sql_bitmap_union(&bitmap_a, &bitmap_b, result); +} + +static void sql_bitmap_union(join_tbl_bitmap_t *a, join_tbl_bitmap_t *b, join_tbl_bitmap_t* result) +{ + join_tbl_bitmap_t *other = NULL; + + if (b == NULL) { + sql_bitmap_copy(a, result); + return; + } + if (a == NULL) { + sql_bitmap_copy(b, result); + return; + } + /* Identify shorter and longer input; copy the longer one */ + if (a->num <= b->num) { + sql_bitmap_copy(b, result); + other = a; + } else { + sql_bitmap_copy(a, result); + other = b; + } + /* And union the shorter input into the result */ + for (uint32 i = 0; i < other->num; i++) + result->ids[i] |= other->ids[i]; + return; +} + +bool sql_bitmap_overlap(join_tbl_bitmap_t* a, join_tbl_bitmap_t* b) +{ + if (a == NULL || b == NULL) { + return false; + } + /* Check ids in common */ + uint32 shortlen = Min(a->num, b->num); + for (uint32 i = 0; i < shortlen; i++) { + if ((a->ids[i] & b->ids[i]) != 0) { + return true; + } + } + return false; +} + +#ifdef __cplusplus +} +#endif diff --git a/pkg/src/ctsql/plan/plan_join_bitmap.h b/pkg/src/ctsql/plan/plan_join_bitmap.h new file mode 100644 index 00000000..b161db3c --- /dev/null +++ b/pkg/src/ctsql/plan/plan_join_bitmap.h @@ -0,0 +1,55 @@ +/* ------------------------------------------------------------------------- + * This file is part of the Cantian project. + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * Cantian is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * 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 PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * plan_join.c + * + * + * IDENTIFICATION + * src/ctsql/plan/plan_join_bitmap.h + * + * ------------------------------------------------------------------------- + */ +#include "srv_instance.h" +#include "table_parser.h" +#include "ctsql_transform.h" +#include "ctsql_plan_defs.h" +#include "plan_join.h" +#include "plan_rbo.h" + +#ifdef __cplusplus +extern "C" { +#endif +#define MAX_JOIN_TABLE_GROUP (uint32)CT_MAX_JOIN_TABLES/64 + +typedef struct st_join_tbl_bitmap { + uint32 num; //table_id / 64 + uint32 ids[MAX_JOIN_TABLE_GROUP]; // ids[i] = (1 << table_id % 64) +} join_tbl_bitmap_t; + + +void sql_bitmap_make_singleton(uint32 table_id, join_tbl_bitmap_t* tables_bms); + +void sql_bitmap_copy(join_tbl_bitmap_t *a, join_tbl_bitmap_t *result); + +void sql_bitmap_union_singleton(uint32 a, uint32 b, join_tbl_bitmap_t* result); + +void sql_bitmap_union(join_tbl_bitmap_t *a, join_tbl_bitmap_t *b, join_tbl_bitmap_t* result); + +bool sql_bitmap_overlap(join_tbl_bitmap_t* a, join_tbl_bitmap_t* b); + +#ifdef __cplusplus +} +#endif -- Gitee From 1782df21869fe40905af55ce2004d6f73080e8df Mon Sep 17 00:00:00 2001 From: lijieac Date: Mon, 24 Mar 2025 21:19:16 +0800 Subject: [PATCH 08/12] feat: add the ut frame for sql --- CI/script/Dev_unit_test.sh | 26 ++- build/Makefile.sh | 175 ++-------------- build/common.sh | 10 +- build/download_opensource_cmc.sh | 102 ---------- pkg/CMakeLists.txt | 6 +- pkg/cfg/cantiand-ut.ini | 14 ++ pkg/cfg/cms-ut.ini | 23 +++ pkg/src/cms/interface/cms_comm.c | 6 + pkg/src/cms/interface/cms_comm.h | 1 + pkg/src/cms/interface/cms_interface.h | 1 + pkg/src/ctsql/ctsql_stmt.c | 2 - .../ctsql/executor/explain/expl_executor.c | 14 +- .../ctsql/executor/explain/expl_executor.h | 5 +- pkg/src/ctsql/executor/explain/expl_plan.c | 191 +++++++++--------- pkg/src/ctsql/executor/explain/expl_plan.h | 43 ++-- pkg/src/kernel/include/db_defs.h | 1 + pkg/src/kernel/include/dml_defs.h | 1 + pkg/src/utils/ctbackup/ctbackup.c | 4 +- pkg/test/unit_test/ut/CMakeLists.txt | 3 +- .../unit_test/ut/cms/cms_disk_lock_test.cpp | 3 +- .../ut/common/common_device_test.cpp | 1 + pkg/test/unit_test/ut/ctsql/CMakeLists.txt | 29 +++ .../unit_test/ut/ctsql/stub/stub_ctsql.cpp | 150 ++++++++++++++ pkg/test/unit_test/ut/ctsql/stub/stub_ctsql.h | 22 ++ .../unit_test/ut/ctsql/test_ctsql_main.cpp | 32 +++ .../unit_test/ut/ctsql/test_expl_execute.cpp | 29 +++ .../message_queue/message_queue_test_main.cpp | 8 +- 27 files changed, 483 insertions(+), 419 deletions(-) delete mode 100644 build/download_opensource_cmc.sh create mode 100644 pkg/cfg/cantiand-ut.ini create mode 100644 pkg/cfg/cms-ut.ini create mode 100644 pkg/test/unit_test/ut/ctsql/CMakeLists.txt create mode 100644 pkg/test/unit_test/ut/ctsql/stub/stub_ctsql.cpp create mode 100644 pkg/test/unit_test/ut/ctsql/stub/stub_ctsql.h create mode 100644 pkg/test/unit_test/ut/ctsql/test_ctsql_main.cpp create mode 100644 pkg/test/unit_test/ut/ctsql/test_expl_execute.cpp diff --git a/CI/script/Dev_unit_test.sh b/CI/script/Dev_unit_test.sh index c0d9d8f6..66e8415a 100644 --- a/CI/script/Dev_unit_test.sh +++ b/CI/script/Dev_unit_test.sh @@ -47,6 +47,15 @@ function make_cantian_pkg(){ fi } +function prepare_cantian_cfg() +{ + echo "DBWR_PROCESSES = 8" >> ${CTDB_HOME}/cfg/cantiand.ini + echo "_SYS_PASSWORD = Ck311QUAECd2bdgppbA85VqPjjV/Wn/1jByyAWxktckKOjFf59olvzHvQWeKumrSJBjcV8RxupSQveBbc1i0J63n4kpk1+m43FyDL2XyBzQ50cVWsOFNXw==" >> ${CTDB_HOME}/cfg/cantiand.ini + echo "MYSQL_DEPLOY_GROUP_ID = 5000" >> ${CTDB_HOME}/cfg/cantiand.ini + echo "SHM_MYSQL_CPU_GROUP_INFO = 0-15" >> ${CTDB_HOME}/cfg/cantiand.ini + echo "SHM_CPU_GROUP_INFO = 0-15" >> ${CTDB_HOME}/cfg/cantiand.ini +} + echo -n "make test ..." dots 5 & DOTS_BG_PID=$! @@ -68,6 +77,8 @@ export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${CTDB_CODE_PATH}/library/mockcpp/lib/ export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${CTDB_CODE_PATH}/library/dbstor/lib/ export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${CTDB_CODE_PATH}/library/dbstor/lib/nomlnx/ +export CTDB_HOME=/home/cantiandb/install + UNAME=$(uname -a) if [[ "${UNAME}" =~ .*aarch64.* ]];then export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${CTDB_CODE_PATH}/library/xnet/lib_arm/ @@ -76,20 +87,19 @@ elif [[ "${UNAME}" =~ .*x86_64.* ]];then else error "error: unknown arch!" fi + mkdir -p ${CTDB_HOME}/cfg -#chmod 777 ${CTDB_CODE_PATH}/pkg/test/unit_test/ut/cms_test/cfg -#chmod 777 ${CTDB_CODE_PATH}/pkg/test/mes_test/config -#chmod 600 ${CTDB_CODE_PATH}/pkg/test/mes_test/config/ca.crt -echo "DBWR_PROCESSES = 8" >> ${CTDB_HOME}/cfg/cantiand.ini +rm -f ${CTDB_HOME}/cfg/cantiand.ini +prepare_cantian_cfg echo -echo -n "run message_queue_test ..." -${CTDB_CODE_PATH}/output/bin/message_queue_test --gtest_output=xml:${GTEST_RESULT_PATH}/ >> ${GTEST_RUN_LOG} 2>&1 +echo -n "run ctsql_test ..." +${CTDB_CODE_PATH}/output/bin/ctsql_test --gtest_output=xml:${GTEST_RESULT_PATH}/ >> ${GTEST_RUN_LOG} 2>&1 if [ "$?" != "0" ]; then - error "run message_queue_test error!" + error "run ctsql_test error!" fi echo -echo "run message_queue_test success!" +echo "run ctsql_test success!" echo echo -n "run ctc_srv_test ..." diff --git a/build/Makefile.sh b/build/Makefile.sh index d8f266a9..273f497d 100644 --- a/build/Makefile.sh +++ b/build/Makefile.sh @@ -4,7 +4,9 @@ set -e -CURRENT_PATH=$(dirname $(readlink -f $0)) +CODE_BUILD_PATH=$(dirname $(readlink -f $0)) +CODE_HOME_PATH="${CODE_BUILD_PATH}"/.. + PS4=':${LINENO}+' declare VERSION_DESCRIP="" declare VERSION_MYSQLIP="" @@ -24,21 +26,15 @@ export BUILD_MODE="" export PYTHON_INCLUDE_DIR="" export LOGICREP_PERSONAL_PKG_DIR="" export WORKSPACE=$(dirname $(dirname $(pwd))) -DFT_WORKSPACE="/home/regress" -source ./common.sh -source ./function.sh +source ${CODE_BUILD_PATH}/common.sh CONFIG_IN_FILE=${CANTIANDB_BUILD}/include/config.h -CTDB_CODE_PATH="${CURRENT_PATH}"/.. CMAKE_C_COMPILER=$(which gcc) CMAKE_CXX_COMPILER=$(which g++) PYTHON3_HOME=${PYTHON3_HOME} -MYSQL_CODE_PATH=${WORKSPACE}/cantian-connector-mysql/mysql-source -INSTALL_DIR=/opt/cantiandb -INITSQL_DIR=../ -func_prepare_git_msg + PROJECT_VERSION=$(cat ${CONFIG_IN_FILE} | grep 'PROJECT_VERSION' | awk '{print $3}') CANTIAND_BIN=cantiand-${PROJECT_VERSION} JDBC_DIR=${CANTIANDB_HOME}/src/jdbc/cantian-jdbc/build/Cantian_PKG @@ -60,11 +56,7 @@ BUILD_MYSQL_SO=${BUILD_MYSQL_SO:-"YES"} FEATURE_FOR_EVERSQL=${FEATURE_FOR_EVERSQL:-"0"} OS_ARCH=$(uname -i) -export INTERNAL_BUILD="TRUE" - -if [[ ! -d "${CTDB_CODE_PATH}"/../ProductComm_DoradoAA ]];then - export INTERNAL_BUILD="FALSE" -fi +export INTERNAL_BUILD="FALSE" if [[ ${OS_ARCH} =~ "x86_64" ]]; then export CPU_CORES_NUM=`cat /proc/cpuinfo |grep "cores" |wc -l` @@ -87,6 +79,7 @@ if [ "${BUILD_MYSQL_SO}" == "YES" ]; then fi echo ${CANTIANDB_HOME} + func_prepare_pkg_name() { cd ${CANTIANDB_HOME} @@ -446,103 +439,6 @@ func_prepare_header_files() rm -rf ${MYSQL_DIR}/3rdPartyPkg fi } -func_make_mysql_debug() -{ - echo "Start build Mysql Debug..." - func_prepare_header_files - - rm -rf ${MYSQL_CODE_PATH}/cantian_lib - mkdir -p ${MYSQL_CODE_PATH}/cantian_lib - cp -arf ${CANTIAN_LIB_DIR}/* ${MYSQL_CODE_PATH}/cantian_lib/ - mkdir -p ${MYSQL_CODE_PATH}/bld_debug - local LLT_TEST_TYPE="NORMAL" - if [ "${ENABLE_LLT_GCOV}" == "YES" ]; then - LLT_TEST_TYPE="GCOV" - elif [ "${ENABLE_LLT_ASAN}" == "YES" ]; then - LLT_TEST_TYPE="ASAN" - fi - prepareGetMysqlClientStaticLibToCantianlib ${MYSQL_CODE_PATH} "DEBUG" ${LLT_TEST_TYPE} ${BOOST_PATH} ${CPU_CORES_NUM} ${MYSQL_CODE_PATH}/bld_debug - - cd ${MYSQL_CODE_PATH}/bld_debug - cp -arf "${CANTIANDB_LIBRARY}"/shared_lib/lib/libsecurec.so /usr/lib64/ - if [ "${MYSQL_BUILD_MODE}" == "multiple" ]; then - if [ "${ENABLE_LLT_GCOV}" == "YES" ]; then - cmake .. -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DENABLE_GCOV=1 -DWITH_CTC_STORAGE_ENGINE=${WITH_CTC_STORAGE_ENGINE} -DFEATURE_FOR_EVERSQL=${FEATURE_FOR_EVERSQL} -DCMAKE_BUILD_TYPE=Debug -DWITH_BOOST=${BOOST_PATH} -DWITHOUT_SERVER=OFF - elif [ "${ENABLE_LLT_ASAN}" == "YES" ]; then - cmake .. -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DWITH_ASAN=ON -DWITH_ASAN_SCOPE=ON -DWITH_CTC_STORAGE_ENGINE=${WITH_CTC_STORAGE_ENGINE} -DFEATURE_FOR_EVERSQL=${FEATURE_FOR_EVERSQL} -DCMAKE_BUILD_TYPE=Debug -DWITH_BOOST=${BOOST_PATH} -DWITHOUT_SERVER=OFF - else - cmake .. -DWITH_CTC_STORAGE_ENGINE=${WITH_CTC_STORAGE_ENGINE} -DFEATURE_FOR_EVERSQL=${FEATURE_FOR_EVERSQL} -DCMAKE_BUILD_TYPE=Debug -DWITH_BOOST=${BOOST_PATH} -DWITHOUT_SERVER=OFF -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_C_FLAGS="-Wno-error=attributes" -DCMAKE_CXX_FLAGS="-Wno-error=attributes" - fi - elif [ "${MYSQL_BUILD_MODE}" == "single" ]; then - cmake .. -DWITH_CANTIAN=1 -DWITH_CTC_STORAGE_ENGINE=${WITH_CTC_STORAGE_ENGINE} -DFEATURE_FOR_EVERSQL=${FEATURE_FOR_EVERSQL} -DCMAKE_BUILD_TYPE=Debug -DWITH_BOOST=${BOOST_PATH} -DWITHOUT_SERVER=OFF -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_C_FLAGS="-Wno-error=attributes" -DCMAKE_CXX_FLAGS="-Wno-error=attributes" - fi - - MYSQL_BUILD_TYPE="debug" - - if [ -f ${MYSQL_BINARY_CODE_PATH}/mysql_${MYSQL_BUILD_TYPE}_${OS_ARCH}_${MYSQL_COMMIT_ID}.tar.gz ]; then - cd ${MYSQL_CODE_PATH}/bld_debug/storage/ctc && make -j${CPU_CORES_NUM} && make install - cd ${MYSQL_BINARY_CODE_PATH} && tar -xzf mysql_${MYSQL_BUILD_TYPE}_${OS_ARCH}_${MYSQL_COMMIT_ID}.tar.gz -C /usr/local/ - echo "mysql binary code untar succeed" - chmod +x /usr/local/mysql/bin/* - cp -arf /${MYSQL_CODE_PATH}/mysql-test /usr/local/mysql/ - else - make -j${CPU_CORES_NUM} - make install - fi - cp -r -f -p ${MYSQL_CODE_PATH}/cantian_lib/libctc_proxy.so /usr/lib64 - echo 'log_raw=ON' >> /usr/local/mysql/mysql-test/include/default_mysqld.cnf - cd - -} - -func_make_mysql_release() -{ - echo "Start build Mysql Release..." - func_prepare_header_files - rm -rf ${MYSQL_CODE_PATH}/cantian_lib - mkdir -p ${MYSQL_CODE_PATH}/cantian_lib - cp -arf ${CANTIAN_LIB_DIR}/* ${MYSQL_CODE_PATH}/cantian_lib/ - mkdir -p ${MYSQL_CODE_PATH}/bld_debug - local LLT_TEST_TYPE="NORMAL" - if [ "${ENABLE_LLT_GCOV}" == "YES" ]; then - LLT_TEST_TYPE="GCOV" - elif [ "${ENABLE_LLT_ASAN}" == "YES" ]; then - LLT_TEST_TYPE="ASAN" - fi - prepareGetMysqlClientStaticLibToCantianlib ${MYSQL_CODE_PATH} "RELEASE" ${LLT_TEST_TYPE} ${BOOST_PATH} ${CPU_CORES_NUM} ${MYSQL_CODE_PATH}/bld_debug - - cd ${MYSQL_CODE_PATH}/bld_debug - cp -arf "${CANTIANDB_LIBRARY}"/shared_lib/lib/libsecurec.so /usr/lib64/ - if [ "${MYSQL_BUILD_MODE}" == "multiple" ]; then - if [[ ${OS_ARCH} =~ "aarch64" ]]; then - cmake .. -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DWITH_CTC_STORAGE_ENGINE=${WITH_CTC_STORAGE_ENGINE} -DFEATURE_FOR_EVERSQL=${FEATURE_FOR_EVERSQL} -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=${BOOST_PATH} -DCMAKE_C_FLAGS="-g -march=armv8.2-a+crc+lse" -DCMAKE_CXX_FLAGS="-g -march=armv8.2-a+crc+lse" -DWITHOUT_SERVER=OFF -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - else - cmake .. -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DWITH_CTC_STORAGE_ENGINE=${WITH_CTC_STORAGE_ENGINE} -DFEATURE_FOR_EVERSQL=${FEATURE_FOR_EVERSQL} -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=${BOOST_PATH} -DCMAKE_C_FLAGS=-g -DCMAKE_CXX_FLAGS=-g -DWITHOUT_SERVER=OFF -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - fi - elif [ "${MYSQL_BUILD_MODE}" == "single" ]; then - if [[ ${OS_ARCH} =~ "aarch64" ]]; then - cmake .. -DWITH_CANTIAN=1 -DWITH_CTC_STORAGE_ENGINE=${WITH_CTC_STORAGE_ENGINE} -DFEATURE_FOR_EVERSQL=${FEATURE_FOR_EVERSQL} -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=${BOOST_PATH} -DCMAKE_C_FLAGS="-g -march=armv8.2-a+crc+lse" -DCMAKE_CXX_FLAGS="-g -march=armv8.2-a+crc+lse" -DWITHOUT_SERVER=OFF -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - else - cmake .. -DWITH_CANTIAN=1 -DWITH_CTC_STORAGE_ENGINE=${WITH_CTC_STORAGE_ENGINE} -DFEATURE_FOR_EVERSQL=${FEATURE_FOR_EVERSQL} -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=${BOOST_PATH} -DCMAKE_C_FLAGS=-g -DCMAKE_CXX_FLAGS=-g -DWITHOUT_SERVER=OFF -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - fi - - fi - - - MYSQL_BUILD_TYPE="release" - if [ -f ${MYSQL_BINARY_CODE_PATH}/mysql_${MYSQL_BUILD_TYPE}_${OS_ARCH}_${MYSQL_COMMIT_ID}.tar.gz ]; then - cd ${MYSQL_CODE_PATH}/bld_debug/storage/ctc && make -j${CPU_CORES_NUM} && make install - cd ${MYSQL_BINARY_CODE_PATH} && tar -xzf mysql_${MYSQL_BUILD_TYPE}_${OS_ARCH}_${MYSQL_COMMIT_ID}.tar.gz -C /usr/local/ - echo "mysql binary code untar succeed" - chmod +x /usr/local/mysql/bin/* - cp -arf /${MYSQL_CODE_PATH}/mysql-test /usr/local/mysql/ - else - make -j${CPU_CORES_NUM} - make install - fi - cp -r -f -p ${MYSQL_CODE_PATH}/cantian_lib/libctc_proxy.so /usr/lib64 - echo 'log_raw=ON' >> /usr/local/mysql/mysql-test/include/default_mysqld.cnf - cd - -} func_test() { @@ -742,29 +638,11 @@ func_making_package() func_download_3rdparty() { - if [[ "${WORKSPACE}" == *"regress"* ]]; then - DOWNLOAD_PATH=$DFT_WORKSPACE"/CantianKernel" - else - DOWNLOAD_PATH=${CTDB_CODE_PATH} - fi - - cd ${DOWNLOAD_PATH} - if [[ ${INTERNAL_BUILD} == "FALSE" ]]; then - git submodule init - git submodule update --recursive - else - echo "Clone source start" - if [[ x"${proxy_user}" != x"" ]]; then - export http_proxy=http://${proxy_user}:${proxy_pwd}@${proxy_url} - export https_proxy=${http_proxy} - export no_proxy=127.0.0.1,.huawei.com,localhost,local,.local - fi - git clone https://gitee.com/cantian-repo/cantian-repo.git - rm -rf open_source - mv cantian-repo open_source - fi - - cd - + cd ${CODE_HOME_PATH} + git submodule init + git submodule update --recursive + + cd ${CODE_BUILD_PATH} echo "start compile 3rdparty : " sh compile_opensource_new.sh @@ -809,7 +687,7 @@ func_prepare_dependency() func_prepare_LLT_dependency() { - echo "Prepare LCRP_HOME dependency func : " + echo "Prepare LLT dependency func : " if [[ ! -d ${CANTIANDB_LIBRARY} ]]; then echo "library dir not exist" mkdir -p ${CANTIANDB_LIBRARY} @@ -835,28 +713,9 @@ func_prepare_LLT_dependency() mkdir -p ${MYSQL_BINARY_CODE_PATH} fi - echo ${LCRP_HOME} - mkdir -p /root/.ArtGet/conf - cp -f ${CANTIANDB_CI_PATH}/CMC/Setting.xml /root/.ArtGet/conf - OS_Version=`sh ${CANTIANDB_CI_PATH}/CMC/get_OS_Version.sh` - #下载三方库并编译 - if [[ ${INTERNAL_BUILD} == "FALSE" ]]; then - func_download_3rdparty - fi - if [[ "${WORKSPACE}" == *"regress"* ]]; then - DOWNLOAD_PATH=$DFT_WORKSPACE"/CantianKernel" - else - DOWNLOAD_PATH=${WORKSPACE}"/cantian" - fi - - echo "start download 3rdparty : ${DOWNLOAD_PATH}" - python ${CANTIANDB_CI_PATH}/CMC/manifest_opensource_download.py manifest_opensource.xml ${DOWNLOAD_PATH} - sh download_opensource_cmc.sh - echo "start download 3rdparty lib: " - artget pull -d ${CANTIANDB_CI_PATH}/CMC/CantianKernel_opensource_dependency.xml -p "{'OS_Version':'${OS_Version}'}" -user ${cmc_username} -pwd ${cmc_password} + func_download_3rdparty - artget pull -d ${CANTIANDB_CI_PATH}/CMC/CantianKernel_dependency_new.xml -p "{'OS_Version':'${OS_Version}'}" -user ${cmc_username} -pwd ${cmc_password} if [[ $? -ne 0 ]]; then echo "dependency download failed" exit 1 @@ -1118,12 +977,6 @@ main() 'mysqllib') fun_pkg_mysql_lib ;; - 'mysql'|'mysql_debug') - func_make_mysql_debug - ;; - 'mysql_release') - func_make_mysql_release - ;; 'mysql_package_node0') func_collect_mysql_target node0 ;; diff --git a/build/common.sh b/build/common.sh index a1d38e5c..cb781abd 100644 --- a/build/common.sh +++ b/build/common.sh @@ -6,13 +6,10 @@ declare OS_SUFFIX="" declare OS_MAJOR_VERSION="" declare OS_MINOR_VERSION="" -declare OPENSSL_LIB_PATH="" -declare SECUREC_LIB_PATH="" declare PCRE_LIB_PATH="" declare Z_LIB_PATH="" declare ZSTD_LIB_PATH="" declare LZ4_LIB_PATH="" -declare XNET_LIB_PATH="" declare OS_ARCH="" declare WHOLE_COMMIT_ID="" declare git_id="" @@ -27,7 +24,9 @@ ARCH=$(getconf LONG_BIT) SYMBOLFIX=symbol SO=so -CODE_HOME_PATH=$(echo $(dirname $(pwd))) +CURRENT_PATH=$(dirname $(readlink -f $0)) +CODE_HOME_PATH="${CURRENT_PATH}"/.. + CANTIANDB_CI_PATH=${CODE_HOME_PATH}/CI CANTIANDB_HOME=${CODE_HOME_PATH}/pkg @@ -56,15 +55,12 @@ else OS_ARCH=$(uname -i) fi -OPENSSL_LIB_PATH=${CANTIANDB_LIBRARY}/openssl/lib PCRE_LIB_PATH=${CANTIANDB_LIBRARY}/pcre/lib Z_LIB_PATH=${CANTIANDB_LIBRARY}/zlib/lib ODBC_LIB_PATH=${CANTIANDB_LIBRARY}/odbc/lib ZSTD_LIB_PATH=${CANTIANDB_LIBRARY}/Zstandard/lib LZ4_LIB_PATH=${CANTIANDB_LIBRARY}/lz4/lib -SECUREC_LIB_PATH=${CANTIANDB_LIBRARY}/security/lib KMC_LIB_PATH=${CANTIANDB_LIBRARY}/kmc/lib -XNET_LIB_PATH=${CANTIANDB_LIBRARY}/xnet/lib SUSE_VERSION_PATH=/etc/SuSE-release REDHAT_VERSION_PATH=/etc/redhat-release diff --git a/build/download_opensource_cmc.sh b/build/download_opensource_cmc.sh deleted file mode 100644 index 34a1138b..00000000 --- a/build/download_opensource_cmc.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/bash -# Copyright Huawei Technologies Co., Ltd. 2010-2018. All rights reserved. -set -e - -declare BEP - -export WORKSPACE=$(dirname $(dirname $(pwd))) -export OPEN_SOURCE=${WORKSPACE}/CantianKernel/open_source -export LIBRARY=${WORKSPACE}/CantianKernel/library -export OS_ARCH=$(uname -i) -DFT_WORKSPACE="/home/regress" - -echo $DFT_WORKSPACE " " $WORKSPACE -if [[ "$WORKSPACE" == *"regress"* ]]; then - echo $DFT_WORKSPACE " eq " $WORKSPACE -else - export OPEN_SOURCE=${WORKSPACE}/cantian/open_source - export LIBRARY=${WORKSPACE}/cantian/library -fi - -#pcre -cd ${OPEN_SOURCE}/pcre/pcre2-10.40 -touch configure.ac aclocal.m4 Makefile.in configure config.h.in -mkdir -p pcre-build;chmod 755 -R ./* -aclocal;autoconf;autoreconf -vif -#判断系统是否是centos,并且参数bep是否为true,都是则删除。 -if [[ ! -z ${BEP} ]]; then - if [[ -n "$(cat /etc/os-release | grep CentOS)" ]] && [[ ${BEP} == "true" ]] && [[ "${BUILD_TYPE}" == "RELEASE" ]];then - sed -i "2656,2690d" configure #从2656到2690行是构建环境检查,检查系统时间的。做bep固定时间戳时,若是centos系统,系统时间固定,必须删除构建环境检查,才能编译,才能保证两次出包bep一致;若是euler系统,可不用删除,删除了也不影响编译。 - fi -fi -./configure -mkdir -p ${OPEN_SOURCE}/pcre/include/ -cp ${OPEN_SOURCE}/pcre/pcre2-10.40/src/pcre2.h ${OPEN_SOURCE}/pcre/include/ - -#lz4 -cd ${OPEN_SOURCE}/lz4/lz4-1.9.4/lib -mkdir -p ${OPEN_SOURCE}/lz4/include/ -cp lz4frame.h lz4.h ${OPEN_SOURCE}/lz4/include - -#zstd -cd ${OPEN_SOURCE}/Zstandard/zstd-1.5.2 -mkdir -p ${OPEN_SOURCE}/Zstandard/include -cp lib/zstd.h ${OPEN_SOURCE}/Zstandard/include -cd lib/;rm -f libzstd.so libzstd.so.1 -ln -s libzstd.so.1.5.2 libzstd.so -ln -s libzstd.so.1.5.2 libzstd.so.1 - - -#protobuf -# cd ${OPEN_SOURCE}/protobuf/protobuf.3.13.0 -# ./autogen.sh -# # 流水线是否设置BEP -# if [[ ! -z ${BEP} ]]; then -# if [[ -n "$(cat /etc/os-release | grep CentOS)" ]] && [[ ${BEP} == "true" ]] && [[ "${BUILD_TYPE}" == "RELEASE" ]];then -# sed -i "2915,2949d" configure -# fi -# fi -# ./configure -# if [[ ${OS_ARCH} =~ "x86_64" ]]; then -# export CPU_CORES_NUM_x86=`cat /proc/cpuinfo |grep "cores" |wc -l` -# make -j${CPU_CORES_NUM_x86} -# elif [[ ${OS_ARCH} =~ "aarch64" ]]; then -# export CPU_CORES_NUM_arm=`cat /proc/cpuinfo |grep "architecture" |wc -l` -# make -j${CPU_CORES_NUM_arm} -# else -# echo "OS_ARCH: ${OS_ARCH} is unknown, set CPU_CORES_NUM=16 " -# export CPU_CORES_NUM=16 -# make -j${CPU_CORES_NUM} -# fi -# make install - -#protobuf-c -mkdir -p ${OPEN_SOURCE}/protobuf-c/include/ -mkdir -p ${LIBRARY}/protobuf/protobuf-c/ -cp ${OPEN_SOURCE}/protobuf-c/protobuf-c-1.4.1/protobuf-c/protobuf-c.h ${OPEN_SOURCE}/protobuf-c/include/ -cp ${OPEN_SOURCE}/protobuf-c/protobuf-c-1.4.1/protobuf-c/protobuf-c.h ${LIBRARY}/protobuf/protobuf-c/ - -#openssl -cd ${OPEN_SOURCE}/openssl/openssl-3.0.7/ -./config shared -if [[ ${OS_ARCH} =~ "x86_64" ]]; then - export CPU_CORES_NUM_x86=`cat /proc/cpuinfo |grep "cores" |wc -l` - make -j${CPU_CORES_NUM_x86} -elif [[ ${OS_ARCH} =~ "aarch64" ]]; then - export CPU_CORES_NUM_arm=`cat /proc/cpuinfo |grep "architecture" |wc -l` - make -j${CPU_CORES_NUM_arm} -else - echo "OS_ARCH: ${OS_ARCH} is unknown, set CPU_CORES_NUM=16 " - export CPU_CORES_NUM=16 - make -j${CPU_CORES_NUM} -fi -mkdir -p ${OPEN_SOURCE}/openssl/include/ -mkdir -p ${LIBRARY}/openssl/lib/ -cp -rf ${OPEN_SOURCE}/openssl/openssl-3.0.7/include/* ${OPEN_SOURCE}/openssl/include/ -cp -rf ${OPEN_SOURCE}/openssl/openssl-3.0.7/*.a ${LIBRARY}/openssl/lib -echo "copy lib finished" - -#zlib -cd ${OPEN_SOURCE}/zlib/zlib-1.2.13 -mkdir -p ${OPEN_SOURCE}/zlib/include -cp zconf.h zlib.h ${OPEN_SOURCE}/zlib/include diff --git a/pkg/CMakeLists.txt b/pkg/CMakeLists.txt index d78532fc..05630fd2 100644 --- a/pkg/CMakeLists.txt +++ b/pkg/CMakeLists.txt @@ -25,8 +25,12 @@ if (UNIX) add_compile_definitions(WSEC_COMPILE_MIP_OTHER) endif () +if(NOT USE_OSS_BUILD) + add_compile_options(-w) +endif() + # add subdir add_subdirectory(src) if(NOT USE_OSS_BUILD) - add_subdirectory(test) + add_subdirectory(test) endif() diff --git a/pkg/cfg/cantiand-ut.ini b/pkg/cfg/cantiand-ut.ini new file mode 100644 index 00000000..86bcf5bc --- /dev/null +++ b/pkg/cfg/cantiand-ut.ini @@ -0,0 +1,14 @@ +TEMP_BUFFER_SIZE = 1G +DATA_BUFFER_SIZE = 2G +SHARED_POOL_SIZE = 1G +LOG_BUFFER_SIZE = 64M +DBWR_PROCESSES = 8 +LOG_BUFFER_COUNT = 8 +LSNR_ADDR = 127.0.0.1 +LSNR_PORT = 1611 +SESSIONS = 1500 +MYSQL_DEPLOY_GROUP_ID = 5000 +_SYS_PASSWORD = Ck311QUAECd2bdgppbA85VqPjjV/Wn/1jByyAWxktckKOjFf59olvzHvQWeKumrSJBjcV8RxupSQveBbc1i0J63n4kpk1+m43FyDL2XyBzQ50cVWsOFNXw== +SHM_MYSQL_CPU_GROUP_INFO = 0-3 +SHM_CPU_GROUP_INFO = 0-3 +CLUSTER_DATABASE = TRUE \ No newline at end of file diff --git a/pkg/cfg/cms-ut.ini b/pkg/cfg/cms-ut.ini new file mode 100644 index 00000000..9a6240b5 --- /dev/null +++ b/pkg/cfg/cms-ut.ini @@ -0,0 +1,23 @@ +_LOG_BACKUP_FILE_COUNT = 10 +NODE_ID = 0 +GCC_HOME = /tmp/cantian_ut/data/gcc_home/gcc_file +GCC_TYPE = FILE +CMS_LOG = /tmp/cantian_ut/data/log +_PORT = 14587 +_IP = 127.0.0.1 +_LOG_LEVEL = 7 +_SPLIT_BRAIN = TRUE +_LOG_MAX_FILE_SIZE = 100M +_DETECT_DISK_TIMEOUT = 6000 +_DISK_DETECT_FILE = gcc_file, +_EXIT_NUM_COUNT_FILE = /tmp/cantian_ut/data/exit_num.txt +_CMS_MES_THREAD_NUM = 5 +_CMS_MES_MAX_SESSION_NUM = 40 +_CMS_MES_MESSAGE_POOL_COUNT = 1 +_CMS_MES_MESSAGE_QUEUE_COUNT = 1 +_CMS_MES_MESSAGE_BUFF_COUNT = 4096 +_CMS_MES_MESSAGE_CHANNEL_NUM = 1 +_CMS_NODE_FAULT_THRESHOLD = 5 +_USE_DBSTOR = FALSE +_CMS_MES_PIPE_TYPE = TCP +_CMS_MES_CRC_CHECK_SWITCH = TRUE diff --git a/pkg/src/cms/interface/cms_comm.c b/pkg/src/cms/interface/cms_comm.c index 55d82787..354638b6 100644 --- a/pkg/src/cms/interface/cms_comm.c +++ b/pkg/src/cms/interface/cms_comm.c @@ -32,6 +32,7 @@ #include "cs_uds.h" #include "securec.h" bool32 g_cluster_no_cms = CT_FALSE; + status_t cms_check_addr_dev_stat(struct sockaddr_in* addr) { struct ifaddrs* ifaddr; @@ -62,3 +63,8 @@ status_t cms_check_addr_dev_stat(struct sockaddr_in* addr) freeifaddrs(ifaddr); return CT_ERROR; } + +void cms_set_cluster_no_cms_switch(bool32 no_cms) +{ + g_cluster_no_cms = no_cms; +} diff --git a/pkg/src/cms/interface/cms_comm.h b/pkg/src/cms/interface/cms_comm.h index 4c44a53e..11579f1a 100644 --- a/pkg/src/cms/interface/cms_comm.h +++ b/pkg/src/cms/interface/cms_comm.h @@ -60,6 +60,7 @@ extern "C" { } while (0); status_t cms_check_addr_dev_stat(struct sockaddr_in* addr); +void cms_set_cluster_no_cms_switch(bool32 no_cms); #ifdef __cplusplus } diff --git a/pkg/src/cms/interface/cms_interface.h b/pkg/src/cms/interface/cms_interface.h index 3aeb5e92..fffeb396 100644 --- a/pkg/src/cms/interface/cms_interface.h +++ b/pkg/src/cms/interface/cms_interface.h @@ -88,6 +88,7 @@ status_t cms_set_res_data(uint32 slot_id, char* data, uint32 size); status_t cms_get_res_data(uint32 slot_id, char* data, uint32 max_size, uint32* size); status_t cms_env_init(void); void cms_res_inst_register_upgrade(cms_upgrade_op_t upgrade_func); +void cms_set_cluster_no_cms_switch(bool32 no_cms); #ifdef __cplusplus } diff --git a/pkg/src/ctsql/ctsql_stmt.c b/pkg/src/ctsql/ctsql_stmt.c index 54d58226..44a17d3f 100644 --- a/pkg/src/ctsql/ctsql_stmt.c +++ b/pkg/src/ctsql/ctsql_stmt.c @@ -1202,7 +1202,6 @@ static inline status_t sql_check_pre_exec(sql_stmt_t *stmt) CT_THROW_ERROR(ERR_REQUEST_OUT_OF_SQUENCE, "prepared."); return CT_ERROR; } -#ifndef CANTIAN_READ_WRITE // disable dml, except under procedure; disable create procedure if (((stmt->context->type > CTSQL_TYPE_INSERT && stmt->context->type < CTSQL_TYPE_DML_CEIL) || (stmt->context->type > CTSQL_TYPE_ROLLBACK_TO && stmt->context->type < CTSQL_TYPE_BACKUP) || @@ -1211,7 +1210,6 @@ static inline status_t sql_check_pre_exec(sql_stmt_t *stmt) CT_THROW_ERROR(ERR_CAPABILITY_NOT_SUPPORT, "DML or create_proc on cantian node"); return CT_ERROR; } -#endif return CT_SUCCESS; } diff --git a/pkg/src/ctsql/executor/explain/expl_executor.c b/pkg/src/ctsql/executor/explain/expl_executor.c index df535a17..31a71895 100644 --- a/pkg/src/ctsql/executor/explain/expl_executor.c +++ b/pkg/src/ctsql/executor/explain/expl_executor.c @@ -14,11 +14,11 @@ * See the Mulan PSL v2 for more details. * ------------------------------------------------------------------------- * - * ctsql_distinct.h + * expl_executor.c * * * IDENTIFICATION - * src/ctsql/executor/ctsql_distinct.h + * src/ctsql/executor/explain/expl_executor.c * * ------------------------------------------------------------------------- */ @@ -139,7 +139,7 @@ static status_t expl_send_explain_tail(sql_stmt_t *stmt, sql_cursor_t *cursor, e CTSQL_SAVE_STACK(stmt); // send divider - CT_RETURN_IFERR(expl_send_explain_divider(stmt, cursor, helper->width, &is_full)); + CT_RETURN_IFERR(expl_send_explain_divider(stmt, cursor, helper->width, &is_full)); CTSQL_RESTORE_STACK(stmt); return CT_SUCCESS; @@ -201,7 +201,8 @@ status_t expl_fmt_table_content(sql_stmt_t *stmt, sql_cursor_t *cursor, expl_hel return CT_SUCCESS; } -status_t expl_fmt_explain_content(sql_stmt_t *stmt, sql_cursor_t *cursor, expl_helper_t *helper, expl_fmt_func_t fmt_func) +status_t expl_fmt_explain_content(sql_stmt_t *stmt, sql_cursor_t *cursor, expl_helper_t *helper, + expl_fmt_func_t fmt_func) { char *row_buf = NULL; char *content = NULL; @@ -268,7 +269,7 @@ status_t expl_send_explain_rows(sql_stmt_t *stmt, sql_cursor_t *cursor, expl_hel static status_t expl_execute_explain_plan(sql_stmt_t *stmt, sql_cursor_t *cursor, plan_node_t *plan) { - expl_helper_t helper = { 0 }; + expl_helper_t helper = {0}; CTSQL_SAVE_STACK(stmt); // explain-executors init @@ -292,7 +293,7 @@ static status_t expl_execute_explain_plan(sql_stmt_t *stmt, sql_cursor_t *cursor status_t expl_execute(sql_stmt_t *stmt) { plan_node_t *node = (plan_node_t *)sql_get_plan(stmt); - CT_RETVALUE_IFTRUE(node == NULL,CT_ERRNO); + CT_RETVALUE_IFTRUE(node == NULL, CT_ERRNO); sql_cursor_t *cursor = NULL; CT_RETURN_IFERR(expl_pre_execute(stmt, &cursor)); @@ -304,4 +305,3 @@ status_t expl_execute(sql_stmt_t *stmt) return CT_SUCCESS; } - diff --git a/pkg/src/ctsql/executor/explain/expl_executor.h b/pkg/src/ctsql/executor/explain/expl_executor.h index 86ea3ca9..7186fafa 100644 --- a/pkg/src/ctsql/executor/explain/expl_executor.h +++ b/pkg/src/ctsql/executor/explain/expl_executor.h @@ -14,11 +14,11 @@ * See the Mulan PSL v2 for more details. * ------------------------------------------------------------------------- * - * ctsql_distinct.h + * expl_executor.h * * * IDENTIFICATION - * src/ctsql/executor/ctsql_distinct.h + * src/ctsql/executor/explain/expl_executor.h * * ------------------------------------------------------------------------- */ @@ -35,5 +35,4 @@ status_t expl_execute(sql_stmt_t *stmt); - #endif diff --git a/pkg/src/ctsql/executor/explain/expl_plan.c b/pkg/src/ctsql/executor/explain/expl_plan.c index 57856484..0b707e01 100644 --- a/pkg/src/ctsql/executor/explain/expl_plan.c +++ b/pkg/src/ctsql/executor/explain/expl_plan.c @@ -14,11 +14,11 @@ * See the Mulan PSL v2 for more details. * ------------------------------------------------------------------------- * - * ctsql_distinct.h + * expl_plan.h * * * IDENTIFICATION - * src/ctsql/executor/ctsql_distinct.h + * src/ctsql/executor/explain/expl_plan.h * * ------------------------------------------------------------------------- */ @@ -39,14 +39,14 @@ static inline status_t expl_row_put_text_data(expl_helper_t *helper, expl_col_ty static status_t expl_format_plan_id(expl_helper_t *helper) { - char buff[CT_MAX_INT32_STRLEN + 1] = { 0 }; + char buff[CT_MAX_INT32_STRLEN + 1] = {0}; int32 row_id = helper->row_helper.id++; int32 len = snprintf_s(buff, CT_MAX_INT32_STRLEN + 1, CT_MAX_INT32_STRLEN, "%lld", row_id); if (SECUREC_UNLIKELY(len == -1)) { return CT_ERROR; } - text_t rowid_str = { buff, len }; + text_t rowid_str = {buff, len}; return expl_row_put_text_data(helper, EXPL_COL_TYPE_ID, &rowid_str); } @@ -93,8 +93,8 @@ static status_t expl_format_plan_name(expl_helper_t *helper) if (row_helper->name == NULL && row_helper->alias == NULL) { return row_put_null(&helper->ra); } - - char buff[CT_MAX_DFLT_VALUE_LEN] = { 0 }; + + char buff[CT_MAX_DFLT_VALUE_LEN] = {0}; text_t *name = row_helper->name; uint32 offset = 0; if (name != NULL && name->str != NULL && name->len > 0) { @@ -112,7 +112,7 @@ static status_t expl_format_plan_name(expl_helper_t *helper) offset += alias->len; } - text_t new_name = { buff, offset }; + text_t new_name = {buff, offset}; return expl_row_put_text_data(helper, EXPL_COL_TYPE_TABLE, &new_name); } @@ -122,13 +122,13 @@ static status_t expl_format_plan_rows(expl_helper_t *helper) return row_put_null(&helper->ra); } - char buff[CT_MAX_INT64_STRLEN + 1] = { 0 }; + char buff[CT_MAX_INT64_STRLEN + 1] = {0}; int32 len = snprintf_s(buff, CT_MAX_INT64_STRLEN + 1, CT_MAX_INT64_STRLEN, "%lld", helper->row_helper.rows); if (SECUREC_UNLIKELY(len == -1)) { return CT_ERROR; } - text_t rows_str = { buff, len }; + text_t rows_str = {buff, len}; return expl_row_put_text_data(helper, EXPL_COL_TYPE_ROWS, &rows_str); } @@ -138,14 +138,14 @@ static status_t expl_format_plan_cost(expl_helper_t *helper) return row_put_null(&helper->ra); } - char buff[CT_MAX_INT64_STRLEN + 1] = { 0 }; + char buff[CT_MAX_INT64_STRLEN + 1] = {0}; int64 cost = (int64)helper->row_helper.cost; int32 len = snprintf_s(buff, CT_MAX_INT64_STRLEN + 1, CT_MAX_INT64_STRLEN, "%lld", cost); if (SECUREC_UNLIKELY(len == -1)) { return CT_ERROR; } - text_t cost_str = { buff, len }; + text_t cost_str = {buff, len}; return expl_row_put_text_data(helper, EXPL_COL_TYPE_COST, &cost_str); } @@ -159,16 +159,14 @@ static status_t expl_format_plan_remarks(expl_helper_t *helper) return row_put_null(&helper->ra); } -expl_column_t g_expl_columns[] = { - { EXPL_COL_TYPE_ID, {"Id", 2}, 4, expl_format_plan_id }, - { EXPL_COL_TYPE_OPERATION, {"Operation", 9}, 20, expl_format_plan_operation }, - { EXPL_COL_TYPE_OWNER, {"Owner", 5}, 10, expl_format_plan_owner }, - { EXPL_COL_TYPE_TABLE, {"Name", 4}, 10, expl_format_plan_name }, - { EXPL_COL_TYPE_ROWS, {"Rows", 4}, 10, expl_format_plan_rows }, - { EXPL_COL_TYPE_COST, {"Cost", 4}, 10, expl_format_plan_cost }, - { EXPL_COL_TYPE_BYTES, {"Bytes", 5}, 10, expl_format_plan_bytes }, - { EXPL_COL_TYPE_REMARK, {"Remark", 6}, 10, expl_format_plan_remarks } -}; +expl_column_t g_expl_columns[] = {{EXPL_COL_TYPE_ID, {"Id", 2}, 4, expl_format_plan_id}, + {EXPL_COL_TYPE_OPERATION, {"Operation", 9}, 20, expl_format_plan_operation}, + {EXPL_COL_TYPE_OWNER, {"Owner", 5}, 10, expl_format_plan_owner}, + {EXPL_COL_TYPE_TABLE, {"Name", 4}, 10, expl_format_plan_name}, + {EXPL_COL_TYPE_ROWS, {"Rows", 4}, 10, expl_format_plan_rows}, + {EXPL_COL_TYPE_COST, {"Cost", 4}, 10, expl_format_plan_cost}, + {EXPL_COL_TYPE_BYTES, {"Bytes", 5}, 10, expl_format_plan_bytes}, + {EXPL_COL_TYPE_REMARK, {"Remark", 6}, 10, expl_format_plan_remarks}}; text_t *expl_get_explcol_name(uint32 idx) { @@ -179,7 +177,7 @@ text_t *expl_get_explcol_name(uint32 idx) } void row_helper_init(row_helper_t *helper, plan_node_t *plan, text_t *operation, text_t *owner, text_t *name, - text_t *alias) + text_t *alias) { helper->operation = operation; helper->owner = owner; @@ -198,8 +196,8 @@ void expl_helper_init(expl_helper_t *helper) } } -status_t expl_format_plan_node_row(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth, char *oper_str, - text_t *owner, text_t *name, text_t *alias) +status_t expl_format_plan_node_row(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth, + char *oper_str, text_t *owner, text_t *name, text_t *alias) { text_t oper = { oper_str, strlen(oper_str) }; helper->depth = depth; @@ -249,14 +247,14 @@ status_t expl_format_expr_tree_plan(sql_stmt_t *stmt, expl_helper_t *helper, exp } status_t expl_format_cond_node_plan(sql_stmt_t *stmt, expl_helper_t *helper, cond_node_t *cond, uint32 depth, - bool32 *has_select) + bool32 *has_select) { visit_assist_t va = {0}; sql_init_visit_assist(&va, stmt, NULL); va.excl_flags = VA_EXCL_PRIOR; va.param0 = (void *)helper; - va.result0 = CT_FALSE; // selectstatement in the expr - va.result1 = (has_select == NULL); // TRUE: execute, FALSE: not execute; + va.result0 = CT_FALSE; // selectstatement in the expr + va.result1 = (has_select == NULL); // TRUE: execute, FALSE: not execute; va.result2 = depth; CT_RETURN_IFERR(visit_cond_node(&va, cond, expl_format_expr_node_plan)); @@ -264,7 +262,7 @@ status_t expl_format_cond_node_plan(sql_stmt_t *stmt, expl_helper_t *helper, con *has_select = va.result0; } - return CT_SUCCESS; + return CT_SUCCESS; } status_t expl_format_default_plan_node(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) @@ -318,10 +316,10 @@ status_t expl_format_user_rowid_scan_plan(sql_stmt_t *stmt, expl_helper_t *helpe { // todo sql_table_t *table = plan->scan_p.table; - CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS BY ROWID", - &table->user.value, &table->name.value, &table->alias.value)); - CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth + 1, "ROWID SCAN", - &table->user.value, &table->name.value, &table->alias.value)); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS BY ROWID", &table->user.value, + &table->name.value, &table->alias.value)); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth + 1, "ROWID SCAN", &table->user.value, + &table->name.value, &table->alias.value)); // todo return CT_SUCCESS; } @@ -333,10 +331,9 @@ status_t expl_format_normal_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *hel sql_table_t *table = plan->scan_p.table; knl_dictionary_t *dc = &table->entry->dc; - if ((dc->is_sysnonym == CT_TRUE) && (dc->type == DICT_TYPE_TABLE || - dc->type == DICT_TYPE_TEMP_TABLE_TRANS || - dc->type == DICT_TYPE_TEMP_TABLE_SESSION || - dc->type == DICT_TYPE_TABLE_NOLOGGING)) { + if ((dc->is_sysnonym == CT_TRUE) && + (dc->type == DICT_TYPE_TABLE || dc->type == DICT_TYPE_TEMP_TABLE_TRANS || + dc->type == DICT_TYPE_TEMP_TABLE_SESSION || dc->type == DICT_TYPE_TABLE_NOLOGGING)) { dc_entry_t *entry = DC_ENTRY(dc); owner.str = entry->user->desc.name; owner.len = (uint32)strlen(owner.str); @@ -346,8 +343,8 @@ status_t expl_format_normal_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *hel owner = *(text_t *)&plan->scan_p.table->user; name = *(text_t *)&plan->scan_p.table->name; } - CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS FULL", - &table->user.value, &table->name.value, &table->alias.value)); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS FULL", &table->user.value, + &table->name.value, &table->alias.value)); return CT_SUCCESS; } @@ -357,13 +354,14 @@ status_t expl_format_view_as_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *he plan_node_t *select_plan = table->select_ctx->plan; plan_node_t *next_plan = select_plan->select_p.next; - CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "VIEW", - &table->user.value, &table->name.value, &table->alias.value)); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "VIEW", &table->user.value, &table->name.value, + &table->alias.value)); return expl_format_plan_node(stmt, helper, next_plan, depth + 1); } -status_t expl_format_subselect_as_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +status_t expl_format_subselect_as_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, + uint32 depth) { char *oper = NULL; plan_node_t *next_plan = NULL; @@ -378,8 +376,8 @@ status_t expl_format_subselect_as_table_scan_plan(sql_stmt_t *stmt, expl_helper_ next_plan = select_plan->select_p.next; } - CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, - &table->user.value, &table->name.value, &table->alias.value)); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, &table->user.value, &table->name.value, + &table->alias.value)); return expl_format_plan_node(stmt, helper, next_plan, depth + 1); } @@ -387,8 +385,8 @@ status_t expl_format_subselect_as_table_scan_plan(sql_stmt_t *stmt, expl_helper_ status_t expl_format_func_as_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) { sql_table_t *table = plan->scan_p.table; - CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS FULL", - &table->user.value, &table->name.value, &table->alias.value)); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS FULL", &table->user.value, + &table->name.value, &table->alias.value)); return CT_SUCCESS; } @@ -399,12 +397,12 @@ status_t expl_format_with_as_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *he if (select_plan->select_p.next->type == PLAN_NODE_WITHAS_MTRL) { withas_mtrl_plan_t *withas_p = &select_plan->select_p.next->withas_p; - return expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS FULL", - NULL, &withas_p->name, &table->alias.value); + return expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS FULL", NULL, &withas_p->name, + &table->alias.value); } - CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS FULL", - &table->user.value, &table->name.value, &table->alias.value)); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TABLE ACCESS FULL", &table->user.value, + &table->name.value, &table->alias.value)); return CT_SUCCESS; } @@ -480,60 +478,57 @@ status_t expl_format_union_all_plan(sql_stmt_t *stmt, expl_helper_t *helper, pla return CT_SUCCESS; } -static expl_plan_t g_expl_plan_funcs[] = { - { PLAN_NODE_QUERY, expl_format_query_plan }, - { PLAN_NODE_UNION, expl_format_union_plan }, - { PLAN_NODE_UNION_ALL, expl_format_union_all_plan }, - { PLAN_NODE_MINUS, expl_format_default_plan_node }, - { PLAN_NODE_HASH_MINUS, expl_format_default_plan_node }, - { PLAN_NODE_MERGE, expl_format_default_plan_node }, - { PLAN_NODE_INSERT, expl_format_default_plan_node }, - { PLAN_NODE_DELETE, expl_format_default_plan_node }, - { PLAN_NODE_UPDATE, expl_format_default_plan_node }, - { PLAN_NODE_SELECT, expl_format_select_plan }, - { PLAN_NODE_JOIN, expl_format_default_plan_node }, - { PLAN_NODE_SORT_GROUP, expl_format_default_plan_node }, - { PLAN_NODE_MERGE_SORT_GROUP, expl_format_default_plan_node }, - { PLAN_NODE_HASH_GROUP, expl_format_default_plan_node }, - { PLAN_NODE_INDEX_GROUP, expl_format_default_plan_node }, - { PLAN_NODE_QUERY_SORT, expl_format_default_plan_node }, - { PLAN_NODE_SELECT_SORT, expl_format_default_plan_node }, - { PLAN_NODE_AGGR, expl_format_default_plan_node }, - { PLAN_NODE_INDEX_AGGR, expl_format_default_plan_node }, - { PLAN_NODE_SORT_DISTINCT, expl_format_default_plan_node }, - { PLAN_NODE_HASH_DISTINCT, expl_format_default_plan_node }, - { PLAN_NODE_INDEX_DISTINCT, expl_format_default_plan_node }, - { PLAN_NODE_HAVING, expl_format_default_plan_node }, - { PLAN_NODE_SCAN, expl_format_scan_plan }, - { PLAN_NODE_QUERY_LIMIT, expl_format_default_plan_node }, - { PLAN_NODE_SELECT_LIMIT, expl_format_default_plan_node }, - { PLAN_NODE_CONNECT, expl_format_default_plan_node }, - { PLAN_NODE_FILTER, expl_format_default_plan_node }, - { PLAN_NODE_WINDOW_SORT, expl_format_default_plan_node }, - { PLAN_NODE_REMOTE_SCAN, expl_format_default_plan_node }, - { PLAN_NODE_GROUP_MERGE, expl_format_default_plan_node }, - { PLAN_NODE_HASH_GROUP_PAR, expl_format_default_plan_node }, - { PLAN_NODE_HASH_MTRL, expl_format_default_plan_node }, - { PLAN_NODE_CONCATE, expl_format_default_plan_node }, - { PLAN_NODE_QUERY_SORT_PAR, expl_format_default_plan_node }, - { PLAN_NODE_QUERY_SIBL_SORT, expl_format_default_plan_node }, - { PLAN_NODE_GROUP_CUBE, expl_format_default_plan_node }, - { PLAN_NODE_HASH_GROUP_PIVOT, expl_format_default_plan_node }, - { PLAN_NODE_UNPIVOT, expl_format_default_plan_node }, - { PLAN_NODE_ROWNUM, expl_format_default_plan_node }, - { PLAN_NODE_FOR_UPDATE, expl_format_default_plan_node }, - { PLAN_NODE_WITHAS_MTRL, expl_format_default_plan_node }, - { PLAN_NODE_CONNECT_MTRL, expl_format_default_plan_node }, - { PLAN_NODE_CONNECT_HASH, expl_format_default_plan_node }, - { PLAN_NODE_VM_VIEW_MTRL, expl_format_default_plan_node } -}; +static expl_plan_t g_expl_plan_funcs[] = {{PLAN_NODE_QUERY, expl_format_query_plan}, + {PLAN_NODE_UNION, expl_format_union_plan}, + {PLAN_NODE_UNION_ALL, expl_format_union_all_plan}, + {PLAN_NODE_MINUS, expl_format_default_plan_node}, + {PLAN_NODE_HASH_MINUS, expl_format_default_plan_node}, + {PLAN_NODE_MERGE, expl_format_default_plan_node}, + {PLAN_NODE_INSERT, expl_format_default_plan_node}, + {PLAN_NODE_DELETE, expl_format_default_plan_node}, + {PLAN_NODE_UPDATE, expl_format_default_plan_node}, + {PLAN_NODE_SELECT, expl_format_select_plan}, + {PLAN_NODE_JOIN, expl_format_default_plan_node}, + {PLAN_NODE_SORT_GROUP, expl_format_default_plan_node}, + {PLAN_NODE_MERGE_SORT_GROUP, expl_format_default_plan_node}, + {PLAN_NODE_HASH_GROUP, expl_format_default_plan_node}, + {PLAN_NODE_INDEX_GROUP, expl_format_default_plan_node}, + {PLAN_NODE_QUERY_SORT, expl_format_default_plan_node}, + {PLAN_NODE_SELECT_SORT, expl_format_default_plan_node}, + {PLAN_NODE_AGGR, expl_format_default_plan_node}, + {PLAN_NODE_INDEX_AGGR, expl_format_default_plan_node}, + {PLAN_NODE_SORT_DISTINCT, expl_format_default_plan_node}, + {PLAN_NODE_HASH_DISTINCT, expl_format_default_plan_node}, + {PLAN_NODE_INDEX_DISTINCT, expl_format_default_plan_node}, + {PLAN_NODE_HAVING, expl_format_default_plan_node}, + {PLAN_NODE_SCAN, expl_format_scan_plan}, + {PLAN_NODE_QUERY_LIMIT, expl_format_default_plan_node}, + {PLAN_NODE_SELECT_LIMIT, expl_format_default_plan_node}, + {PLAN_NODE_CONNECT, expl_format_default_plan_node}, + {PLAN_NODE_FILTER, expl_format_default_plan_node}, + {PLAN_NODE_WINDOW_SORT, expl_format_default_plan_node}, + {PLAN_NODE_REMOTE_SCAN, expl_format_default_plan_node}, + {PLAN_NODE_GROUP_MERGE, expl_format_default_plan_node}, + {PLAN_NODE_HASH_GROUP_PAR, expl_format_default_plan_node}, + {PLAN_NODE_HASH_MTRL, expl_format_default_plan_node}, + {PLAN_NODE_CONCATE, expl_format_default_plan_node}, + {PLAN_NODE_QUERY_SORT_PAR, expl_format_default_plan_node}, + {PLAN_NODE_QUERY_SIBL_SORT, expl_format_default_plan_node}, + {PLAN_NODE_GROUP_CUBE, expl_format_default_plan_node}, + {PLAN_NODE_HASH_GROUP_PIVOT, expl_format_default_plan_node}, + {PLAN_NODE_UNPIVOT, expl_format_default_plan_node}, + {PLAN_NODE_ROWNUM, expl_format_default_plan_node}, + {PLAN_NODE_FOR_UPDATE, expl_format_default_plan_node}, + {PLAN_NODE_WITHAS_MTRL, expl_format_default_plan_node}, + {PLAN_NODE_CONNECT_MTRL, expl_format_default_plan_node}, + {PLAN_NODE_CONNECT_HASH, expl_format_default_plan_node}, + {PLAN_NODE_VM_VIEW_MTRL, expl_format_default_plan_node}}; status_t expl_format_plan_node(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) { - CM_ASSERT(plan->type <= sizeof(g_expl_plan_funcs)/sizeof(expl_plan_t)); + CM_ASSERT(plan->type <= sizeof(g_expl_plan_funcs) / sizeof(expl_plan_t)); CM_ASSERT(plan->type == g_expl_plan_funcs[plan->type - PLAN_NODE_QUERY].type); CM_ASSERT(g_expl_plan_funcs[plan->type - PLAN_NODE_QUERY].explain_plan_func != NULL); return g_expl_plan_funcs[plan->type - PLAN_NODE_QUERY].explain_plan_func(stmt, helper, plan, depth); } - diff --git a/pkg/src/ctsql/executor/explain/expl_plan.h b/pkg/src/ctsql/executor/explain/expl_plan.h index 097f2da2..7d12de64 100644 --- a/pkg/src/ctsql/executor/explain/expl_plan.h +++ b/pkg/src/ctsql/executor/explain/expl_plan.h @@ -14,17 +14,17 @@ * See the Mulan PSL v2 for more details. * ------------------------------------------------------------------------- * - * ctsql_distinct.h + * expl_plan.h * * * IDENTIFICATION - * src/ctsql/executor/ctsql_distinct.h + * src/ctsql/executor/explain/expl_plan.h * * ------------------------------------------------------------------------- */ - #ifndef __EXPL_PLAN_H__ - #define __EXPL_PLAN_H__ +#ifndef __EXPL_PLAN_H__ +#define __EXPL_PLAN_H__ #include "cm_memory.h" #include "cm_row.h" @@ -47,32 +47,32 @@ typedef enum { } expl_col_type_t; typedef struct st_row_helper { - int32 id; // Id - text_t *operation; // Operation - text_t *owner; // Owner - text_t *name; // Table name - text_t *alias; // Table name alias - int64 rows; // Rows - double cost; // Cost - int64 bytes; // bytes - int64 remark; // remark + int32 id; // Id + text_t *operation; // Operation + text_t *owner; // Owner + text_t *name; // Table name + text_t *alias; // Table name alias + int64 rows; // Rows + double cost; // Cost + int64 bytes; // bytes + int64 remark; // remark } row_helper_t; typedef struct st_expl_helper { mtrl_rowid_t row_id; - uint32 mtrl_id; + uint32 mtrl_id; row_assist_t ra; char *row_buf; - text_t tmp_buf; // for operation + text_t tmp_buf; // for operation - row_helper_t row_helper; // for format; - uint32 fmt_sizes[EXPL_COL_TYPE_MAX]; // format sizes for every column - int32 depth; // depth + row_helper_t row_helper; // for format; + uint32 fmt_sizes[EXPL_COL_TYPE_MAX]; // format sizes for every column + int32 depth; // depth sql_cursor_t *cursor; - sql_query_t *query; // reference sql query context - sql_array_t *ssa; // SubSelect Array for subselect expr + sql_query_t *query; // reference sql query context + sql_array_t *ssa; // SubSelect Array for subselect expr // format uint32 width; @@ -83,11 +83,10 @@ typedef status_t (*expl_column_func_t)(expl_helper_t *helper); typedef struct st_expl_column { expl_col_type_t type; text_t name; - uint32 fmt_size; // default format size + uint32 fmt_size; // default format size expl_column_func_t expl_column_func; } expl_column_t; - typedef status_t (*expl_plan_func_t)(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth); typedef struct st_expl_plan { diff --git a/pkg/src/kernel/include/db_defs.h b/pkg/src/kernel/include/db_defs.h index 31806025..3fc57eeb 100644 --- a/pkg/src/kernel/include/db_defs.h +++ b/pkg/src/kernel/include/db_defs.h @@ -25,6 +25,7 @@ #ifndef __KNL_DB_DEFS_H__ #define __KNL_DB_DEFS_H__ +#include "dcl_defs.h" #include "knl_defs.h" #include "persist_defs.h" diff --git a/pkg/src/kernel/include/dml_defs.h b/pkg/src/kernel/include/dml_defs.h index 7668d71f..76ab4275 100644 --- a/pkg/src/kernel/include/dml_defs.h +++ b/pkg/src/kernel/include/dml_defs.h @@ -26,6 +26,7 @@ #define __KNL_DML_DEFS_H__ #include "knl_defs.h" +#include "index_defs.h" #ifdef __cplusplus extern "C" { diff --git a/pkg/src/utils/ctbackup/ctbackup.c b/pkg/src/utils/ctbackup/ctbackup.c index a9613b36..4b392ed6 100644 --- a/pkg/src/utils/ctbackup/ctbackup.c +++ b/pkg/src/utils/ctbackup/ctbackup.c @@ -28,13 +28,13 @@ #include "ctbackup_common.h" #ifdef WIN32 -const char *cantiand_get_dbversion() +char *cantiand_get_dbversion() { return "NONE"; } #else -extern const char* cantiand_get_dbversion(void); +extern char* cantiand_get_dbversion(void); #endif diff --git a/pkg/test/unit_test/ut/CMakeLists.txt b/pkg/test/unit_test/ut/CMakeLists.txt index c68e69ba..777480c8 100644 --- a/pkg/test/unit_test/ut/CMakeLists.txt +++ b/pkg/test/unit_test/ut/CMakeLists.txt @@ -5,4 +5,5 @@ add_subdirectory(mes) add_subdirectory(cms) add_subdirectory(server) add_subdirectory(common) -add_subdirectory(ctbackup) \ No newline at end of file +add_subdirectory(ctbackup) +add_subdirectory(ctsql) \ No newline at end of file diff --git a/pkg/test/unit_test/ut/cms/cms_disk_lock_test.cpp b/pkg/test/unit_test/ut/cms/cms_disk_lock_test.cpp index 45e0c007..cc5a38b8 100644 --- a/pkg/test/unit_test/ut/cms/cms_disk_lock_test.cpp +++ b/pkg/test/unit_test/ut/cms/cms_disk_lock_test.cpp @@ -35,7 +35,8 @@ TEST_F(CmsDiskLockTest, lock_init_fail) { cms_disk_lock_t lock = {0}; int64 node_id = 0; - lock.flock = malloc(sizeof(cms_flock_t)); + lock.flock = (cms_flock_t*)malloc(sizeof(cms_flock_t)); + EXPECT_NE(lock.flock, nullptr); int ret = cms_disk_lock_init_file(&lock, "./fake", 0, node_id, false); EXPECT_EQ(ret, CT_SUCCESS); } \ No newline at end of file diff --git a/pkg/test/unit_test/ut/common/common_device_test.cpp b/pkg/test/unit_test/ut/common/common_device_test.cpp index e0c25f38..4d091fd3 100644 --- a/pkg/test/unit_test/ut/common/common_device_test.cpp +++ b/pkg/test/unit_test/ut/common/common_device_test.cpp @@ -31,6 +31,7 @@ TEST_F(CMDeviceTest, CreateDeviceTest) { MOCKER(cm_dbs_pg_create).stubs().will(returnValue(CT_SUCCESS)); status_t ret = cm_create_device("TEST", DEV_TYPE_PGPOOL, 0, NULL); + EXPECT_EQ(ret, CT_SUCCESS); GlobalMockObject::reset(); record_io_stat_print(); } \ No newline at end of file diff --git a/pkg/test/unit_test/ut/ctsql/CMakeLists.txt b/pkg/test/unit_test/ut/ctsql/CMakeLists.txt new file mode 100644 index 00000000..10d2b4db --- /dev/null +++ b/pkg/test/unit_test/ut/ctsql/CMakeLists.txt @@ -0,0 +1,29 @@ +message(STATUS "build ctsql_ut...") + +include_directories(${CMAKE_SOURCE_DIR}/pkg/src/ctsql) +include_directories(${CMAKE_SOURCE_DIR}/pkg/src/common) +include_directories(${CMAKE_SOURCE_DIR}/pkg/src/kernel/include) +include_directories(${CMAKE_SOURCE_DIR}/pkg/src/cms/interface) +include_directories(${CMAKE_SOURCE_DIR}/pkg/test/unit_test/ut/ctsql/stub) + +set(SERVER_UT_SOURCE ${CMAKE_SOURCE_DIR}/pkg/test/unit_test/ut/ctsql/stub/stub_ctsql.cpp + ${CMAKE_SOURCE_DIR}/pkg/test/unit_test/ut/ctsql/test_expl_execute.cpp + ${CMAKE_SOURCE_DIR}/pkg/test/unit_test/ut/ctsql/test_ctsql_main.cpp) + +#add_compile_options(-fno-common) +add_compile_options(-Wall -fpermissive) + +#add_link_options(-Wl, -Bsymbolic) +add_link_options(-rdynamic) + +add_executable(ctsql_test ${SERVER_UT_SOURCE}) +set_target_properties(ctsql_test PROPERTIES LINKER_LANGUAGE "CXX") + +target_link_libraries(ctsql_test + -Wl,--start-group + gtest mockcpp gmock zetms zecms zeprotocol m rt dl z zstd lz4 + zecmssrc zeclient zerc zecommon zemes zefdsa zectc zecluster + zeserver zekernel zesql pthread z + -Wl,--end-group) +target_compile_definitions(ctsql_test PRIVATE -DCT_LIB_VERSION=${DD_CT_LIB_VERSION}) +target_compile_definitions(ctsql_test PRIVATE -DGETDBVERSION=${DD_GETDBVERSION}) diff --git a/pkg/test/unit_test/ut/ctsql/stub/stub_ctsql.cpp b/pkg/test/unit_test/ut/ctsql/stub/stub_ctsql.cpp new file mode 100644 index 00000000..e8d40e4d --- /dev/null +++ b/pkg/test/unit_test/ut/ctsql/stub/stub_ctsql.cpp @@ -0,0 +1,150 @@ +#include "gtest/gtest.h" +#include + +#include +#include "stub_ctsql.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern instance_t *g_instance; + +#ifdef __cplusplus +} +#endif + +#define STUB_SYS_USER "SYS" +#define STUB_DEFAULT_USER "utdb" +#define STUB_CTDB_HOME (char *)"/tmp/cantian_ut" + +session_t *g_ut_session; +std::string g_ctdb_home; +std::string g_data_dir; + +status_t stub_init_runtime_env() +{ + g_ctdb_home = std::string(STUB_CTDB_HOME); + g_data_dir = g_ctdb_home + SEPERATOR + std::string("data"); + // todo : + // clear environment and make environment. + system("rm -rf /tmp/cantian_ut/data/*"); + // set.. + if (setenv(CMS_ENV_CMS_HOME, STUB_CTDB_HOME, 1) != 0) { + return CT_ERROR; + } + + if (setenv(CT_ENV_HOME, STUB_CTDB_HOME, 1) != 0) { + return CT_ERROR; + } + return CT_SUCCESS; +} + +status_t stub_alloc_new_session(session_t **session) +{ + session_t *tmp_session = NULL; + + agent_t *agent = (agent_t *)malloc(sizeof(agent_t)); + if (agent == NULL) { + CT_THROW_ERROR(ERR_ALLOC_MEMORY, (uint64)sizeof(agent_t), "replcia agent"); + return CT_ERROR; + } + (void)memset_s(agent, sizeof(agent_t), 0, sizeof(agent_t)); + status_t ret = srv_create_agent_private_area(agent); + if (ret != CT_SUCCESS) { + free(agent); + return ret; + } + + ret = srv_alloc_session(&tmp_session, NULL, SESSION_TYPE_USER); + if (ret != CT_SUCCESS) { + free(agent->area_buf); + free(agent); + return ret; + } + + srv_bind_sess_agent(tmp_session, agent); + *session = tmp_session; + + return CT_SUCCESS; +} + +status_t stub_srv_start_lsnr(void) +{ + g_instance->lsnr.tcp_service.type = LSNR_TYPE_SERVICE; + g_instance->lsnr.uds_service.type = LSNR_TYPE_UDS; + return CT_SUCCESS; +} + +status_t stub_instance_init() +{ + status_t ret = CT_ERROR; + if (g_ut_session != NULL) { + return CT_SUCCESS; + } + + ret = stub_init_runtime_env(); + if (ret != CT_SUCCESS) { + return ret; + } + + ret = srv_instance_startup(STARTUP_NOMOUNT, CT_FALSE, CT_FALSE, CT_FALSE); + if (ret != CT_SUCCESS) { + return ret; + } + cms_set_cluster_no_cms_switch(CT_TRUE); + + ret = stub_alloc_new_session(&g_ut_session); + if (ret != CT_SUCCESS) { + return ret; + } + + (void)sprintf_s(g_ut_session->curr_schema, CT_NAME_BUFFER_SIZE, STUB_SYS_USER); + (void)sprintf_s(g_ut_session->db_user, CT_NAME_BUFFER_SIZE, STUB_SYS_USER); + cm_str2text(g_ut_session->db_user, &g_ut_session->curr_user); + + return CT_SUCCESS; +} + +status_t stub_create_database() +{ + sql_stmt_t *stmt = nullptr; + text_t cmd_create_db = {0}; + std::string str_create_db = std::string("CREATE DATABASE CLUSTERED ") + std::string(STUB_DEFAULT_USER) + std::string(" ") + + std::string("CONTROLFILE ('") + g_data_dir + SEPERATOR + std::string("ctrl1', '") + g_data_dir + SEPERATOR + + std::string("ctrl2', '") + g_data_dir + SEPERATOR + std::string("ctrl3') ") + + std::string("system TABLESPACE DATAFILE '") + g_data_dir + SEPERATOR + std::string("system' SIZE 128M ") + + std::string("nologging TABLESPACE TEMPFILE '") + g_data_dir + SEPERATOR + std::string("temp2_01' SIZE 128M ") + + std::string("nologging undo TABLESPACE TEMPFILE '") + g_data_dir + SEPERATOR + std::string("temp2_undo' SIZE 128M ") + + std::string("default TABLESPACE DATAFILE '") + g_data_dir + SEPERATOR + std::string("user1' SIZE 16M ") + + std::string("instance node 0 ") + + std::string("undo TABLESPACE DATAFILE '") + g_data_dir + SEPERATOR + std::string("undo01' SIZE 128M ") + + std::string("temporary TABLESPACE TEMPFILE '") + g_data_dir + SEPERATOR + std::string("temp1_01' SIZE 16M ") + + std::string("nologging undo TABLESPACE TEMPFILE '") + g_data_dir + SEPERATOR + std::string("temp2_undo_01' SIZE 128M ") + + std::string("LOGFILE ('") + g_data_dir + SEPERATOR + std::string("log1' SIZE 256M, '") + g_data_dir + SEPERATOR + + std::string("log2' SIZE 256M, '") + g_data_dir + SEPERATOR + std::string("log3' SIZE 256M)"); + + status_t ret = sql_alloc_stmt(g_ut_session, &stmt); + if (ret != CT_SUCCESS) { + return ret; + } + + text_t sql = {0}; + source_location_t loc = {1, 1}; + sql.str = (char *)str_create_db.c_str(); + sql.len = str_create_db.length(); + ret = sql_parse(stmt, &sql, &loc); + if (ret != CT_SUCCESS) { + sql_free_stmt(stmt); + return ret; + } + g_ut_session->current_stmt = stmt; + stmt->is_verifying = CT_TRUE; + + ret = sql_execute(stmt); + if (ret != CT_SUCCESS) { + sql_free_stmt(stmt); + return ret; + } + return CT_SUCCESS; +} diff --git a/pkg/test/unit_test/ut/ctsql/stub/stub_ctsql.h b/pkg/test/unit_test/ut/ctsql/stub/stub_ctsql.h new file mode 100644 index 00000000..d5459d03 --- /dev/null +++ b/pkg/test/unit_test/ut/ctsql/stub/stub_ctsql.h @@ -0,0 +1,22 @@ + +#ifndef __UT_STUB_CTSQL_H__ +#define __UT_STUB_CTSQL_H__ + +#include "knl_interface.h" +#include "cms_interface.h" +#include "cm_defs.h" +#include "db_defs.h" +#include "srv_session.h" +#include "srv_instance.h" +#include "ctsql_parser.h" + +#ifdef WIN32 +#define SEPERATOR "\\" +#else +#define SEPERATOR "/" +#endif + +status_t stub_instance_init(); +status_t stub_create_database(); + +#endif diff --git a/pkg/test/unit_test/ut/ctsql/test_ctsql_main.cpp b/pkg/test/unit_test/ut/ctsql/test_ctsql_main.cpp new file mode 100644 index 00000000..6818cf5f --- /dev/null +++ b/pkg/test/unit_test/ut/ctsql/test_ctsql_main.cpp @@ -0,0 +1,32 @@ +#include "gtest/gtest.h" +#include + +#include "stub_ctsql.h" +#include "cm_defs.h" +#include "ctsql_parser.h" + +#ifdef __cplusplus +extern "C" { +#endif + +char *cantiand_get_dbversion() +{ + return "NONE"; +} + +#ifdef __cplusplus +} +#endif + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + + status_t ret = stub_instance_init(); + EXPECT_EQ(ret, CT_SUCCESS); + + ret = stub_create_database(); + EXPECT_EQ(ret, CT_SUCCESS); + + return RUN_ALL_TESTS(); +} diff --git a/pkg/test/unit_test/ut/ctsql/test_expl_execute.cpp b/pkg/test/unit_test/ut/ctsql/test_expl_execute.cpp new file mode 100644 index 00000000..3f8a9547 --- /dev/null +++ b/pkg/test/unit_test/ut/ctsql/test_expl_execute.cpp @@ -0,0 +1,29 @@ +#include "gtest/gtest.h" +#include + +#include + +#include "knl_interface.h" +#include "cm_defs.h" +#include "db_defs.h" +#include "srv_session.h" +#include "srv_instance.h" +#include "ctsql_parser.h" + +extern instance_t *g_instance; +extern session_t *g_ut_session; + +TEST(expl_test, test_explain_parse) +{ + text_t sql = {0}; + source_location_t loc = {1, 1}; + sql_stmt_t *stmt = nullptr; + + status_t ret = sql_alloc_stmt(g_ut_session, &stmt); + EXPECT_EQ(ret, CT_SUCCESS); + + sql.str = "explain select * from t1"; + sql.len = strlen(sql.str); + ret = sql_parse(stmt, &sql, &loc); + EXPECT_EQ(ret, CT_SUCCESS); +} diff --git a/pkg/test/unit_test/ut/message_queue/message_queue_test_main.cpp b/pkg/test/unit_test/ut/message_queue/message_queue_test_main.cpp index 23a28ad4..9ac368b7 100644 --- a/pkg/test/unit_test/ut/message_queue/message_queue_test_main.cpp +++ b/pkg/test/unit_test/ut/message_queue/message_queue_test_main.cpp @@ -32,12 +32,12 @@ protected: TEST_F(TestShm, shm_get_shm_type_and_addr_should_return_ok_when_normal) { - char *tokens[] = {"mmap", "test1", "test2"}; + const char *tokens[] = {"mmap", "test1", "test2"}; struct key_map_s *key_map = (key_map_s *)malloc(sizeof(key_map_s)); - int *count; - int *is_count; + int count = 0; + int is_count = 0; MOCKER(strcpy_s).stubs().will(returnValue(0)); - int ret = shm_get_shm_type_and_addr(tokens, key_map, 0, 0, count, is_count); + int ret = shm_get_shm_type_and_addr(tokens, key_map, 0, 0, &count, &is_count); EXPECT_EQ(ret, -1); free(key_map); } -- Gitee From 72b707414f1a191a5c49cc048cd71f89e0a4a618 Mon Sep 17 00:00:00 2001 From: lys <120677277@qq.com> Date: Mon, 31 Mar 2025 17:23:08 +0800 Subject: [PATCH 09/12] fix review --- pkg/src/ctsql/optimizer/ctsql_transform.c | 21 ++++++++++++--------- pkg/src/ctsql/optimizer/ctsql_transform.h | 9 +++++---- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/pkg/src/ctsql/optimizer/ctsql_transform.c b/pkg/src/ctsql/optimizer/ctsql_transform.c index a28669c6..8184d5ff 100644 --- a/pkg/src/ctsql/optimizer/ctsql_transform.c +++ b/pkg/src/ctsql/optimizer/ctsql_transform.c @@ -39,13 +39,13 @@ extern "C" { static transform_sql_t g_transformers[] = { - {CTSQL_TYPE_NONE, sql_transform_dummy }, - {CTSQL_TYPE_SELECT, ctsql_optimize_logic_select }, - {CTSQL_TYPE_UPDATE, sql_transform_dummy }, - {CTSQL_TYPE_INSERT, sql_transform_dummy }, - {CTSQL_TYPE_DELETE, sql_transform_dummy }, - {CTSQL_TYPE_MERGE, sql_transform_dummy }, - {CTSQL_TYPE_REPLACE, sql_transform_dummy }, + { CTSQL_TYPE_NONE, sql_transform_dummy }, + { CTSQL_TYPE_SELECT, ctsql_optimize_logic_select }, + { CTSQL_TYPE_UPDATE, sql_transform_dummy }, + { CTSQL_TYPE_INSERT, sql_transform_dummy }, + { CTSQL_TYPE_DELETE, sql_transform_dummy }, + { CTSQL_TYPE_MERGE, sql_transform_dummy }, + { CTSQL_TYPE_REPLACE, sql_transform_dummy }, }; typedef status_t (*sql_optimizer_func_t)(sql_stmt_t *stmt, sql_query_t *query); @@ -368,11 +368,13 @@ status_t ctsql_optimize_logically(sql_stmt_t *stmt) { uint32 count = sizeof(g_transformers) / sizeof(transform_sql_t) - 1; uint32 index = (uint32)stmt->context->type; - // SAVE_AND_RESET_NODE_STACK(stmt); + SAVE_AND_RESET_NODE_STACK(stmt); + if (index <= count) { CT_RETURN_IFERR(g_transformers[index].tranform(stmt, stmt->context->entry)); } - // SQL_RESTORE_NODE_STACK(stmt); + + SQL_RESTORE_NODE_STACK(stmt); return CT_SUCCESS; } @@ -442,6 +444,7 @@ static inline bool32 ctsql_check_subselect_if_as_table(sql_table_t *table) return CT_FALSE; } + status_t ctsql_tranform_subselect_as_table(sql_stmt_t *stmt, sql_query_t *query) { sql_array_t *tables = &query->tables; diff --git a/pkg/src/ctsql/optimizer/ctsql_transform.h b/pkg/src/ctsql/optimizer/ctsql_transform.h index caf93211..5bb33e27 100644 --- a/pkg/src/ctsql/optimizer/ctsql_transform.h +++ b/pkg/src/ctsql/optimizer/ctsql_transform.h @@ -69,10 +69,11 @@ typedef status_t (*sql_tranform_rule_func_t)(sql_stmt_t *stmt, sql_query_t *quer status_t ctsql_transform_one_rule(sql_stmt_t *stmt, sql_query_t *query, const char* rule_name, sql_tranform_rule_func_t proc); -#define CTSQL_APPLY_RULE(s, q, p) do {\ - if (ctsql_transform_one_rule(s, q, #p, p)) {\ - CT_LOG_DEBUG_ERR("Failed to transform one rule=%s", #p); \ - }\ +#define CTSQL_APPLY_RULE(s, q, p) \ + do { \ + if (ctsql_transform_one_rule(s, q, #p, p)) { \ + CT_LOG_DEBUG_ERR("Failed to transform one rule=%s", #p); \ + } \ } while (0); -- Gitee From 1198ffe446eea82eeea4a9bc3b3ae4352d1324cf Mon Sep 17 00:00:00 2001 From: pengbingjie Date: Mon, 31 Mar 2025 19:44:20 +0800 Subject: [PATCH 10/12] add explain oper --- pkg/src/ctsql/executor/explain/expl_plan.c | 513 ++++++++++++++++++++- pkg/src/ctsql/executor/explain/expl_plan.h | 1 + 2 files changed, 491 insertions(+), 23 deletions(-) diff --git a/pkg/src/ctsql/executor/explain/expl_plan.c b/pkg/src/ctsql/executor/explain/expl_plan.c index 0b707e01..93a73fcd 100644 --- a/pkg/src/ctsql/executor/explain/expl_plan.c +++ b/pkg/src/ctsql/executor/explain/expl_plan.c @@ -28,8 +28,54 @@ #include "expl_plan.h" #define EXPL_SGL_INDENT_SIZE 2 +#define EXPL_DEPTH_CALC_LEVEL 2 +#define SORT_ORDER_BY_ROWNUM(plan) (g_instance->sql.topn_threshold !=0 \ + && (plan)->query_sort.rownum_upper <= g_instance->sql.topn_threshold) + +static char* g_minus_names[] = { + "MINUS", + "INTERSECT", + "INTERSECT ALL", + "EXCEPT ALL" +}; + +static char* g_group_by_names[] = { + "SORT GROUP BY", + "MERGE SORT GROUP BY", + "HASH GROUP BY", + "INDEX GROUP BY" +}; + +static char *g_distinct_names[] = { + "SORT DISTINCT", + "HASH DISTINCT", + "INDEX DISTINCT" +}; + +static char* g_join_oper[][2] = { + { "", "" }, + { "NESTED LOOPS" , "NESTED LOOPS" }, + { "NESTED LOOPS" , "NESTED LOOPS" }, + { "NESTED LOOPS OUTER" , "NESTED LOOPS OUTER ANTI" }, + { "NESTED LOOPS FULL" , "NESTED LOOPS FULL" }, + { "HASH JOIN(R)" , "HASH JOIN(L)" }, + { "HASH JOIN OUTER(R)" , "HASH JOIN OUTER(L)" }, + { "HASH JOIN FULL(R)" , "HASH JOIN FULL(L)" }, + { "HASH JOIN OUTER(R)" , "HASH JOIN OUTER(L)" }, + { "MERGE JOIN" , "MERGE JOIN" }, + { "MERGE JOIN OUTER" , "MERGE JOIN OUTER" }, + { "MERGE JOIN FULL" , "MERGE JOIN FULL" }, + { "HASH JOIN SEMI(R)" , "HASH JOIN SEMI(L)" }, + { "HASH JOIN ANTI(R)" , "HASH JOIN ANTI(L)" }, + { "HASH JOIN ANTI NA(R)" , "HASH JOIN ANTI NA(L)" }, + { "HASH JOIN RIGHT SEMI(R)" , "HASH JOIN RIGHT SEMI(L)" }, + { "HASH JOIN RIGHT ANTI(R)" , "HASH JOIN RIGHT ANTI(L)" }, + { "HASH JOIN RIGHT ANTI NA(R)" , "HASH JOIN RIGHT ANTI NA(L)" }, + { "HASH JOIN PAR(R)" , "HASH JOIN PAR(L)" }, +}; status_t expl_format_plan_node(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth); +static status_t expl_format_join_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth); static inline status_t expl_row_put_text_data(expl_helper_t *helper, expl_col_type_t type, text_t *row_data) { @@ -184,8 +230,10 @@ void row_helper_init(row_helper_t *helper, plan_node_t *plan, text_t *operation, helper->name = name; helper->alias = alias; - helper->rows = plan->rows; - helper->cost = plan->cost; + if (plan != NULL) { + helper->rows = plan->rows; + helper->cost = plan->cost; + } } void expl_helper_init(expl_helper_t *helper) @@ -233,6 +281,18 @@ status_t expl_format_expr_node_plan(visit_assist_t *va, expr_node_t **node) return expl_format_plan_node(va->stmt, helper, plan->select_p.next, va->result2); } +status_t expl_format_aggr_node_plan(sql_stmt_t *stmt, expl_helper_t *helper, expr_node_t *node, uint32 depth) +{ + visit_assist_t va = {0}; + sql_init_visit_assist(&va, stmt, NULL); + va.excl_flags = VA_EXCL_PRIOR; + va.param0 = (void *)helper; + va.result0 = CT_FALSE; + va.result1 = CT_TRUE; + va.result2 = depth; + return visit_expr_node(&va, &node, expl_format_expr_node_plan); +} + status_t expl_format_expr_tree_plan(sql_stmt_t *stmt, expl_helper_t *helper, expr_tree_t *expr, uint32 depth) { visit_assist_t va = {0}; @@ -303,11 +363,60 @@ status_t expl_format_query_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_no return CT_SUCCESS; } +static inline bool32 expl_format_withas_has_mtrl(sql_withas_t *withas_plan) +{ + if (withas_plan == NULL || withas_plan->withas_factors->count == 0) { + return CT_FALSE; + } + uint32 i = 0; + sql_withas_factor_t *factor = NULL; + while (i < withas_plan->withas_factors->count) { + factor = (sql_withas_factor_t *)cm_galist_get(withas_plan->withas_factors, i++); + if (factor->is_mtrl) { + return CT_TRUE; + } + } + return CT_FALSE; +} + +static status_t expl_format_withas_plan_node(sql_stmt_t *stmt, expl_helper_t *helper, sql_withas_t *withas_plan, + uint32 depth) +{ + uint32 i = 0; + sql_withas_factor_t *factor = NULL; + while (i < withas_plan->withas_factors->count) { + factor = (sql_withas_factor_t *)cm_galist_get(withas_plan->withas_factors, i++); + if (!factor->is_mtrl) { + continue; + } + plan_node_t *ws_plan = ((sql_select_t *)factor->subquery_ctx)->plan->select_p.next; + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, ws_plan, depth, "LOAD AS SELECT", + NULL, &ws_plan->withas_p.name, NULL)); + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, ws_plan->withas_p.next, depth + 1)); + } + return CT_SUCCESS; +} + +static status_t expl_format_withas_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + sql_withas_t *withas_plan = (sql_withas_t *)stmt->context->withas_entry; + if (!expl_format_withas_has_mtrl(withas_plan)) { + return CT_SUCCESS; + } + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "TEMP TABLE TRANSFORMATION", + NULL, NULL, NULL)); + CT_RETURN_IFERR(expl_format_withas_plan_node(stmt, helper, withas_plan, depth + 1)); + return CT_SUCCESS; +} + status_t expl_format_select_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) { bool32 is_subselect = (sql_get_plan(stmt) != plan); char *oper = is_subselect ? "SUBSELECT" : "SELECT STATEMENT"; CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, NULL, NULL, NULL)); + if (!is_subselect) { + CT_RETURN_IFERR(expl_format_withas_plan(stmt, helper, plan, depth + 1)); + } return expl_format_plan_node(stmt, helper, plan->select_p.next, depth + 1); } @@ -468,38 +577,396 @@ status_t expl_format_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_nod status_t expl_format_union_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) { - // pass througth + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "HASH JOIN", NULL, NULL, NULL)); + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, plan->set_p.left, depth + 1)); + return expl_format_plan_node(stmt, helper, plan->set_p.right, depth + 1); +} + +static status_t expl_format_union_all_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + plan_node_t *sub_node = NULL; + char oper[CT_MAX_DFLT_VALUE_LEN] = {0}; + uint32 offset = 0; + int32 len = 0; + MEMS_RETURN_IFERR(memcpy_s(oper, CT_MAX_DFLT_VALUE_LEN, "UNION ALL", strlen("UNION ALL"))); + if (g_instance->sql.parallel_policy && plan->set_p.union_all_p.par_exec) { + offset = (uint32)strlen("UNION ALL"); + len = snprintf_s(oper + offset, CT_MAX_DFLT_VALUE_LEN - offset, CT_MAX_DFLT_VALUE_LEN - offset- 1, + "(p %3u)", stmt->context->parallel); + } + if (SECUREC_UNLIKELY(len == -1)) { + return CT_ERROR; + } + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, NULL, NULL, NULL)); + for (uint32 i = 0; i < plan->set_p.list->count; i++) { + sub_node = (plan_node_t *)cm_galist_get(plan->set_p.list, i); + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, sub_node, depth + 1)); + } + return CT_SUCCESS; +} + +static status_t expl_format_minus_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + char oper[CT_MAX_DFLT_VALUE_LEN] = {0}; + uint32 offset = 0; + char *name = g_minus_names[plan->set_p.minus_p.minus_type]; + if (plan->type == PLAN_NODE_HASH_MINUS) { + MEMS_RETURN_IFERR(memcpy_s(oper, CT_MAX_DFLT_VALUE_LEN, "HASH ", strlen("HASH "))); + offset = (uint32)strlen("HASH "); + } + MEMS_RETURN_IFERR(memcpy_s(oper + offset, CT_MAX_DFLT_VALUE_LEN - offset, name, strlen(name))); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, NULL, NULL, NULL)); + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, plan->set_p.left, depth + 1)); + return expl_format_plan_node(stmt, helper, plan->set_p.right, depth + 1); +} + +static status_t expl_format_aggr_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + char oper[CT_MAX_DFLT_VALUE_LEN] = {0}; + uint32 offset = 0; + expr_node_t *aggr_node = NULL; + if (plan->type == PLAN_NODE_INDEX_AGGR) { + MEMS_RETURN_IFERR(memcpy_s(oper, CT_MAX_DFLT_VALUE_LEN, "INDEX ", strlen("INDEX "))); + offset = (uint32)strlen("INDEX "); + } + MEMS_RETURN_IFERR(memcpy_s(oper + offset, CT_MAX_DFLT_VALUE_LEN - offset, "AGGR", strlen("AGGR"))); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, NULL, NULL, NULL)); + for (uint32 i = 0; i < plan->aggr.items->count; i++) { + aggr_node = (expr_node_t*)cm_galist_get(plan->aggr.items, i); + CT_RETURN_IFERR(expl_format_aggr_node_plan(stmt, helper, aggr_node, depth + 1)); + } + return expl_format_plan_node(stmt, helper, plan->aggr.next, depth + 1); +} + +static status_t expl_format_nl_full_opt_row(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + plan_node_t l_drive_plan = *plan; + l_drive_plan.join_p.oper = JOIN_OPER_NL_LEFT; + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "UNION ALL", NULL, NULL, NULL)); + CT_RETURN_IFERR(expl_format_join_plan(stmt, helper, &l_drive_plan, depth + 1)); + return expl_format_plan_node(stmt, helper, plan->join_p.r_drive_plan, depth + 1); +} + +static status_t expl_format_join_exists_subselect(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, + uint32 depth, cond_node_t **subselect_cond) +{ + bool32 has_subselect = CT_FALSE; + if (plan->join_p.filter != NULL) { + CT_RETURN_IFERR(expl_format_cond_node_plan(stmt, helper, plan->join_p.filter->root, + depth + 1, &has_subselect)); + if (has_subselect) { + *subselect_cond = plan->join_p.filter->root; + } + return CT_SUCCESS; + } + if (plan->join_p.cond != NULL) { + CT_RETURN_IFERR(expl_format_cond_node_plan(stmt, helper, plan->join_p.cond->root, + depth + 1, &has_subselect)); + if (has_subselect) { + *subselect_cond = plan->join_p.cond->root; + } + return CT_SUCCESS; + } return CT_SUCCESS; } -status_t expl_format_union_all_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +static status_t expl_format_join_fill_oper(plan_node_t *plan, char *oper) { - // pass througth + char *join_oper = NULL; + if (plan->join_p.oper != JOIN_OPER_NL_LEFT) { + join_oper = g_join_oper[plan->join_p.oper][plan->join_p.hash_left]; + } else { + join_oper = g_join_oper[plan->join_p.oper][plan->join_p.nl_full_r_drive]; + } + MEMS_RETURN_IFERR(memcpy_s(oper, CT_MAX_DFLT_VALUE_LEN, join_oper, strlen(join_oper))); + return CT_SUCCESS; +} + +static status_t expl_format_join_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + if (plan->join_p.oper == JOIN_OPER_NL_FULL && plan->join_p.nl_full_opt_type != NL_FULL_OPT_NONE) { + return expl_format_nl_full_opt_row(stmt, helper, plan, depth); + } + + cond_node_t *subselect_cond = NULL; + char oper[CT_MAX_DFLT_VALUE_LEN] = {0}; + CT_RETURN_IFERR(expl_format_join_exists_subselect(stmt, helper, plan, depth, &subselect_cond)); + if (subselect_cond != NULL) { + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth++, "KERNEL FILTER", NULL, NULL, NULL)); + } + CT_RETURN_IFERR(expl_format_join_fill_oper(plan, oper)); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, NULL, NULL, NULL)); + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, plan->join_p.left, depth + 1)); + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, plan->join_p.right, depth + 1)); + if (subselect_cond == NULL) { + return CT_SUCCESS; + } + return expl_format_cond_node_plan(stmt, helper, subselect_cond, depth, NULL); +} + +static status_t expl_format_insert_print_oper(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, + uint32 depth, bool32 insert_all) +{ + char oper[CT_MAX_DFLT_VALUE_LEN] = {0}; + sql_table_t *table = plan->insert_p.table; + if (insert_all) { + MEMS_RETURN_IFERR(memcpy_s(oper, CT_MAX_DFLT_VALUE_LEN, "MULTI TABLE INSERT", strlen("MULTI TABLE INSERT"))); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, NULL, NULL, NULL)); + return CT_SUCCESS; + } + uint32 offset = (uint32)strlen("LOAD TABLE CONVENTIONAL "); + MEMS_RETURN_IFERR(memcpy_s(oper, CT_MAX_DFLT_VALUE_LEN, "LOAD TABLE CONVENTIONAL ", offset)); + if (stmt->context->type != CTSQL_TYPE_REPLACE && knl_is_part_table(table->entry->dc.handle)) { + CT_RETURN_IFERR(sql_calc_part_print(stmt, oper + offset, CT_MAX_DFLT_VALUE_LEN - offset)); + } + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, + &table->user.value, &table->name.value, + &table->alias.value)); return CT_SUCCESS; } +static status_t expl_format_insert_expr_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, + uint32 depth, sql_insert_t *insert_ctx, bool32 insert_all) +{ + uint32 i = 0; + column_value_pair_t *pair = NULL; + expr_tree_t *expr = NULL; + sql_table_t *table = plan->insert_p.table; + if (insert_all) { + while (i < insert_ctx->pairs_count) { + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "INTO", + &table->user.value, &table->name.value, + &table->alias.value)); + i++; + } + return CT_SUCCESS; + } + while (i < insert_ctx->pairs_count) { + pair = (column_value_pair_t *)cm_galist_get(insert_ctx->pairs, i++); + if (pair->exprs == NULL) { + continue; + } + for(uint32 j = 0; j < pair->exprs->count; j++) { + expr = (expr_tree_t *)cm_galist_get(pair->exprs, j); + CT_RETURN_IFERR(expl_format_expr_tree_plan(stmt, helper, expr, depth)); + } + } + return CT_SUCCESS; +} + +static status_t expl_format_insert_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + sql_insert_t *insert_ctx = NULL; + sql_array_t *ssa = helper->ssa; + char *oper = NULL; + if (stmt->context->type != CTSQL_TYPE_REPLACE) { + insert_ctx = (sql_insert_t *)stmt->context->entry; + oper = "INSERT STATEMENT"; + } else { + insert_ctx = &((sql_replace_t *)stmt->context->entry)->insert_ctx; + oper = "REPLACE STATEMENT"; + } + helper->ssa = &insert_ctx->ssa; + bool32 insert_all = CT_BIT_TEST(insert_ctx->syntax_flag, INSERT_IS_ALL); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, NULL, NULL, NULL)); + if (sql_get_plan(stmt) == plan) { + CT_RETURN_IFERR(expl_format_withas_plan(stmt, helper, plan, depth + 1)); + } + CT_RETURN_IFERR(expl_format_insert_print_oper(stmt, helper, plan, depth + 1, insert_all)); + if (insert_ctx->select_ctx != NULL) { + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, insert_ctx->select_ctx->plan, + depth + EXPL_DEPTH_CALC_LEVEL)); + } + CT_RETURN_IFERR(expl_format_insert_expr_plan(stmt, helper, plan, depth + EXPL_DEPTH_CALC_LEVEL, + insert_ctx, insert_all)); + helper->ssa = ssa; + return CT_SUCCESS; +} + +static status_t expl_format_merge_insert_plan(sql_stmt_t *stmt, expl_helper_t *helper, uint32 depth) +{ + sql_merge_t *merge_ctx = (sql_merge_t *)stmt->context->entry; + if (merge_ctx->insert_ctx == NULL) { + return CT_SUCCESS; + } + if (merge_ctx->insert_filter_cond == NULL) { + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, merge_ctx->insert_ctx->plan, depth, "INSERT STATEMENT", + NULL, NULL, NULL)); + return CT_SUCCESS; + } + sql_array_t *ssa = helper->ssa; + helper->ssa = &merge_ctx->query->ssa; + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, NULL, depth, "FILTER", NULL, NULL, NULL)); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, merge_ctx->insert_ctx->plan, depth + 1, "INSERT STATEMENT", + NULL, NULL, NULL)); + CT_RETURN_IFERR(expl_format_cond_node_plan(stmt, helper, merge_ctx->insert_filter_cond->root, + depth + EXPL_DEPTH_CALC_LEVEL, NULL)); + helper->ssa = ssa; + return CT_SUCCESS; +} + +static status_t expl_format_merge_update_expr_plan(sql_stmt_t *stmt, expl_helper_t *helper, uint32 depth) +{ + sql_merge_t *merge_ctx = (sql_merge_t *)stmt->context->entry; + galist_t *update_pairs = merge_ctx->update_ctx->pairs; + expr_tree_t * expr = NULL; + column_value_pair_t *update_pair = NULL; + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, merge_ctx->update_ctx->plan, depth, "UPDATE STATEMENT", + NULL, NULL, NULL)); + for (uint32 i = 0; i < update_pairs->count; i++) { + update_pair = (column_value_pair_t *)cm_galist_get(update_pairs, i); + expr = (expr_tree_t *)cm_galist_get(update_pair->exprs, 0); + CT_RETURN_IFERR(expl_format_expr_tree_plan(stmt, helper, expr, depth + 1)); + } + return CT_SUCCESS; +} + +static status_t expl_format_merge_update_plan(sql_stmt_t *stmt, expl_helper_t *helper, uint32 depth) +{ + sql_merge_t *merge_ctx = (sql_merge_t *)stmt->context->entry; + if (merge_ctx->update_ctx == NULL) { + return CT_SUCCESS; + } + sql_array_t *ssa = helper->ssa; + helper->ssa = &merge_ctx->query->ssa; + if (merge_ctx->update_filter_cond == NULL) { + CT_RETURN_IFERR(expl_format_merge_update_expr_plan(stmt, helper, depth)); + return CT_SUCCESS; + } + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, NULL, depth, "FILTER", NULL, NULL, NULL)); + CT_RETURN_IFERR(expl_format_merge_update_expr_plan(stmt, helper, depth + 1)); + CT_RETURN_IFERR(expl_format_cond_node_plan(stmt, helper, merge_ctx->update_filter_cond->root, + depth + EXPL_DEPTH_CALC_LEVEL, NULL)); + helper->ssa = ssa; + return CT_SUCCESS; +} + +static status_t expl_format_merge_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + char oper[CT_MAX_DFLT_VALUE_LEN] = {0}; + uint32 offset = (uint32)strlen("MERGE STATEMENT"); + MEMS_RETURN_IFERR(memcpy_s(oper, CT_MAX_DFLT_VALUE_LEN, "MERGE STATEMENT", offset)); + if (plan->merge_p.merge_keys == NULL || plan->merge_p.merge_keys->count == 0) { + MEMS_RETURN_IFERR(memcpy_s(oper + offset, CT_MAX_DFLT_VALUE_LEN - offset, "(NESTED LOOPS)", + strlen("(NESTED LOOPS)"))); + } else { + MEMS_RETURN_IFERR(memcpy_s(oper + offset, CT_MAX_DFLT_VALUE_LEN - offset, "(HASH JOIN)", + strlen("(HASH JOIN)"))); + } + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, NULL, NULL, NULL)); + if (sql_get_plan(stmt) == plan) { + CT_RETURN_IFERR(expl_format_withas_plan(stmt, helper, plan, depth + 1)); + } + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan->merge_p.using_table_scan_p, depth + 1, + "USING TABLE", NULL, NULL, NULL)); + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, plan->merge_p.using_table_scan_p, + depth + EXPL_DEPTH_CALC_LEVEL)); + helper->query = NULL; + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan->merge_p.merge_into_scan_p, depth + 1, + "MERGE TABLE", NULL, NULL, NULL)); + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, plan->merge_p.merge_into_scan_p, + depth + EXPL_DEPTH_CALC_LEVEL)); + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, NULL, depth + 1, "ON CONDITION", NULL, NULL, NULL)); + + CT_RETURN_IFERR(expl_format_merge_insert_plan(stmt, helper, depth + EXPL_DEPTH_CALC_LEVEL)); + return expl_format_merge_update_plan(stmt, helper, depth +EXPL_DEPTH_CALC_LEVEL); +} + +static status_t expl_format_delete_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "DELETE STATEMENT", NULL, NULL, NULL)); + if (sql_get_plan(stmt) == plan) { + CT_RETURN_IFERR(expl_format_withas_plan(stmt, helper, plan, depth + 1)); + } + return expl_format_plan_node(stmt, helper, plan->delete_p.next, depth + 1); +} + +static status_t expl_format_sort_distinct_expr(sql_stmt_t *stmt, expl_helper_t *helper, galist_t *columns, uint32 depth) +{ + rs_column_t *col = NULL; + for (uint32 i = 0; i < columns->count; i++) { + col = (rs_column_t *)cm_galist_get(columns, i); + if (col->type == RS_COL_CALC) { + CT_RETURN_IFERR(expl_format_expr_tree_plan(stmt, helper, col->expr, depth)); + } + } + return CT_SUCCESS; +} + +static status_t expl_format_sort_plan_data(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth, + char *oper) +{ + galist_t *columns = plan->query_sort.select_columns; + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, NULL, NULL, NULL)); + CT_RETURN_IFERR(expl_format_sort_distinct_expr(stmt, helper, columns, depth + 1)); + return expl_format_plan_node(stmt, helper, plan->query_sort.next, depth + 1); +} + +static status_t expl_format_sort_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + char *oper = NULL; + if (plan->type == PLAN_NODE_QUERY_SORT_PAR) { + oper = "PAR QUERY SORT ORDER BY"; + } else if (plan->type == PLAN_NODE_QUERY_SIBL_SORT) { + oper = "QUERY SORT SIBLINGS ORDER BY"; + } else if (SORT_ORDER_BY_ROWNUM(plan)) { + oper = "QUERY SORT ORDER BY ROWNUM"; + } else { + oper = "QUERY SORT ORDER BY"; + } + return expl_format_sort_plan_data(stmt, helper, plan, depth, oper); +} + +static status_t expl_format_distinct_plan_data(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, + uint32 depth, char *oper) +{ + galist_t *columns = plan->distinct.columns; + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, NULL, NULL, NULL)); + CT_RETURN_IFERR(expl_format_sort_distinct_expr(stmt, helper, columns, depth + 1)); + return expl_format_plan_node(stmt, helper, plan->distinct.next, depth + 1); +} + +static status_t expl_format_distinct_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + char *oper = g_distinct_names[plan->type - PLAN_NODE_SORT_DISTINCT]; + return expl_format_distinct_plan_data(stmt, helper, plan, depth, oper); +} + +static status_t expl_format_next_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, + plan_node_t *next_plan, uint32 depth, char *oper) +{ + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, NULL, NULL, NULL)); + return expl_format_plan_node(stmt, helper, next_plan, depth + 1); +} + +static status_t expl_format_group_by_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + char *oper = g_group_by_names[plan->type - PLAN_NODE_SORT_GROUP]; + return expl_format_next_plan(stmt, helper, plan, plan->group.next, depth, oper); +} + static expl_plan_t g_expl_plan_funcs[] = {{PLAN_NODE_QUERY, expl_format_query_plan}, {PLAN_NODE_UNION, expl_format_union_plan}, {PLAN_NODE_UNION_ALL, expl_format_union_all_plan}, - {PLAN_NODE_MINUS, expl_format_default_plan_node}, - {PLAN_NODE_HASH_MINUS, expl_format_default_plan_node}, - {PLAN_NODE_MERGE, expl_format_default_plan_node}, - {PLAN_NODE_INSERT, expl_format_default_plan_node}, - {PLAN_NODE_DELETE, expl_format_default_plan_node}, + {PLAN_NODE_MINUS, expl_format_minus_plan}, + {PLAN_NODE_HASH_MINUS, expl_format_minus_plan}, + {PLAN_NODE_MERGE, expl_format_merge_plan}, + {PLAN_NODE_INSERT, expl_format_insert_plan}, + {PLAN_NODE_DELETE, expl_format_delete_plan}, {PLAN_NODE_UPDATE, expl_format_default_plan_node}, {PLAN_NODE_SELECT, expl_format_select_plan}, - {PLAN_NODE_JOIN, expl_format_default_plan_node}, - {PLAN_NODE_SORT_GROUP, expl_format_default_plan_node}, - {PLAN_NODE_MERGE_SORT_GROUP, expl_format_default_plan_node}, - {PLAN_NODE_HASH_GROUP, expl_format_default_plan_node}, - {PLAN_NODE_INDEX_GROUP, expl_format_default_plan_node}, - {PLAN_NODE_QUERY_SORT, expl_format_default_plan_node}, + {PLAN_NODE_JOIN, expl_format_join_plan}, + {PLAN_NODE_SORT_GROUP, expl_format_group_by_plan}, + {PLAN_NODE_MERGE_SORT_GROUP, expl_format_group_by_plan}, + {PLAN_NODE_HASH_GROUP, expl_format_group_by_plan}, + {PLAN_NODE_INDEX_GROUP, expl_format_group_by_plan}, + {PLAN_NODE_QUERY_SORT, expl_format_sort_plan}, {PLAN_NODE_SELECT_SORT, expl_format_default_plan_node}, - {PLAN_NODE_AGGR, expl_format_default_plan_node}, - {PLAN_NODE_INDEX_AGGR, expl_format_default_plan_node}, - {PLAN_NODE_SORT_DISTINCT, expl_format_default_plan_node}, - {PLAN_NODE_HASH_DISTINCT, expl_format_default_plan_node}, - {PLAN_NODE_INDEX_DISTINCT, expl_format_default_plan_node}, + {PLAN_NODE_AGGR, expl_format_aggr_plan}, + {PLAN_NODE_INDEX_AGGR, expl_format_aggr_plan}, + {PLAN_NODE_SORT_DISTINCT, expl_format_distinct_plan}, + {PLAN_NODE_HASH_DISTINCT, expl_format_distinct_plan}, + {PLAN_NODE_INDEX_DISTINCT, expl_format_distinct_plan}, {PLAN_NODE_HAVING, expl_format_default_plan_node}, {PLAN_NODE_SCAN, expl_format_scan_plan}, {PLAN_NODE_QUERY_LIMIT, expl_format_default_plan_node}, @@ -512,8 +979,8 @@ static expl_plan_t g_expl_plan_funcs[] = {{PLAN_NODE_QUERY, expl_format_query_pl {PLAN_NODE_HASH_GROUP_PAR, expl_format_default_plan_node}, {PLAN_NODE_HASH_MTRL, expl_format_default_plan_node}, {PLAN_NODE_CONCATE, expl_format_default_plan_node}, - {PLAN_NODE_QUERY_SORT_PAR, expl_format_default_plan_node}, - {PLAN_NODE_QUERY_SIBL_SORT, expl_format_default_plan_node}, + {PLAN_NODE_QUERY_SORT_PAR, expl_format_sort_plan}, + {PLAN_NODE_QUERY_SIBL_SORT, expl_format_sort_plan}, {PLAN_NODE_GROUP_CUBE, expl_format_default_plan_node}, {PLAN_NODE_HASH_GROUP_PIVOT, expl_format_default_plan_node}, {PLAN_NODE_UNPIVOT, expl_format_default_plan_node}, diff --git a/pkg/src/ctsql/executor/explain/expl_plan.h b/pkg/src/ctsql/executor/explain/expl_plan.h index 7d12de64..e6afe2ba 100644 --- a/pkg/src/ctsql/executor/explain/expl_plan.h +++ b/pkg/src/ctsql/executor/explain/expl_plan.h @@ -32,6 +32,7 @@ #include "cm_list.h" #include "ctsql_plan_defs.h" #include "ctsql_stmt.h" +#include "ctsql_insert.h" #include "srv_instance.h" typedef enum { -- Gitee From adaf78f5e23079d7d85253f8495a34443266d636 Mon Sep 17 00:00:00 2001 From: pengbingjie Date: Tue, 8 Apr 2025 06:56:16 +0000 Subject: [PATCH 11/12] =?UTF-8?q?!9=20feat(explain)=EF=BC=9A=E8=A1=A5?= =?UTF-8?q?=E5=85=85explain=E7=AE=97=E5=AD=90=20*=20complete=20explain=20o?= =?UTF-8?q?per?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/src/ctsql/executor/explain/expl_plan.c | 343 +++++++++++++++++++-- pkg/src/ctsql/executor/explain/expl_plan.h | 3 +- 2 files changed, 323 insertions(+), 23 deletions(-) diff --git a/pkg/src/ctsql/executor/explain/expl_plan.c b/pkg/src/ctsql/executor/explain/expl_plan.c index 93a73fcd..cea4abfa 100644 --- a/pkg/src/ctsql/executor/explain/expl_plan.c +++ b/pkg/src/ctsql/executor/explain/expl_plan.c @@ -32,6 +32,31 @@ #define SORT_ORDER_BY_ROWNUM(plan) (g_instance->sql.topn_threshold !=0 \ && (plan)->query_sort.rownum_upper <= g_instance->sql.topn_threshold) +typedef enum { + INDEX_MODE_MULTI_PARTS_SCAN = 0, + INDEX_MODE_FAST_FULL_SCAN, + INDEX_MODE_FULL_SCAN, + INDEX_MODE_OPTIMIZED_RANGE_SCAN, + INDEX_MODE_UNIQUE_SCAN, + INDEX_MODE_SKIP_SCAN, + INDEX_MODE_RANGE_SCAN +} index_mode_type_t; + +typedef struct { + bool32 idx_cond; + index_mode_type_t idx_mode; +} index_mode_t; + +static char* g_index_mode_oper[] = { + "INDEX MULTI PARTS SCAN", + "INDEX FAST FULL SCAN", + "INDEX FULL SCAN", + "OPTIMIZED INDEX RANGE SCAN", + "INDEX UNIQUE SCAN", + "INDEX SKIP SCAN", + "INDEX RANGE SCAN" +}; + static char* g_minus_names[] = { "MINUS", "INTERSECT", @@ -433,6 +458,90 @@ status_t expl_format_user_rowid_scan_plan(sql_stmt_t *stmt, expl_helper_t *helpe return CT_SUCCESS; } +static bool32 expl_format_has_optimize(scan_list_array_t *arr) +{ + if (!can_use_point_scan(arr)) { + return CT_FALSE; + } + uint32 i = 0; + while (i < arr->count) { + if (arr->items[i].count > 1) { + return CT_TRUE; + } + if (arr->items[i].type == RANGE_LIST_FULL) { + return CT_FALSE; + } + i++; + } + return CT_FALSE; +} + +static inline index_mode_type_t expl_format_get_index_mode(sql_table_t *table, scan_list_array_t *arr) +{ + knl_index_desc_t *index = table->index; + index_mode_type_t index_mode = INDEX_MODE_RANGE_SCAN; + const index_mode_t g_index_mode[] = { + { table->multi_parts_scan, INDEX_MODE_MULTI_PARTS_SCAN }, + { table->index_ffs, INDEX_MODE_FAST_FULL_SCAN }, + { table->index_full_scan, INDEX_MODE_FULL_SCAN }, + { expl_format_has_optimize(arr), INDEX_MODE_OPTIMIZED_RANGE_SCAN }, + { table->idx_equal_to == index->column_count && (index->primary || index->unique), INDEX_MODE_UNIQUE_SCAN }, + { table->index_skip_scan, INDEX_MODE_SKIP_SCAN } + }; + for (uint32 i = 0; i < sizeof(g_index_mode) / sizeof(g_index_mode[0]); i++) { + if (g_index_mode[i].idx_cond) { + index_mode = g_index_mode[i].idx_mode; + break; + } + } + return index_mode; +} + +static status_t expl_format_index_scan_mode(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + char oper[CT_MAX_DFLT_VALUE_LEN] = { 0 }; + sql_table_t *scan_tbl = plan->scan_p.table; + sql_array_t *index_arr = &plan->scan_p.index_array; + scan_list_array_t arr = { 0 }; + arr.count = scan_tbl->index->column_count; + CT_RETURN_IFERR(sql_finalize_scan_range(stmt, index_arr, &arr, scan_tbl, NULL, NULL, CALC_IN_PLAN)); + + index_mode_type_t idx_mode = expl_format_get_index_mode(scan_tbl, &arr); + char *idx_oper = g_index_mode_oper[idx_mode]; + MEMS_RETURN_IFERR(memcpy_s(oper, CT_MAX_DFLT_VALUE_LEN, idx_oper, strlen(idx_oper))); + uint32 offset = (uint32)strlen(idx_oper); + text_t idx_name = { .str = scan_tbl->index->name, .len = (uint32)strlen(scan_tbl->index->name) }; + if (scan_tbl->index_dsc) { + MEMS_RETURN_IFERR(memcpy_s(oper + offset, CT_MAX_DFLT_VALUE_LEN - offset, " DESCENDING", + strlen(" DESCENDING"))); + } + return expl_format_plan_node_row(stmt, helper, plan, depth, oper, &scan_tbl->user.value, &idx_name, NULL); +} + +static status_t expl_format_user_index_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, + uint32 depth) +{ + char oper[CT_MAX_DFLT_VALUE_LEN] = { 0 }; + int len = 0; + sql_table_t *scan_tbl = plan->scan_p.table; + if (!INDEX_ONLY_SCAN(scan_tbl->scan_flag)) { + len = snprintf_s(oper, CT_MAX_DFLT_VALUE_LEN, CT_MAX_DFLT_VALUE_LEN -1, "TABLE ACCESS BY INDEX ROWID "); + } else { + len = snprintf_s(oper, CT_MAX_DFLT_VALUE_LEN, CT_MAX_DFLT_VALUE_LEN -1, "TABLE ACCESS BY INDEX ONLY "); + } + if (SECUREC_UNLIKELY(len == -1)) { + return CT_ERROR; + } + uint32 offset = (uint32)len; + if (knl_is_part_table(scan_tbl->entry->dc.handle)) { + sql_part_get_print(stmt, &plan->scan_p, oper + offset, CT_MAX_DFLT_VALUE_LEN - offset); + } + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, oper, &scan_tbl->user.value, + &scan_tbl->name.value, &scan_tbl->alias.value)); + CT_RETURN_IFERR(expl_format_index_scan_mode(stmt, helper, plan, depth + 1)); + return CT_SUCCESS; +} + status_t expl_format_normal_table_scan_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) { text_t owner = {0}; @@ -522,8 +631,7 @@ status_t expl_format_scan_plan_deep(sql_stmt_t *stmt, expl_helper_t *helper, pla if (plan->scan_p.rowid_set != NULL && plan->scan_p.rowid_set->type == RANGE_LIST_NORMAL) { return expl_format_user_rowid_scan_plan(stmt, helper, plan, depth); } else if (plan->scan_p.table->index != NULL) { - // todo: index scan - return CT_SUCCESS; + return expl_format_user_index_scan_plan(stmt, helper, plan, depth); } sql_table_type_t type = table->type; @@ -881,6 +989,63 @@ static status_t expl_format_delete_plan(sql_stmt_t *stmt, expl_helper_t *helper, return expl_format_plan_node(stmt, helper, plan->delete_p.next, depth + 1); } +static bool32 expl_format_update_expr_exists(expr_tree_t **expr_arr, expr_tree_t *expr, uint32 count) +{ + for (uint32 i = 0; i < count; i++) { + if (expr_arr[i] == expr) { + return CT_TRUE; + } + } + return CT_FALSE; +} + +static status_t expl_format_update_expr_plan(sql_stmt_t *stmt, expl_helper_t *helper, update_plan_t *upd_plan, + uint32 depth) +{ + sql_update_t *update_ctx = (sql_update_t *)stmt->context->entry; + sql_array_t *ssa = helper->ssa; + expr_tree_t **expr_arr; + upd_object_t *object = NULL; + column_value_pair_t *pair = NULL; + expr_tree_t *expr = NULL; + for (uint32 i = 0; i < upd_plan->objects->count; i++) { + object = (upd_object_t *)cm_galist_get(upd_plan->objects, i); + if (object->pairs->count == 0) { + continue; + } + CT_RETURN_IFERR(sql_push(stmt, object->pairs->count * sizeof(pointer_t), (void **)&expr_arr)); + uint32 expr_count = 0; + for (uint32 j = 0; j < object->pairs->count; j++) { + pair = (column_value_pair_t *)cm_galist_get(object->pairs, j); + expr = (expr_tree_t *)cm_galist_get(pair->exprs, 0); + if (expr_count == 0 || !expl_format_update_expr_exists(expr_arr, expr, expr_count)) { + expr_arr[expr_count] = expr; + expr_count++; + } else { + continue; + } + helper->ssa = &update_ctx->query->ssa; + if (expl_format_expr_tree_plan(stmt, helper, expr, depth) != CT_SUCCESS) { + CTSQL_POP(stmt); + return CT_ERROR; + } + } + CTSQL_POP(stmt); + } + helper->ssa = ssa; + return CT_SUCCESS; +} + +static status_t expl_format_update_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "UPDATE STATEMENT", NULL, NULL, NULL)); + if (sql_get_plan(stmt) == plan) { + CT_RETURN_IFERR(expl_format_withas_plan(stmt, helper, plan, depth + 1)); + } + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, plan->update_p.next, depth + 1)); + return expl_format_update_expr_plan(stmt, helper, &plan->update_p, depth + 1); +} + static status_t expl_format_sort_distinct_expr(sql_stmt_t *stmt, expl_helper_t *helper, galist_t *columns, uint32 depth) { rs_column_t *col = NULL; @@ -945,6 +1110,140 @@ static status_t expl_format_group_by_plan(sql_stmt_t *stmt, expl_helper_t *helpe return expl_format_next_plan(stmt, helper, plan, plan->group.next, depth, oper); } +static status_t expl_format_select_sort_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return expl_format_next_plan(stmt, helper, plan, plan->select_sort.next, depth, "SELECT SORT ORDER BY"); +} + +static status_t expl_format_having_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + CT_RETURN_IFERR(expl_format_next_plan(stmt, helper, plan, plan->having.next, depth, "HAVING")); + if (plan->having.cond == NULL) { + return CT_SUCCESS; + } + return expl_format_cond_node_plan(stmt, helper, plan->having.cond->root, depth, NULL); +} + +static status_t expl_format_query_limit_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return expl_format_next_plan(stmt, helper, plan, plan->limit.next, depth, "QUERY LIMIT"); +} + +static status_t expl_format_select_limit_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return expl_format_next_plan(stmt, helper, plan, plan->limit.next, depth, "SELECT LIMIT"); +} + +static status_t expl_format_connect_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + connect_plan_t *cb_plan = &plan->connect; + bool32 is_next_cb_type_mtrl = (cb_plan->next_connect_by->type == PLAN_NODE_CONNECT_MTRL); + + // start with condition + cond_tree_t *sw_cond = (cb_plan->s_query != NULL) ? cb_plan->s_query->cond : + (is_next_cb_type_mtrl ? NULL : cb_plan->start_with_cond); + if (cb_plan->s_query || (!is_next_cb_type_mtrl && cb_plan->start_with_cond)) { + CT_RETURN_IFERR(expl_format_next_plan(stmt, helper, plan, cb_plan->next_start_with, depth, "START WITH")); + if (sw_cond) { + CT_RETURN_IFERR(expl_format_cond_node_plan(stmt, helper, sw_cond->root, depth, NULL)); + } + } + + // connect by condition + if (is_next_cb_type_mtrl) { + return expl_format_plan_node(stmt, helper, cb_plan->next_connect_by, depth); + } + if (cb_plan->connect_by_cond == NULL) { + return CT_SUCCESS; + } + CT_RETURN_IFERR(expl_format_next_plan(stmt, helper, plan, cb_plan->next_connect_by, depth, "CONNECT BY")); + return expl_format_cond_node_plan(stmt, helper, cb_plan->connect_by_cond->root, depth, NULL); +} + +static status_t expl_format_filter_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + CT_RETURN_IFERR(expl_format_next_plan(stmt, helper, plan, plan->filter.next, depth, "FILTER")); + if (plan->filter.cond == NULL) { + return CT_SUCCESS; + } + return expl_format_cond_node_plan(stmt, helper, plan->filter.cond->root, depth, NULL); +} + +static status_t expl_format_window_sort_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return expl_format_next_plan(stmt, helper, plan, plan->winsort_p.next, depth, "WINDOW SORT"); +} + +static status_t expl_format_group_merge_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return expl_format_next_plan(stmt, helper, plan, plan->group.next, depth, "MERGE GROUP BY"); +} + +static status_t expl_format_parallel_group_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, + uint32 depth) +{ + group_plan_t group = plan->group; + if (group.multi_prod) { + return expl_format_next_plan(stmt, helper, plan, group.next, depth, "PARALLEL HASH GROUP BY (M-M)"); + } + return expl_format_next_plan(stmt, helper, plan, group.next, depth, "PARALLEL HASH GROUP BY (S-S)"); +} + +static status_t expl_format_hash_mtrl_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return expl_format_next_plan(stmt, helper, plan, plan->hash_mtrl.group.next, depth, "HASH MATERIALIZE"); +} + +static status_t expl_format_concate_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + uint32 i = 0; + plan_node_t *sub_plan = NULL; + CT_RETURN_IFERR(expl_format_plan_node_row(stmt, helper, plan, depth, "CONCATENATION", NULL, NULL, NULL)); + while (i < plan->cnct_p.plans->count) { + sub_plan = (plan_node_t *)cm_galist_get(plan->cnct_p.plans, i++); + CT_RETURN_IFERR(expl_format_plan_node(stmt, helper, sub_plan, depth + 1)); + } + return CT_SUCCESS; +} + +static status_t expl_format_cube_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return expl_format_next_plan(stmt, helper, plan, plan->cube.next, depth, "GENERATE CUBE"); +} + +static status_t expl_format_pivot_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return expl_format_next_plan(stmt, helper, plan, plan->group.next, depth, "HASH GROUP PIVOT"); +} + +static status_t expl_format_unpivot_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return expl_format_next_plan(stmt, helper, plan, plan->unpivot_p.next, depth, "UNPIVOT"); +} + +static status_t expl_format_rownum_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + if (helper->query->incl_flags & COND_INCL_ROWNUM) { + return expl_format_next_plan(stmt, helper, plan, plan->rownum_p.next, depth, "ROWNUM FILTER"); + } + return expl_format_next_plan(stmt, helper, plan, plan->rownum_p.next, depth, "ROWNUM COUNT"); +} + +static status_t expl_format_for_update_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return expl_format_next_plan(stmt, helper, plan, plan->for_update.next, depth, "FOR UPDATE"); +} + +static status_t expl_format_connect_mtrl_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return expl_format_next_plan(stmt, helper, plan, plan->cb_mtrl.next, depth, "CONNECT BY MATERIALIZE"); +} + +static status_t expl_format_vm_view_mtrl_plan(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) +{ + return expl_format_next_plan(stmt, helper, plan, plan->vm_view_p.next, depth, "VM VIEW"); +} + static expl_plan_t g_expl_plan_funcs[] = {{PLAN_NODE_QUERY, expl_format_query_plan}, {PLAN_NODE_UNION, expl_format_union_plan}, {PLAN_NODE_UNION_ALL, expl_format_union_all_plan}, @@ -953,7 +1252,7 @@ static expl_plan_t g_expl_plan_funcs[] = {{PLAN_NODE_QUERY, expl_format_query_pl {PLAN_NODE_MERGE, expl_format_merge_plan}, {PLAN_NODE_INSERT, expl_format_insert_plan}, {PLAN_NODE_DELETE, expl_format_delete_plan}, - {PLAN_NODE_UPDATE, expl_format_default_plan_node}, + {PLAN_NODE_UPDATE, expl_format_update_plan}, {PLAN_NODE_SELECT, expl_format_select_plan}, {PLAN_NODE_JOIN, expl_format_join_plan}, {PLAN_NODE_SORT_GROUP, expl_format_group_by_plan}, @@ -961,35 +1260,35 @@ static expl_plan_t g_expl_plan_funcs[] = {{PLAN_NODE_QUERY, expl_format_query_pl {PLAN_NODE_HASH_GROUP, expl_format_group_by_plan}, {PLAN_NODE_INDEX_GROUP, expl_format_group_by_plan}, {PLAN_NODE_QUERY_SORT, expl_format_sort_plan}, - {PLAN_NODE_SELECT_SORT, expl_format_default_plan_node}, + {PLAN_NODE_SELECT_SORT, expl_format_select_sort_plan}, {PLAN_NODE_AGGR, expl_format_aggr_plan}, {PLAN_NODE_INDEX_AGGR, expl_format_aggr_plan}, {PLAN_NODE_SORT_DISTINCT, expl_format_distinct_plan}, {PLAN_NODE_HASH_DISTINCT, expl_format_distinct_plan}, {PLAN_NODE_INDEX_DISTINCT, expl_format_distinct_plan}, - {PLAN_NODE_HAVING, expl_format_default_plan_node}, + {PLAN_NODE_HAVING, expl_format_having_plan}, {PLAN_NODE_SCAN, expl_format_scan_plan}, - {PLAN_NODE_QUERY_LIMIT, expl_format_default_plan_node}, - {PLAN_NODE_SELECT_LIMIT, expl_format_default_plan_node}, - {PLAN_NODE_CONNECT, expl_format_default_plan_node}, - {PLAN_NODE_FILTER, expl_format_default_plan_node}, - {PLAN_NODE_WINDOW_SORT, expl_format_default_plan_node}, + {PLAN_NODE_QUERY_LIMIT, expl_format_query_limit_plan}, + {PLAN_NODE_SELECT_LIMIT, expl_format_select_limit_plan}, + {PLAN_NODE_CONNECT, expl_format_connect_plan}, + {PLAN_NODE_FILTER, expl_format_filter_plan}, + {PLAN_NODE_WINDOW_SORT, expl_format_window_sort_plan}, {PLAN_NODE_REMOTE_SCAN, expl_format_default_plan_node}, - {PLAN_NODE_GROUP_MERGE, expl_format_default_plan_node}, - {PLAN_NODE_HASH_GROUP_PAR, expl_format_default_plan_node}, - {PLAN_NODE_HASH_MTRL, expl_format_default_plan_node}, - {PLAN_NODE_CONCATE, expl_format_default_plan_node}, + {PLAN_NODE_GROUP_MERGE, expl_format_group_merge_plan}, + {PLAN_NODE_HASH_GROUP_PAR, expl_format_parallel_group_plan}, + {PLAN_NODE_HASH_MTRL, expl_format_hash_mtrl_plan}, + {PLAN_NODE_CONCATE, expl_format_concate_plan}, {PLAN_NODE_QUERY_SORT_PAR, expl_format_sort_plan}, {PLAN_NODE_QUERY_SIBL_SORT, expl_format_sort_plan}, - {PLAN_NODE_GROUP_CUBE, expl_format_default_plan_node}, - {PLAN_NODE_HASH_GROUP_PIVOT, expl_format_default_plan_node}, - {PLAN_NODE_UNPIVOT, expl_format_default_plan_node}, - {PLAN_NODE_ROWNUM, expl_format_default_plan_node}, - {PLAN_NODE_FOR_UPDATE, expl_format_default_plan_node}, + {PLAN_NODE_GROUP_CUBE, expl_format_cube_plan}, + {PLAN_NODE_HASH_GROUP_PIVOT, expl_format_pivot_plan}, + {PLAN_NODE_UNPIVOT, expl_format_unpivot_plan}, + {PLAN_NODE_ROWNUM, expl_format_rownum_plan}, + {PLAN_NODE_FOR_UPDATE, expl_format_for_update_plan}, {PLAN_NODE_WITHAS_MTRL, expl_format_default_plan_node}, - {PLAN_NODE_CONNECT_MTRL, expl_format_default_plan_node}, - {PLAN_NODE_CONNECT_HASH, expl_format_default_plan_node}, - {PLAN_NODE_VM_VIEW_MTRL, expl_format_default_plan_node}}; + {PLAN_NODE_CONNECT_MTRL, expl_format_connect_mtrl_plan}, + {PLAN_NODE_CONNECT_HASH, expl_format_connect_plan}, + {PLAN_NODE_VM_VIEW_MTRL, expl_format_vm_view_mtrl_plan}}; status_t expl_format_plan_node(sql_stmt_t *stmt, expl_helper_t *helper, plan_node_t *plan, uint32 depth) { diff --git a/pkg/src/ctsql/executor/explain/expl_plan.h b/pkg/src/ctsql/executor/explain/expl_plan.h index e6afe2ba..c33c1a86 100644 --- a/pkg/src/ctsql/executor/explain/expl_plan.h +++ b/pkg/src/ctsql/executor/explain/expl_plan.h @@ -30,9 +30,10 @@ #include "cm_row.h" #include "cm_defs.h" #include "cm_list.h" -#include "ctsql_plan_defs.h" +#include "plan_rbo.h" #include "ctsql_stmt.h" #include "ctsql_insert.h" +#include "ctsql_scan.h" #include "srv_instance.h" typedef enum { -- Gitee From d6e5fcb92769e7900aaa80247a7628cedd2a8794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=86=8A=E5=B0=8F=E5=86=9B?= Date: Wed, 9 Apr 2025 21:44:35 +0800 Subject: [PATCH 12/12] join commit 2 --- pkg/src/ctsql/ctsql_context.h | 60 -------------- pkg/src/ctsql/plan/plan_join.c | 111 ++++++++++++++++++-------- pkg/src/ctsql/plan/plan_join.h | 59 ++++++++++++++ pkg/src/ctsql/plan/plan_join_bitmap.c | 56 +++++++------ pkg/src/ctsql/plan/plan_join_bitmap.h | 11 +-- pkg/src/ctsql/plan/plan_query.c | 2 +- 6 files changed, 173 insertions(+), 126 deletions(-) diff --git a/pkg/src/ctsql/ctsql_context.h b/pkg/src/ctsql/ctsql_context.h index 2e88cdd3..a52d3db9 100644 --- a/pkg/src/ctsql/ctsql_context.h +++ b/pkg/src/ctsql/ctsql_context.h @@ -1153,66 +1153,6 @@ typedef struct st_cbo_filter_info { bool32 is_ready; } cbo_filter_info_t; -typedef struct st_join_path{ - sql_join_node_t *join_node; - double cost; - double rows; - uint32 relids; - sql_join_type_t join_type; - join_oper_t join_method; - cond_tree_t *join_cond; - cond_tree_t *filter; - struct st_join_path *outer; - struct st_join_path *inner; - bool32 is_required; -} join_path_t; - -typedef struct st_tbl_join_info { - sql_join_type_t join_type; - join_tbl_bitmap_t table_ids; // bitmap of table ids -} tbl_join_info_t; - -typedef struct st_tbl_join_info_node { - bilist_node_t bilist_node; - tbl_join_info_t join_info; -} tbl_join_info_node_t; - -typedef struct st_special_join_info { - join_tbl_bitmap_t min_lefthand; /* base relids in minimum LHS for join */ - join_tbl_bitmap_t min_righthand; /* base relids in minimum RHS for join */ - join_tbl_bitmap_t syn_lefthand; /* base relids syntactically within LHS */ - join_tbl_bitmap_t syn_righthand; /* base relids syntactically within RHS */ - sql_join_type_t jointype; /* always INNER, LEFT, FULL, SEMI, or ANTI */ - bool lhs_strict; /* joinclause is strict for some LHS rel */ - bool delay_upper_joins; /* can't commute with upper RHS */ - bool varratio_cached; /* decide chach selec or not. */ - bool is_straight_join; /* set true if is straight_join*/ -} special_join_info_t; - -typedef struct st_sql_join_table_node { - bilist_node_t bilist_node; - sql_join_table_t *join_table; -} sql_join_table_node_t; - -typedef enum join_table_type_t { - BASE_TABLE, - JOIN_TABLE -} join_table_type_t; - -typedef struct st_join_path { - int cost; -}join_path_t; - -typedef struct st_sql_join_table { - join_table_type_t table_type; - double rows; - int encode_width; - bilist_t join_path; - join_path_t *cheapest_startup_path; - join_path_t *cheapest_total_path; - join_tbl_bitmap_t table_ids; // bitmap of table_ids - bilist_t join_info; -}sql_join_table_t; // /////////////////////////////////////////////////////////////////////////////////// typedef struct st_sql_table { diff --git a/pkg/src/ctsql/plan/plan_join.c b/pkg/src/ctsql/plan/plan_join.c index dd1da882..83ab4d4c 100644 --- a/pkg/src/ctsql/plan/plan_join.c +++ b/pkg/src/ctsql/plan/plan_join.c @@ -788,19 +788,19 @@ static status_t sql_create_join_tree(sql_stmt_t *stmt, plan_assist_t *pa, join_a return CT_SUCCESS; } -static bool find_join_rel(sql_stmt_t *stmt, join_tbl_bitmap_t *join_tables_ids, sql_table_t *join_tbl) +static bool find_join_rel(sql_stmt_t *stmt, join_tbl_bitmap_t *join_tables_ids, sql_join_table_t *join_tbl) { //todo: find join rel in hash table return CT_FALSE; } -static status_t build_join_tbl(sql_stmt_t *stmt, plan_assist_t *pa, join_tbl_bitmap_t *join_tables_ids, sql_join_table_t *table1, sql_join_table_t *table2, special_join_info_t sjoininfo, sql_join_table_t *join_tbl) +static status_t build_join_tbl(sql_stmt_t *stmt, plan_assist_t *pa, join_tbl_bitmap_t *join_tables_ids, sql_join_table_t *table1, sql_join_table_t *table2, special_join_info_t *sjoininfo, sql_join_table_t *join_tbl) { if (find_join_rel(stmt, join_tables_ids, join_tbl) == CT_TRUE) { return CT_SUCCESS; } join_tbl->table_type = JOIN_TABLE; - sql_bitmap_copy(join_tables_ids, &join_tbl->table_ids); + sql_bitmap_copy(join_tables_ids, &join_tbl->table_ids); join_tbl->rows = 0; cm_bilist_init(&join_tbl->join_path); join_tbl->cheapest_startup_path = NULL; @@ -820,7 +820,7 @@ static status_t build_join_tbl(sql_stmt_t *stmt, plan_assist_t *pa, join_tbl_bit sql_join_table_node_t *table_node = NULL; //sql_join_table_t is brief of sql_table_t CT_RETURN_IFERR(sql_stack_alloc(stmt, sizeof(sql_join_table_node_t), (void **)&table_node)); table_node->join_table = join_tbl; - cm_bilist_add_tail(&table_node->bilist_node, pa->join_tbl_level[pa->join_cur_level]); + cm_bilist_add_tail(&table_node->bilist_node, &pa->join_tbl_level[pa->join_cur_level]); } return CT_SUCCESS; @@ -829,25 +829,50 @@ static status_t build_join_tbl(sql_stmt_t *stmt, plan_assist_t *pa, join_tbl_bit static status_t sql_make_join_relation(sql_stmt_t *stmt, plan_assist_t *pa, join_assist_t *join_ass, sql_join_node_t **join_root, sql_join_table_t *table1, sql_join_table_t *table2) { + special_join_info_t* sjoininfo = NULL; + join_tbl_bitmap_t join_tables_ids; + sql_bitmap_init(&join_tables_ids); sql_bitmap_union(&table1->table_ids, &table2->table_ids, &join_tables_ids); - //todo: check validity of table1、table2, and determine join type. - - //generate join info - special_join_info_t sjoininfo; - sjoininfo.min_lefthand = table1->table_ids; - sjoininfo.min_righthand = table2->table_ids; - sjoininfo.syn_lefthand = table1->table_ids; - sjoininfo.syn_righthand = table2->table_ids; - sjoininfo.jointype = JOIN_TYPE_INNER; //todo - + //todo: check validity of table1、table2, and determine join type、set sjoininfo. --wangfeihuo + //if (sql_join_is_legal() == CT_FALSE) { + // return CT_FALSE; + //} + + //generate join info, maybe it is useless. + /* if (sjoininfo == NULL) { + sjoininfo->min_lefthand = table1->table_ids; + sjoininfo->min_righthand = table2->table_ids; + sjoininfo->syn_lefthand = table1->table_ids; + sjoininfo->syn_righthand = table2->table_ids; + sjoininfo->jointype = JOIN_TYPE_INNER; //set join type by pa->join_assist->join_node->type + } */ sql_join_table_t *join_tbl = NULL; - CT_RETURN_IFERR(sql_alloc_mem(stmt->context, sizeof(sql_join_table_t), (void **)&join_tbl)); - CT_RETURN_IFERR(build_join_tbl(stmt, pa, &join_tables_ids, table1, table2, sjoininfo, &join_tbl)); - + CT_RETURN_IFERR(sql_stack_alloc(stmt->context, sizeof(sql_join_table_t), (void **)&join_tbl)); + CT_RETURN_IFERR(build_join_tbl(stmt, pa, &join_tables_ids, table1, table2, sjoininfo, join_tbl)); - + //todo: generate join path by JOIN TYPE, and add join path to join_tbl + /* + switch (sjoininfo->jointype) { + case JOIN_TYPE_INNER: + // todo: add_paths_to_joinrel(stmt, pa, table1, table2, sjoininfo, join_tbl); + // todo: add_paths_to_joinrel(stmt, pa, table2, table1, sjoininfo, join_tbl); + break; + case JOIN_TYPE_COMMA: + break; + case JOIN_TYPE_CROSS: + break; + + case JOIN_TYPE_LEFT: + break; + case JOIN_TYPE_RIGHT: + break; + case JOIN_TYPE_FULL: + break; + } + */ + return CT_SUCCESS; } static bool sql_have_relevant_join_relation(sql_join_table_t *table1, sql_join_table_t *table2) @@ -876,17 +901,21 @@ static status_t sql_make_rels_by_clause_joins(sql_stmt_t *stmt, plan_assist_t *p sql_join_node_t **join_root, sql_join_table_node_t *old_table_node, bilist_node_t *other_tables) { bilist_node_t *other_node = other_tables; - while (other_node) { + for (; other_node != NULL; other_node = BINODE_NEXT(other_node)) { sql_join_table_node_t *other_table_node = BILIST_NODE_OF(sql_join_table_node_t, other_node, bilist_node); sql_join_table_t *other_table = other_table_node->join_table; - + + // when a table_ids overlap another table_ids, then skip it if (sql_bitmap_overlap(&old_table_node->join_table->table_ids, &other_table->table_ids) == CT_TRUE) { continue; - } + } + + // when the join_table has no join relation with another one, then skip it if (sql_have_relevant_join_relation(old_table_node->join_table, other_table) == CT_FALSE) { continue; } - sql_make_join_relation(stmt, pa, join_ass, join_root, old_table_node->join_table, other_table); + + CT_RETURN_IFERR(sql_make_join_relation(stmt, pa, join_ass, join_root, old_table_node->join_table, other_table)); } return CT_SUCCESS; } @@ -901,19 +930,33 @@ static status_t sql_search_one_level(sql_stmt_t *stmt, plan_assist_t *pa, join_a sql_join_table_node_t *old_table = BILIST_NODE_OF(sql_join_table_node_t, pre_level_node, bilist_node); bilist_node_t * other_tables = NULL; - if (level == 1) { - other_tables = pre_level_node->next; - } else { - other_tables = cm_bilist_head(pa->join_tbl_level[0]); + if (level == 1) { /* when level == 1, consider remaining initial rels */ + other_tables = pre_level_node->next; + } else { /* when level >= 2, consider all initial rels */ + other_tables = cm_bilist_head(&pa->join_tbl_level[0]); } CT_RETURN_IFERR(sql_make_rels_by_clause_joins(stmt, pa, join_ass, join_root, old_table, other_tables)); } + + return CT_SUCCESS; +} + +static status_t make_base_join_tbl(sql_stmt_t *stmt, sql_table_t *table, sql_join_table_node_t *join_table_node) +{ + CT_RETURN_IFERR(sql_stack_alloc(stmt->context, sizeof(sql_join_table_t), (void **)&join_table_node->join_table)); + sql_bitmap_init(&join_table_node->join_table->table_ids); + sql_bitmap_make_singleton(table->id, &join_table_node->join_table->table_ids); + join_table_node->join_table->table_type = BASE_TABLE; + join_table_node->join_table->join_info = table->join_info; + // TODO: check indexable, get index、sequence scan cost,get path list + // TODO: sql_get_cheapest_path(join_table_node->join_table); + return CT_SUCCESS; } static status_t sql_create_join_tree_new(sql_stmt_t *stmt, plan_assist_t *pa, join_assist_t *join_ass, sql_join_node_t **join_root) { - CT_RETURN_IFERR(sql_alloc_mem(stmt->context, sizeof((pa->table_count) * sizeof(bilist_t*)), (void **)&pa->join_tbl_level)); + CT_RETURN_IFERR(sql_stack_alloc(stmt->context, sizeof((pa->table_count) * sizeof(bilist_t*)), (void **)&pa->join_tbl_level)); for (uint32 i = 0; i < pa->table_count; i++) { cm_bilist_init(&pa->join_tbl_level[i]); } @@ -921,17 +964,19 @@ static status_t sql_create_join_tree_new(sql_stmt_t *stmt, plan_assist_t *pa, jo for (uint32 i = 0; i < pa->table_count; i++) { sql_join_table_node_t *table_node = NULL; //sql_join_table_t is brief of sql_table_t CT_RETURN_IFERR(sql_stack_alloc(stmt, sizeof(sql_join_table_node_t), (void **)&table_node)); - sql_bitmap_make_singleton(pa->tables[i]->id, &table_node->join_table->table_ids); - table_node->join_table->table_type = BASE_TABLE; - table_node->join_table->join_info = pa->tables[i]->join_info; - cm_bilist_add_tail(&table_node->bilist_node, pa->join_tbl_level[0]); + CT_RETURN_IFERR(make_base_join_tbl(stmt, pa->tables[i], table_node)); + cm_bilist_add_tail(&table_node->bilist_node, &pa->join_tbl_level[0]); } - for (uint32 level = 1; level <= pa->table_count; level++) { + for (uint32 level = 1; level < pa->table_count; level++) { pa->join_cur_level = level; CT_RETURN_IFERR(sql_search_one_level(stmt, pa, join_ass, join_root)); - //sql_get_cheapest_path(); + //bilist_node_t *table_node = cm_bilist_head(&pa->join_tbl_level[level]); + //for (; table_node != NULL; table_node = BINODE_NEXT(table_node)) { + //TODO: sql_get_cheapest_path(join_table_node->join_table); + //sql_join_table_node_t *join_table_node = BILIST_NODE_OF(sql_join_table_node_t, table_node, bilist_node); + //} } return CT_SUCCESS; } diff --git a/pkg/src/ctsql/plan/plan_join.h b/pkg/src/ctsql/plan/plan_join.h index 75049838..1df3e419 100644 --- a/pkg/src/ctsql/plan/plan_join.h +++ b/pkg/src/ctsql/plan/plan_join.h @@ -26,6 +26,7 @@ #define __PLAN_JOIN_H__ #include "ctsql_plan.h" +#include "ctsql_context.h" typedef struct st_join_assist { uint32 count; @@ -35,6 +36,64 @@ typedef struct st_join_assist { sql_join_node_t *selected_nodes[CT_MAX_JOIN_TABLES]; } join_assist_t; +typedef struct st_join_path{ + sql_join_node_t *join_node; + double cost; + double rows; + uint32 relids; + sql_join_type_t join_type; + join_oper_t join_method; + cond_tree_t *join_cond; + cond_tree_t *filter; + struct st_join_path *outer; + struct st_join_path *inner; + bool32 is_required; +} join_path_t; + +typedef struct st_tbl_join_info { + sql_join_type_t join_type; + join_tbl_bitmap_t table_ids; // bitmap of table ids +} tbl_join_info_t; + +typedef struct st_tbl_join_info_node { + bilist_node_t bilist_node; + tbl_join_info_t join_info; +} tbl_join_info_node_t; + +typedef struct st_special_join_info { + join_tbl_bitmap_t min_lefthand; + join_tbl_bitmap_t min_righthand; + join_tbl_bitmap_t syn_lefthand; + join_tbl_bitmap_t syn_righthand; + sql_join_type_t jointype; /* always INNER, LEFT, FULL, SEMI, or ANTI */ + bool lhs_strict; + bool delay_upper_joins; + bool varratio_cached; + bool is_straight_join; +} special_join_info_t; + +typedef enum join_table_type_t { + BASE_TABLE, + JOIN_TABLE +} join_table_type_t; + +typedef struct st_sql_join_table { + join_table_type_t table_type; + double rows; + int encode_width; + bilist_t join_path; + join_path_t *cheapest_startup_path; + join_path_t *cheapest_total_path; + join_tbl_bitmap_t table_ids; // bitmap of table_ids + bilist_t join_info; +}sql_join_table_t; + +typedef struct st_sql_join_table_node { + bilist_node_t bilist_node; + sql_join_table_t *join_table; +} sql_join_table_node_t; + + bool32 need_adjust_hash_order(sql_join_node_t *join_root); status_t sql_build_join_tree(sql_stmt_t *stmt, plan_assist_t *plan_ass, sql_join_node_t **join_root); status_t sql_create_join_plan(sql_stmt_t *stmt, plan_assist_t *pa, sql_join_node_t *join_node, cond_tree_t *cond, diff --git a/pkg/src/ctsql/plan/plan_join_bitmap.c b/pkg/src/ctsql/plan/plan_join_bitmap.c index 148d85d1..6aaa22fe 100644 --- a/pkg/src/ctsql/plan/plan_join_bitmap.c +++ b/pkg/src/ctsql/plan/plan_join_bitmap.c @@ -22,18 +22,22 @@ * * ------------------------------------------------------------------------- */ -#include "srv_instance.h" -#include "table_parser.h" -#include "ctsql_transform.h" -#include "ctsql_plan_defs.h" -#include "plan_join.h" -#include "plan_rbo.h" + +#include "plan_join_bitmap.h" #ifdef __cplusplus extern "C" { #endif -static void sql_bitmap_make_singleton(uint32 table_id, join_tbl_bitmap_t* tables_bms) +void sql_bitmap_init(join_tbl_bitmap_t *result) +{ + result->num = 0; + for (uint32 i = 0; i < MAX_JOIN_TABLE_GROUP; i++) { //init + result->ids[i] = 0; + } +} + +void sql_bitmap_make_singleton(uint32 table_id, join_tbl_bitmap_t* tables_bms) { uint32 wordnum, bitnum; @@ -44,40 +48,40 @@ static void sql_bitmap_make_singleton(uint32 table_id, join_tbl_bitmap_t* tables return; } -static void sql_bitmap_copy(join_tbl_bitmap_t *a, join_tbl_bitmap_t *result) +void sql_bitmap_copy(join_tbl_bitmap_t *a, join_tbl_bitmap_t *result) { - if (a == NULL) { - result = a; + if (a->num == 0) { + sql_bitmap_init(result); return; } - for (uint32 i = 0; i < MAX_JOIN_TABLE_GROUP; i++) { //init - result->num[i] = 0; - } result->num = a->num; for (uint32 i = 0; i < a->num; i++) { - result->ids[i] = a->num[i]; + result->ids[i] = a->ids[i]; } } -static void sql_bitmap_union_singleton(uint32 a, uint32 b, join_tbl_bitmap_t* result) +void sql_bitmap_union_singleton(uint32 a, uint32 b, join_tbl_bitmap_t* result) { join_tbl_bitmap_t bitmap_a; join_tbl_bitmap_t bitmap_b; + sql_bitmap_init(&bitmap_a); + sql_bitmap_init(&bitmap_b); + sql_bitmap_make_singleton(a, &bitmap_a); sql_bitmap_make_singleton(b, &bitmap_b); sql_bitmap_union(&bitmap_a, &bitmap_b, result); } -static void sql_bitmap_union(join_tbl_bitmap_t *a, join_tbl_bitmap_t *b, join_tbl_bitmap_t* result) +void sql_bitmap_union(join_tbl_bitmap_t *a, join_tbl_bitmap_t *b, join_tbl_bitmap_t* result) { join_tbl_bitmap_t *other = NULL; - if (b == NULL) { + if (b->num == 0) { sql_bitmap_copy(a, result); return; } - if (a == NULL) { + if (a->num == 0) { sql_bitmap_copy(b, result); return; } @@ -90,24 +94,26 @@ static void sql_bitmap_union(join_tbl_bitmap_t *a, join_tbl_bitmap_t *b, join_tb other = b; } /* And union the shorter input into the result */ - for (uint32 i = 0; i < other->num; i++) + for (uint32 i = 0; i < other->num; i++) { result->ids[i] |= other->ids[i]; + + } return; } -bool sql_bitmap_overlap(join_tbl_bitmap_t* a, join_tbl_bitmap_t* b) +bool8 sql_bitmap_overlap(join_tbl_bitmap_t* a, join_tbl_bitmap_t* b) { - if (a == NULL || b == NULL) { - return false; + if (a->num == 0 || b->num == 0) { + return CT_FALSE; } /* Check ids in common */ - uint32 shortlen = Min(a->num, b->num); + uint32 shortlen = MIN(a->num, b->num); for (uint32 i = 0; i < shortlen; i++) { if ((a->ids[i] & b->ids[i]) != 0) { - return true; + return CT_TRUE; } } - return false; + return CT_FALSE; } #ifdef __cplusplus diff --git a/pkg/src/ctsql/plan/plan_join_bitmap.h b/pkg/src/ctsql/plan/plan_join_bitmap.h index b161db3c..778aad5e 100644 --- a/pkg/src/ctsql/plan/plan_join_bitmap.h +++ b/pkg/src/ctsql/plan/plan_join_bitmap.h @@ -22,12 +22,8 @@ * * ------------------------------------------------------------------------- */ -#include "srv_instance.h" -#include "table_parser.h" -#include "ctsql_transform.h" -#include "ctsql_plan_defs.h" -#include "plan_join.h" -#include "plan_rbo.h" + +#include "cm_defs.h" #ifdef __cplusplus extern "C" { @@ -39,6 +35,7 @@ typedef struct st_join_tbl_bitmap { uint32 ids[MAX_JOIN_TABLE_GROUP]; // ids[i] = (1 << table_id % 64) } join_tbl_bitmap_t; +void sql_bitmap_init(join_tbl_bitmap_t *result); void sql_bitmap_make_singleton(uint32 table_id, join_tbl_bitmap_t* tables_bms); @@ -48,7 +45,7 @@ void sql_bitmap_union_singleton(uint32 a, uint32 b, join_tbl_bitmap_t* result); void sql_bitmap_union(join_tbl_bitmap_t *a, join_tbl_bitmap_t *b, join_tbl_bitmap_t* result); -bool sql_bitmap_overlap(join_tbl_bitmap_t* a, join_tbl_bitmap_t* b); +bool8 sql_bitmap_overlap(join_tbl_bitmap_t* a, join_tbl_bitmap_t* b); #ifdef __cplusplus } diff --git a/pkg/src/ctsql/plan/plan_query.c b/pkg/src/ctsql/plan/plan_query.c index 741ba2b5..55346e4f 100644 --- a/pkg/src/ctsql/plan/plan_query.c +++ b/pkg/src/ctsql/plan/plan_query.c @@ -199,7 +199,7 @@ plan_node_type_t sql_get_group_plan_type(sql_stmt_t *stmt, sql_query_t *query) } } } - return PLAN_NODE_HASH_GROUP; + return PLAN_NODE_HASH_GROUP; //TODO:ǰʱŻSORT_GROUPҪݴ۹ʱHASH_GROUPSORT_GROUP } static status_t sql_generate_group_sets(sql_stmt_t *stmt, sql_query_t *query, group_plan_t *group_p) -- Gitee