From d8cb08bed8dec5a1cc7e2ae4764e77fab3189fad Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 13 Aug 2025 16:51:58 +0900 Subject: [PATCH 001/112] =?UTF-8?q?(feature)=20=5Fdb=5Fhistogram=20catalog?= =?UTF-8?q?=20class=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/schema_system_catalog.cpp | 5 +- src/object/schema_system_catalog_constants.h | 2 + src/object/schema_system_catalog_install.cpp | 72 +++++++++++++++++++ src/object/schema_system_catalog_install.hpp | 3 + ...hema_system_catalog_install_query_spec.cpp | 26 +++++++ 5 files changed, 106 insertions(+), 2 deletions(-) diff --git a/src/object/schema_system_catalog.cpp b/src/object/schema_system_catalog.cpp index 1927435b938..2b2950e555b 100644 --- a/src/object/schema_system_catalog.cpp +++ b/src/object/schema_system_catalog.cpp @@ -79,8 +79,8 @@ namespace cubschema CT_CHARSET_NAME, // "_db_charset" CT_DB_SERVER_NAME, // "_db_server" CT_SYNONYM_NAME, // "_db_synonym" - CT_TRIGGER_NAME, // "db_trigger" + CT_DB_HISTOGRAM_NAME, // "_db_histogram" /* currently, not implemented */ CT_RESOLUTION_NAME // "_db_resolution" @@ -110,7 +110,8 @@ namespace cubschema CTV_DB_COLLATION_NAME, // "db_collation" CTV_DB_CHARSET_NAME, // "db_charset" CTV_DB_SERVER_NAME, // "db_server" - CTV_SYNONYM_NAME // "db_synonym" + CTV_SYNONYM_NAME, // "db_synonym" + CTV_DB_HISTOGRAM_NAME // "db_histogram" }; static const identifier_store sm_catalog_class_names (sm_system_class_names, false); diff --git a/src/object/schema_system_catalog_constants.h b/src/object/schema_system_catalog_constants.h index 909dcb98dbe..4bbb351c32c 100644 --- a/src/object/schema_system_catalog_constants.h +++ b/src/object/schema_system_catalog_constants.h @@ -55,6 +55,7 @@ #define CT_DUAL_NAME "dual" #define CT_DB_SERVER_NAME "_db_server" #define CT_SYNONYM_NAME "_db_synonym" +#define CT_DB_HISTOGRAM_NAME "_db_histogram" /* catalog vclasses */ #define CTV_CLASS_NAME "db_class" @@ -77,6 +78,7 @@ #define CTV_DB_CHARSET_NAME "db_charset" #define CTV_DB_SERVER_NAME "db_server" #define CTV_SYNONYM_NAME "db_synonym" +#define CTV_DB_HISTOGRAM_NAME "db_histogram" #define CT_DBCOLL_COLL_ID_COLUMN "coll_id" #define CT_DBCOLL_COLL_NAME_COLUMN "coll_name" diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index cc45379b583..9cdc1caea94 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -232,6 +232,7 @@ catcls_init (void) ADD_TABLE_DEFINITION (CT_DUAL_NAME, system_catalog_initializer::get_dual()); ADD_TABLE_DEFINITION (CT_SYNONYM_NAME, system_catalog_initializer::get_synonym()); ADD_TABLE_DEFINITION (CT_DB_SERVER_NAME, system_catalog_initializer::get_db_server()); + ADD_TABLE_DEFINITION (CT_DB_HISTOGRAM_NAME, system_catalog_initializer::get_db_histogram()); ADD_VIEW_DEFINITION (CTV_CLASS_NAME, system_catalog_initializer::get_view_class ()); ADD_VIEW_DEFINITION (CTV_SUPER_CLASS_NAME, system_catalog_initializer::get_view_super_class ()); @@ -253,6 +254,7 @@ catcls_init (void) ADD_VIEW_DEFINITION (CTV_DB_CHARSET_NAME, system_catalog_initializer::get_view_db_charset ()); ADD_VIEW_DEFINITION (CTV_DB_SERVER_NAME, system_catalog_initializer::get_view_db_server ()); ADD_VIEW_DEFINITION (CTV_SYNONYM_NAME, system_catalog_initializer::get_view_synonym ()); + ADD_VIEW_DEFINITION (CTV_DB_HISTOGRAM_NAME, system_catalog_initializer::get_view_db_histogram ()); } int @@ -1257,6 +1259,41 @@ namespace cubschema } + system_catalog_definition + system_catalog_initializer::get_db_histogram () + { +// db_class + return system_catalog_definition ( + // name + CT_DB_HISTOGRAM_NAME, + // columns + { + {"class_of", CT_CLASS_NAME}, + {"def_index", "integer"}, + {"data_type", "integer"}, + {"histogram_type", "varchar(32)"}, + {"bucket_count", "integer"}, + {"histogram_values", "varchar(2048)"}, + }, +// constraint + { + {DB_CONSTRAINT_INDEX, "", {"class_of", "def_index", nullptr}, false} + }, +// authorization + { + // owner + Au_dba_user, + // grants + { + {Au_public_user, AU_SELECT, false} + } + }, +// initializer + nullptr + ); + + } + /* ========================================================================== */ /* NEW DEFINITION (VCLASS) */ /* ========================================================================== */ @@ -2021,4 +2058,39 @@ namespace cubschema ); } + + system_catalog_definition + system_catalog_initializer::get_view_db_histogram () + { +// db_class + return system_catalog_definition ( + // name + CTV_DB_HISTOGRAM_NAME, + // columns + { + {"class_of", CT_CLASS_NAME}, + {"def_index", "integer"}, + {"data_type", "integer"}, + {"histogram_type", "varchar(32)"}, + {"bucket_count", "integer"}, + {"histogram_values", "varchar(2048)"}, + // query specs + {attribute_kind::QUERY_SPEC, sm_define_view_db_histogram_spec ()} + }, +// constraint + {}, +// authorization + { + // owner + Au_dba_user, + // grants + { + {Au_public_user, AU_SELECT, false} + } + }, +// initializer + nullptr + ); + + } } diff --git a/src/object/schema_system_catalog_install.hpp b/src/object/schema_system_catalog_install.hpp index 98133d956e9..dd2ea1c9235 100644 --- a/src/object/schema_system_catalog_install.hpp +++ b/src/object/schema_system_catalog_install.hpp @@ -57,6 +57,7 @@ namespace cubschema static system_catalog_definition get_dual (); static system_catalog_definition get_db_server (); static system_catalog_definition get_synonym (); + static system_catalog_definition get_db_histogram (); // views static system_catalog_definition get_view_class (); @@ -79,6 +80,7 @@ namespace cubschema static system_catalog_definition get_view_db_charset (); static system_catalog_definition get_view_synonym (); static system_catalog_definition get_view_db_server (); + static system_catalog_definition get_view_db_histogram (); }; } @@ -103,5 +105,6 @@ const char *sm_define_view_db_collation_spec (void); const char *sm_define_view_db_charset_spec (void); const char *sm_define_view_synonym_spec (void); const char *sm_define_view_db_server_spec (void); +const char *sm_define_view_db_histogram_spec (void); #endif /* _SCHEMA_SYSTEM_CATALOG_INSTALL_HPP_ */ diff --git a/src/object/schema_system_catalog_install_query_spec.cpp b/src/object/schema_system_catalog_install_query_spec.cpp index a1183e46852..a6fa356a0a0 100644 --- a/src/object/schema_system_catalog_install_query_spec.cpp +++ b/src/object/schema_system_catalog_install_query_spec.cpp @@ -1582,3 +1582,29 @@ sm_define_view_db_server_spec (void) return stmt; } + +const char * +sm_define_view_db_histogram_spec (void) +{ + static char stmt [2048]; + + // *INDENT-OFF* + sprintf (stmt, + "SELECT " + "[h].[class_of] AS [class_of], " + "[h].[def_index] AS [def_index], " + "[h].[data_type] AS [data_type], " + "[h].[histogram_type] AS [histogram_type], " + "[h].[bucket_count] AS [bucket_count], " + "[h].[histogram_values] AS [histogram_values] " + "FROM " + /* CT_DB_HISTOGRAM_NAME */ + "[%s] AS [h] " + "ORDER BY " /* Is it possible to remove ORDER BY? */ + "[h].[class_of], " + "[h].[def_index]", + CT_DB_HISTOGRAM_NAME); + // *INDENT-ON* + + return stmt; +} \ No newline at end of file From 8b7c4146fffddc739d0ad8cd95568e85ab0f6709 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 14 Aug 2025 16:14:25 +0900 Subject: [PATCH 002/112] =?UTF-8?q?(feature)=20CBRD-26217:=20histogram=20d?= =?UTF-8?q?dl=20=EC=9B=90=ED=98=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :빌드 되게 만들고 나머지 TODO 및 ASSERT 처리 --- src/base/ddl_log.c | 1 + src/communication/network_sr.c | 9 +++++ src/compat/dbtype_def.h | 1 + src/parser/csql_grammar.y | 66 ++++++++++++++++++++++++++++++++++ src/parser/csql_lexer.l | 1 + src/parser/name_resolution.c | 4 +++ src/parser/parse_tree.h | 11 ++++++ src/parser/parse_tree_cl.c | 53 +++++++++++++++++++++++++++ src/parser/parser_message.h | 1 + src/parser/parser_support.c | 1 + src/parser/semantic_check.c | 2 ++ 11 files changed, 150 insertions(+) diff --git a/src/base/ddl_log.c b/src/base/ddl_log.c index bdb77288425..ac1ca460c1e 100644 --- a/src/base/ddl_log.c +++ b/src/base/ddl_log.c @@ -1433,6 +1433,7 @@ logddl_is_ddl_type (int node_type, PT_NODE * node) case PT_CREATE_ENTITY: case PT_CREATE_INDEX: case PT_CREATE_SERIAL: + case PT_CREATE_HISTOGRAM: case PT_CREATE_STORED_PROCEDURE: case PT_CREATE_SYNONYM: case PT_CREATE_TRIGGER: diff --git a/src/communication/network_sr.c b/src/communication/network_sr.c index 9320f6c2857..a03783dad2c 100644 --- a/src/communication/network_sr.c +++ b/src/communication/network_sr.c @@ -453,6 +453,15 @@ net_server_init (void) req_p->action_attribute = (CHECK_DB_MODIFICATION | IN_TRANSACTION); req_p->processing_function = sqst_update_statistics; +// /* TODO: histogram */ +// req_p = &net_Requests[NET_SERVER_CT_GET_HISTOGRAM]; +// req_p->action_attribute = IN_TRANSACTION; +// req_p->processing_function = sct_get_histogram; + +// req_p = &net_Requests[NET_SERVER_CT_UPDATE_HISTOGRAM]; +// req_p->action_attribute = (CHECK_DB_MODIFICATION | IN_TRANSACTION); +// req_p->processing_function = sct_update_histogram; + /* query manager */ req_p = &net_Requests[NET_SERVER_QM_QUERY_PREPARE]; req_p->action_attribute = IN_TRANSACTION; diff --git a/src/compat/dbtype_def.h b/src/compat/dbtype_def.h index 5645fbb41f8..4a36f12151d 100644 --- a/src/compat/dbtype_def.h +++ b/src/compat/dbtype_def.h @@ -119,6 +119,7 @@ extern "C" CUBRID_STMT_ALTER_USER, CUBRID_STMT_SET_SYS_PARAMS, CUBRID_STMT_ALTER_INDEX, + CUBRID_STMT_CREATE_HISTOGRAM, CUBRID_STMT_CREATE_STORED_PROCEDURE, CUBRID_STMT_DROP_STORED_PROCEDURE, diff --git a/src/parser/csql_grammar.y b/src/parser/csql_grammar.y index d03e6692d2e..06585ad54d5 100644 --- a/src/parser/csql_grammar.y +++ b/src/parser/csql_grammar.y @@ -698,6 +698,8 @@ BEGIN_SUPPRESS_WARNING_BISON_FLEX %type drop_stmt %type opt_index_column_name_list %type index_column_name_list +%type histogram_column_list +%type histogram_column %type update_statistics_stmt %type only_class_name_list %type opt_level_spec @@ -1267,6 +1269,7 @@ BEGIN_SUPPRESS_WARNING_BISON_FLEX %token GRANT %token GROUP_ %token HAVING +%token HISTOGRAM %token HOUR_ %token HOUR_MILLISECOND %token HOUR_SECOND @@ -3138,6 +3141,43 @@ create_stmt $$ = node; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} + | CREATE /* 1 */ + { /* 2 */ + DBG_TRACE_GRAMMAR(create_stmt, | CREATE); + PT_NODE* node = parser_new_node (this_parser, PT_CREATE_HISTOGRAM); + parser_push_hint_node (node); + push_msg (MSGCAT_SYNTAX_INVALID_CREATE_HISTOGRAM); + } + HISTOGRAM /* 3 */ + { pop_msg(); } /* 4 */ + ON_ /* 5 */ + only_class_name /* 6 */ + '(' histogram_column_list ')' /* 8 */ + opt_comment_spec /* 9 */ + {{ DBG_TRACE_GRAMMAR (create_stmt, | CREATE HISTOGRAM ON_ ~); + + PT_NODE *node = parser_pop_hint_node (); + PARSER_SAVE_ERR_CONTEXT (node, @$.buffer_pos) + PT_NODE *ocs = parser_new_node(this_parser, PT_SPEC); + + if (node && ocs) + { + PT_NODE *col, *temp; + int arg_count = 0, prefix_col_count = 0; + ocs->info.spec.entity_name = $6; + PARSER_SAVE_ERR_CONTEXT (ocs, @6.buffer_pos) + ocs->info.spec.meta_class = PT_CLASS; + node->info.histogram.target_table_name = ocs; + col = $8; + + prefix_col_count = parser_count_prefix_columns (col, &arg_count); + node->info.histogram.target_columns = col; + } + + $$ = node; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} | CREATE /* 1 */ opt_or_replace /* 2 */ @@ -4956,6 +4996,32 @@ index_column_name_list DBG_PRINT}} ; +histogram_column_list + : /* empty */ + {{ DBG_TRACE_GRAMMAR(histogram_column_list, : ); + $$ = NULL; + DBG_PRINT}} + + | histogram_column_list ',' histogram_column + {{ DBG_TRACE_GRAMMAR(histogram_column_list, | histogram_column_list ',' histogram_column); + $$ = parser_make_link ($1, $3); + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} + | histogram_column + {{ DBG_TRACE_GRAMMAR(histogram_column_list, | histogram_column); + $$ = $1; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} + ; + +histogram_column + : identifier + {{ DBG_TRACE_GRAMMAR(histogram_column, | name); + $$ = $1; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} + ; + update_statistics_stmt : UPDATE STATISTICS ON_ only_class_name_list opt_with_fullscan {{ DBG_TRACE_GRAMMAR(update_statistics_stmt, : UPDATE STATISTICS ON_ only_class_name_list opt_with_fullscan); diff --git a/src/parser/csql_lexer.l b/src/parser/csql_lexer.l index 6991874f76a..a265e2e204a 100644 --- a/src/parser/csql_lexer.l +++ b/src/parser/csql_lexer.l @@ -444,6 +444,7 @@ IDL [a-zA-Z0-9_] [hH][eE][aA][pP] { begin_token(yytext); csql_yylval.cptr = pt_makename(yytext); return HEAP; } +[hH][iI][sS][tT][oO][gG][rR][aA][mM] { begin_token(yytext); return HISTOGRAM; } [hH][oO][sS][tT] { begin_token(yytext); csql_yylval.cptr = pt_makename(yytext); return HOST; } diff --git a/src/parser/name_resolution.c b/src/parser/name_resolution.c index 62223e6cfe1..7d8ca087048 100644 --- a/src/parser/name_resolution.c +++ b/src/parser/name_resolution.c @@ -3294,6 +3294,10 @@ pt_bind_names (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue *continue_walk = PT_LIST_WALK; break; + case PT_CREATE_HISTOGRAM: + // TODO: histogram + break; + case PT_METHOD_CALL: /* * We accept two different method call syntax: diff --git a/src/parser/parse_tree.h b/src/parser/parse_tree.h index 38a71f4c68f..5f68e9a87c2 100644 --- a/src/parser/parse_tree.h +++ b/src/parser/parse_tree.h @@ -998,6 +998,7 @@ enum pt_node_type PT_REVOKE = CUBRID_STMT_REVOKE, PT_UPDATE_STATS = CUBRID_STMT_UPDATE_STATS, PT_GET_STATS = CUBRID_STMT_GET_STATS, + PT_CREATE_HISTOGRAM = CUBRID_STMT_CREATE_HISTOGRAM, //TODO PT_INSERT = CUBRID_STMT_INSERT, PT_SELECT = CUBRID_STMT_SELECT, PT_UPDATE = CUBRID_STMT_UPDATE, @@ -1799,6 +1800,7 @@ typedef struct pt_auth_cmd_info PT_AUTH_CMD_INFO; typedef struct pt_commit_work_info PT_COMMIT_WORK_INFO; typedef struct pt_create_entity_info PT_CREATE_ENTITY_INFO; typedef struct pt_index_info PT_INDEX_INFO; +typedef struct pt_histogram_info PT_HISTOGRAM_INFO; typedef struct pt_create_user_info PT_CREATE_USER_INFO; typedef struct pt_create_trigger_info PT_CREATE_TRIGGER_INFO; typedef struct pt_cte_info PT_CTE_INFO; @@ -2183,6 +2185,14 @@ struct pt_index_info short deduplicate_level; /* -1: Not set yet, 0 : Not Use, others : mod by pow(2,deduplicate_level), refer to DEDUPLICATE_KEY_LEVEL_??? */ }; +/* CREATE HISTOGRAM INFO */ + +struct pt_histogram_info +{ + PT_NODE *target_table_name; /* PT_NAME */ + PT_NODE *target_columns; /* PT_NAME list */ +}; + /* CREATE USER INFO */ struct pt_create_user_info { @@ -3694,6 +3704,7 @@ union pt_statement_info PT_GRANT_INFO grant; PT_HOST_VAR_INFO host_var; PT_INDEX_INFO index; + PT_HISTOGRAM_INFO histogram; PT_INSERT_INFO insert; PT_INSERT_VALUE_INFO insert_value; PT_ISOLATION_LVL_INFO isolation_lvl; diff --git a/src/parser/parse_tree_cl.c b/src/parser/parse_tree_cl.c index ca16b1b599a..0366628d6fa 100644 --- a/src/parser/parse_tree_cl.c +++ b/src/parser/parse_tree_cl.c @@ -212,6 +212,7 @@ static PT_NODE *pt_apply_commit_work (PARSER_CONTEXT * parser, PT_NODE * p, void static PT_NODE *pt_apply_constraint (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); static PT_NODE *pt_apply_create_entity (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); static PT_NODE *pt_apply_create_index (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); +static PT_NODE *pt_apply_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); static PT_NODE *pt_apply_create_user (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); static PT_NODE *pt_apply_data_default (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); static PT_NODE *pt_apply_datatype (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); @@ -340,6 +341,7 @@ static PARSER_VARCHAR *pt_print_constraint (PARSER_CONTEXT * parser, PT_NODE * p static PARSER_VARCHAR *pt_print_col_def_constraint (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_entity (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_index (PARSER_CONTEXT * parser, PT_NODE * p); +static PARSER_VARCHAR *pt_print_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_serial (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_trigger (PARSER_CONTEXT * parser, PT_NODE * p); @@ -3071,6 +3073,8 @@ pt_show_node_type (PT_NODE * node) return "CREATE_ENTITY"; case PT_CREATE_INDEX: return "CREATE_INDEX"; + case PT_CREATE_HISTOGRAM: + return "CREATE_HISTOGRAM"; case PT_CREATE_USER: return "CREATE_USER"; case PT_CREATE_TRIGGER: @@ -5030,6 +5034,7 @@ pt_init_apply_f (void) pt_apply_func_array[PT_COMMIT_WORK] = pt_apply_commit_work; pt_apply_func_array[PT_CREATE_ENTITY] = pt_apply_create_entity; pt_apply_func_array[PT_CREATE_INDEX] = pt_apply_create_index; + pt_apply_func_array[PT_CREATE_HISTOGRAM] = pt_apply_create_histogram; //TODO pt_apply_func_array[PT_CREATE_USER] = pt_apply_create_user; pt_apply_func_array[PT_CREATE_TRIGGER] = pt_apply_create_trigger; pt_apply_func_array[PT_CREATE_SERIAL] = pt_apply_create_serial; @@ -5164,6 +5169,7 @@ pt_init_init_f (void) pt_init_func_array[PT_COMMIT_WORK] = pt_init_func_null_function; pt_init_func_array[PT_CREATE_ENTITY] = pt_init_create_entity; pt_init_func_array[PT_CREATE_INDEX] = pt_init_create_index; + pt_init_func_array[PT_CREATE_HISTOGRAM] = pt_init_func_null_function; //TODO pt_init_func_array[PT_CREATE_USER] = pt_init_func_null_function; pt_init_func_array[PT_CREATE_TRIGGER] = pt_init_func_null_function; pt_init_func_array[PT_CREATE_SERIAL] = pt_init_func_null_function; @@ -5294,6 +5300,7 @@ pt_init_print_f (void) pt_print_func_array[PT_COMMIT_WORK] = pt_print_commit_work; pt_print_func_array[PT_CREATE_ENTITY] = pt_print_create_entity; pt_print_func_array[PT_CREATE_INDEX] = pt_print_create_index; + pt_print_func_array[PT_CREATE_HISTOGRAM] = pt_print_create_histogram; //TODO pt_print_func_array[PT_CREATE_USER] = pt_print_create_user; pt_print_func_array[PT_CREATE_TRIGGER] = pt_print_create_trigger; pt_print_func_array[PT_CREATE_SERIAL] = pt_print_create_serial; @@ -7347,6 +7354,52 @@ pt_apply_create_index (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) return p; } +/* CREATE_HISTOGRAM */ +/* + * pt_init_create_histogram () - + * return: + * p(in): + */ +static PT_NODE * +pt_init_create_histogram (PT_NODE * p) +{ + // TODO: implement this + assert (false); + return p; +} + +/* + * pt_apply_create_histogram () - + * return: + * parser(in): + * p(in): + * g(in): + * arg(in): + */ +static PT_NODE * +pt_apply_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) +{ + // TODO: implement this + assert (false); + return p; +} + +/* + * pt_apply_create_histogram () - + * return: + * parser(in): + * p(in): + * g(in): + * arg(in): + */ +static PARSER_VARCHAR * +pt_print_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p) +{ + // TODO: implement this + assert (false); + return NULL; +} + /* * pt_init_create_index () - * return: diff --git a/src/parser/parser_message.h b/src/parser/parser_message.h index 198435f6703..871897b2bfb 100644 --- a/src/parser/parser_message.h +++ b/src/parser/parser_message.h @@ -174,6 +174,7 @@ #define MSGCAT_SYNTAX_MAX_SERVER_USER_LEN MSGCAT_SYNTAX_NO(137) #define MSGCAT_SYNTAX_INVALID_LEVEL MSGCAT_SYNTAX_NO(138) #define MSGCAT_SYNTAX_NO_PRECISION_IN_SP_FUNCTION MSGCAT_SYNTAX_NO(139) +#define MSGCAT_SYNTAX_INVALID_CREATE_HISTOGRAM MSGCAT_SYNTAX_NO(140) /* Message id in the set MSGCAT_SET_PARSER_SEMANTIC */ diff --git a/src/parser/parser_support.c b/src/parser/parser_support.c index 56f94240d0e..22072de1608 100644 --- a/src/parser/parser_support.c +++ b/src/parser/parser_support.c @@ -1490,6 +1490,7 @@ pt_is_ddl_statement (const PT_NODE * node) case PT_REMOVE_TRIGGER: case PT_RENAME_TRIGGER: case PT_UPDATE_STATS: + case PT_CREATE_HISTOGRAM: //TODO /* TODO: check it */ case PT_CREATE_SERVER: case PT_DROP_SERVER: diff --git a/src/parser/semantic_check.c b/src/parser/semantic_check.c index 8369a8e771f..2fc7aa863e8 100644 --- a/src/parser/semantic_check.c +++ b/src/parser/semantic_check.c @@ -12327,6 +12327,8 @@ pt_check_with_info (PARSER_CONTEXT * parser, PT_NODE * node, SEMANTIC_CHK_INFO * } break; + case PT_CREATE_HISTOGRAM: + break; case PT_SAVEPOINT: if ((node->info.savepoint.save_name) && (node->info.savepoint.save_name->info.name.meta_class == PT_PARAMETER)) { From a64b9433d366c363b6baf5b62de1cd4d1d310cfd Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 20 Aug 2025 13:14:47 +0900 Subject: [PATCH 003/112] =?UTF-8?q?(feature)=20pt=5Fprint=5Fcreate=5Fhisto?= =?UTF-8?q?gram=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parser/csql_grammar.y | 2 +- src/parser/parse_tree.h | 20 ++++---- src/parser/parse_tree_cl.c | 94 ++++++++++++++++++++++++++------------ 3 files changed, 77 insertions(+), 39 deletions(-) diff --git a/src/parser/csql_grammar.y b/src/parser/csql_grammar.y index 06585ad54d5..a56564baff6 100644 --- a/src/parser/csql_grammar.y +++ b/src/parser/csql_grammar.y @@ -3168,7 +3168,7 @@ create_stmt ocs->info.spec.entity_name = $6; PARSER_SAVE_ERR_CONTEXT (ocs, @6.buffer_pos) ocs->info.spec.meta_class = PT_CLASS; - node->info.histogram.target_table_name = ocs; + node->info.histogram.target_table_spec = ocs; col = $8; prefix_col_count = parser_count_prefix_columns (col, &arg_count); diff --git a/src/parser/parse_tree.h b/src/parser/parse_tree.h index 5f68e9a87c2..a1983de5312 100644 --- a/src/parser/parse_tree.h +++ b/src/parser/parse_tree.h @@ -998,7 +998,7 @@ enum pt_node_type PT_REVOKE = CUBRID_STMT_REVOKE, PT_UPDATE_STATS = CUBRID_STMT_UPDATE_STATS, PT_GET_STATS = CUBRID_STMT_GET_STATS, - PT_CREATE_HISTOGRAM = CUBRID_STMT_CREATE_HISTOGRAM, //TODO + PT_CREATE_HISTOGRAM = CUBRID_STMT_CREATE_HISTOGRAM, PT_INSERT = CUBRID_STMT_INSERT, PT_SELECT = CUBRID_STMT_SELECT, PT_UPDATE = CUBRID_STMT_UPDATE, @@ -2160,6 +2160,16 @@ struct pt_create_entity_info unsigned if_not_exists:1; /* IF NOT EXISTS clause for create table | class */ }; +/* CREATE HISTOGRAM INFO */ + +struct pt_histogram_info +{ + PT_NODE *target_table_spec; /* PT_SPEC */ + PT_NODE *target_columns; /* PT_COLUMN_LIST (PT_NAME) */ + int histogram_type; /* histogram type */ + int bucket_count; /* bucket count */ +}; + /* CREATE/DROP INDEX INFO */ struct pt_index_info { @@ -2185,14 +2195,6 @@ struct pt_index_info short deduplicate_level; /* -1: Not set yet, 0 : Not Use, others : mod by pow(2,deduplicate_level), refer to DEDUPLICATE_KEY_LEVEL_??? */ }; -/* CREATE HISTOGRAM INFO */ - -struct pt_histogram_info -{ - PT_NODE *target_table_name; /* PT_NAME */ - PT_NODE *target_columns; /* PT_NAME list */ -}; - /* CREATE USER INFO */ struct pt_create_user_info { diff --git a/src/parser/parse_tree_cl.c b/src/parser/parse_tree_cl.c index 0366628d6fa..3f9a7db69a1 100644 --- a/src/parser/parse_tree_cl.c +++ b/src/parser/parse_tree_cl.c @@ -293,6 +293,7 @@ static PT_NODE *pt_init_auth_cmd (PT_NODE * p); static PT_NODE *pt_init_constraint (PT_NODE * node); static PT_NODE *pt_init_create_entity (PT_NODE * p); static PT_NODE *pt_init_create_index (PT_NODE * p); +static PT_NODE *pt_init_create_histogram (PT_NODE * p); static PT_NODE *pt_init_data_default (PT_NODE * p); static PT_NODE *pt_init_datatype (PT_NODE * p); static PT_NODE *pt_init_delete (PT_NODE * p); @@ -5169,7 +5170,7 @@ pt_init_init_f (void) pt_init_func_array[PT_COMMIT_WORK] = pt_init_func_null_function; pt_init_func_array[PT_CREATE_ENTITY] = pt_init_create_entity; pt_init_func_array[PT_CREATE_INDEX] = pt_init_create_index; - pt_init_func_array[PT_CREATE_HISTOGRAM] = pt_init_func_null_function; //TODO + pt_init_func_array[PT_CREATE_HISTOGRAM] = pt_init_create_histogram; //TODO pt_init_func_array[PT_CREATE_USER] = pt_init_func_null_function; pt_init_func_array[PT_CREATE_TRIGGER] = pt_init_func_null_function; pt_init_func_array[PT_CREATE_SERIAL] = pt_init_func_null_function; @@ -7333,27 +7334,6 @@ pt_print_create_entity (PARSER_CONTEXT * parser, PT_NODE * p) return q; } -/* CREATE_INDEX */ -/* - * pt_apply_create_index () - - * return: - * parser(in): - * p(in): - * g(in): - * arg(in): - */ -static PT_NODE * -pt_apply_create_index (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) -{ - PT_APPLY_WALK (parser, p->info.index.indexed_class, arg); - PT_APPLY_WALK (parser, p->info.index.column_names, arg); - PT_APPLY_WALK (parser, p->info.index.index_name, arg); - PT_APPLY_WALK (parser, p->info.index.prefix_length, arg); - PT_APPLY_WALK (parser, p->info.index.where, arg); - PT_APPLY_WALK (parser, p->info.index.function_expr, arg); - return p; -} - /* CREATE_HISTOGRAM */ /* * pt_init_create_histogram () - @@ -7363,8 +7343,8 @@ pt_apply_create_index (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) static PT_NODE * pt_init_create_histogram (PT_NODE * p) { - // TODO: implement this - assert (false); + p->info.histogram.histogram_type = 0; + p->info.histogram.bucket_count = 256; return p; } @@ -7379,8 +7359,8 @@ pt_init_create_histogram (PT_NODE * p) static PT_NODE * pt_apply_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) { - // TODO: implement this - assert (false); + PT_APPLY_WALK (parser, p->info.histogram.target_table_spec, arg); + PT_APPLY_WALK (parser, p->info.histogram.target_columns, arg); return p; } @@ -7395,9 +7375,65 @@ pt_apply_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) static PARSER_VARCHAR * pt_print_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p) { - // TODO: implement this - assert (false); - return NULL; + PARSER_VARCHAR *b = 0, *tbl = 0, *cl = 0; + unsigned int saved_cp = parser->custom_print; + PT_NODE *target_columns; + + parser->custom_print |= PT_SUPPRESS_RESOLVED; + + if (!(parser->custom_print & PT_SUPPRESS_INDEX)) + { + b = pt_append_nulstring (parser, b, "create"); + } + + b = pt_append_nulstring (parser, b, " histogram"); + + if (p->info.histogram.target_table_spec) + { + tbl = pt_print_bytes (parser, p->info.histogram.target_table_spec); + } + + if (!(parser->custom_print & PT_SUPPRESS_INDEX)) + { + b = pt_append_nulstring (parser, b, " on "); + b = pt_append_varchar (parser, b, tbl); + } + + + if (p->info.histogram.target_columns) + { + target_columns = p->info.histogram.target_columns; + cl = pt_print_bytes_l (parser, target_columns); + } + + b = pt_append_nulstring (parser, b, " ("); + b = pt_append_varchar (parser, b, cl); + b = pt_append_nulstring (parser, b, ") "); + + parser->custom_print = saved_cp; + + return b; +} + +/* CREATE_INDEX */ +/* + * pt_apply_create_index () - + * return: + * parser(in): + * p(in): + * g(in): + * arg(in): + */ +static PT_NODE * +pt_apply_create_index (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) +{ + PT_APPLY_WALK (parser, p->info.index.indexed_class, arg); + PT_APPLY_WALK (parser, p->info.index.column_names, arg); + PT_APPLY_WALK (parser, p->info.index.index_name, arg); + PT_APPLY_WALK (parser, p->info.index.prefix_length, arg); + PT_APPLY_WALK (parser, p->info.index.where, arg); + PT_APPLY_WALK (parser, p->info.index.function_expr, arg); + return p; } /* From 142c028c28502c9c61986f048ba8001ccd595c03 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 22 Aug 2025 14:16:57 +0900 Subject: [PATCH 004/112] =?UTF-8?q?(feature)=20CBRD-26217:=20=ED=9E=88?= =?UTF-8?q?=EC=8A=A4=ED=86=A0=EA=B7=B8=EB=9E=A8=20DDL=20=EC=A4=91=EA=B0=84?= =?UTF-8?q?=EB=B6=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 중간부 구현: SERVER_SIDE로 가기 직전의 빌드 가능하고, 실행 가능한 상태로 중간 구현 --- src/parser/name_resolution.c | 14 ++- src/parser/semantic_check.c | 108 +++++++++++++++++ src/query/execute_schema.c | 213 ++++++++++++++++++++++++++++++++++ src/query/execute_statement.c | 10 ++ src/query/execute_statement.h | 2 + 5 files changed, 346 insertions(+), 1 deletion(-) diff --git a/src/parser/name_resolution.c b/src/parser/name_resolution.c index 7d8ca087048..8f4db800e25 100644 --- a/src/parser/name_resolution.c +++ b/src/parser/name_resolution.c @@ -3295,7 +3295,19 @@ pt_bind_names (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue break; case PT_CREATE_HISTOGRAM: - // TODO: histogram + scopestack.specs = node->info.histogram.target_table_spec; + bind_arg->scopes = &scopestack; + spec_frame.next = bind_arg->spec_frames; + spec_frame.extra_specs = NULL; + bind_arg->spec_frames = &spec_frame; + pt_bind_scope (parser, bind_arg); + + parser_walk_leaves (parser, node, pt_bind_names, bind_arg, pt_bind_names_post, bind_arg); + + bind_arg->spec_frames = bind_arg->spec_frames->next; + bind_arg->scopes = bind_arg->scopes->next; + + *continue_walk = PT_LIST_WALK; break; case PT_METHOD_CALL: diff --git a/src/parser/semantic_check.c b/src/parser/semantic_check.c index 2fc7aa863e8..4135c83072f 100644 --- a/src/parser/semantic_check.c +++ b/src/parser/semantic_check.c @@ -9112,6 +9112,91 @@ pt_check_create_index (PARSER_CONTEXT * parser, PT_NODE * node) pt_check_filter_index_expr (parser, node->info.index.column_names, node->info.index.where, db_obj); } +static void +pt_check_create_histogram (PARSER_CONTEXT * parser, PT_NODE * node) +{ + PT_NODE *name, *col, *col_expr; + DB_OBJECT *db_obj; + int is_partition = DB_NOT_PARTITIONED_CLASS; + + /* check that there trying to create an index on a class */ + name = node->info.histogram.target_table_spec->info.spec.entity_name; + + /* We cannot create index of a class by using synonym names. */ + if (db_find_synonym (name->info.name.original) != NULL) + { + PT_ERRORmf (parser, name, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_IS_NOT_A_CLASS, name->info.name.original); + return; + } + else + { + /* db_find_synonym () == NULL */ + ASSERT_ERROR (); + + if (er_errid () == ER_SYNONYM_NOT_EXIST) + { + er_clear (); + } + else + { + return; + } + } + + db_obj = db_find_class (name->info.name.original); + if (db_obj == NULL) + { + PT_ERRORmf (parser, name, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_IS_NOT_A_CLASS, name->info.name.original); + return; + } + + /* make sure it's not a virtual class */ + if (db_is_class (db_obj) <= 0) + { + PT_ERRORm (parser, name, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_NO_INDEX_ON_VCLASS); + return; + } + /* check if this is a partition class (TODO: to be implemented) */ + if (sm_partitioned_class_type (db_obj, &is_partition, NULL, NULL) != NO_ERROR) + { + PT_ERROR (parser, node, er_msg ()); + return; + } + + if (is_partition == DB_PARTITION_CLASS) + { + PT_ERRORm (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INVALID_PARTITION_REQUEST); + return; + } + + /* Check if the columns are valid. We only allow attribute names. we're only interested in the node type */ + for (col = node->info.histogram.target_columns; col != NULL; col = col->next) + { + if (col_expr->node_type == PT_NAME) + { + /* make sure this is not a parameter */ + if (col_expr->info.name.meta_class != PT_NORMAL) + { + PT_ERRORmf (parser, col_expr, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INVALID_INDEX_COLUMN, + pt_short_print (parser, col_expr)); + return; + } + } + } + + name->info.name.db_object = db_obj; + + /* check that histogram already exists */ + // TODO + + pt_check_user_owns_class (parser, name); + if (pt_has_error (parser)) + { + return; + } + +} + static void pt_check_alter_synonym (PARSER_CONTEXT * parser, PT_NODE * node) { @@ -12328,6 +12413,29 @@ pt_check_with_info (PARSER_CONTEXT * parser, PT_NODE * node, SEMANTIC_CHK_INFO * break; case PT_CREATE_HISTOGRAM: + if (parser->host_var_count) + { + PT_ERRORm (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_HOSTVAR_IN_DDL); + } + else + { + sc_info_ptr->system_class = false; + node = pt_resolve_names (parser, node, sc_info_ptr); + if (!pt_has_error (parser) && node->node_type == PT_CREATE_HISTOGRAM) + { + pt_check_create_histogram (parser, node); + } + + if (!pt_has_error (parser)) + { + node = pt_semantic_type (parser, node, info); + } + + if (node && !pt_has_error (parser)) + { + node = parser_walk_tree (parser, node, NULL, NULL, pt_semantic_check_local, sc_info_ptr); + } + } break; case PT_SAVEPOINT: if ((node->info.savepoint.save_name) && (node->info.savepoint.save_name->info.name.meta_class == PT_PARAMETER)) diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 425a3359739..9a9fa2af3dd 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -93,6 +93,11 @@ typedef enum DO_INDEX_CREATE, DO_INDEX_DROP } DO_INDEX; +typedef enum +{ + DO_HISTOGRAM_CREATE, DO_HISTOGRAM_DROP +} DO_HISTOGRAM; + typedef enum { SM_ATTR_CHG_NOT_NEEDED = 0, @@ -3863,6 +3868,214 @@ do_alter_index (PARSER_CONTEXT * parser, const PT_NODE * statement) return error; } + + +/* + * create_or_drop_histogram_helper() - Creates or drops a histogram on a class. + * return: Error code + * parser(in): Parser context + * obj(in): Class object + * histogram_info(in): Histogram information +*/ +static int +create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, PT_HISTOGRAM_INFO * const histogram_info, DO_HISTOGRAM do_histogram) +{ + assert (false); // TODO: implement + return NO_ERROR; +// int error = NO_ERROR; +// int nnames = 0; +// bool *already_exists = NULL; +// char **attnames = NULL; +// char *cname = NULL; +// bool free_packing_buff = false; +// PRED_EXPR_WITH_CONTEXT *filter_predicate = NULL; +// SM_PREDICATE_INFO pred_index_info = { NULL, NULL, 0, NULL, 0 }; +// SM_PREDICATE_INFO *p_pred_index_info = NULL; +// SM_FUNCTION_INFO *func_index_info = NULL; +// int is_partition = DB_NOT_PARTITIONED_CLASS; + +// error = sm_partitioned_class_type (obj, &is_partition, NULL, NULL); +// if (error != NO_ERROR) +// { +// return error; +// } +// if (is_partition == DB_PARTITION_CLASS) +// { +// er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NOT_ALLOWED_ACCESS_TO_PARTITION, 0); +// return ER_NOT_ALLOWED_ACCESS_TO_PARTITION; +// } + +// char *attname_tmp = NULL; +// if (do_histogram != DO_HISTOGRAM_CREATE) +// { +// nnames = 0; +// attnames = &attname_tmp; +// attnames[0] = NULL; +// } +// else +// { +// assert (histogram_info); + +// nnames = pt_length_of_list (histogram_info->target_columns); +// attnames = (char **) malloc ((nnames + 1) * sizeof (const char *)); +// already_exists = (bool *) malloc ((nnames + 1) * sizeof (bool)); + +// if (attnames == NULL) +// { +// er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (nnames + 1) * sizeof (const char *)); +// return ER_OUT_OF_VIRTUAL_MEMORY; +// } + +// int i = 0; +// const PT_NODE *c = histogram_info->target_columns; +// while (c != NULL) +// { +// /* column name node */ +// attnames[i] = (char *) c->info.name.original; +// i++; +// c = c->next; +// } +// attnames[i] = NULL; +// } + +// // TODO: already exists + +// if (do_histogram == DO_HISTOGRAM_CREATE) +// { +// if (histogram_info->where) +// { +// PARSER_VARCHAR *filter_expr = NULL; +// unsigned int save_custom; + +// /* free at parser_free_parser */ +// /* make sure paren_type is 0 so parenthesis are not printed */ +// idx_info->where->info.expr.paren_type = 0; +// save_custom = parser->custom_print; +// parser->custom_print |= PT_CHARSET_COLLATE_FULL; + +// filter_expr = pt_print_bytes ((PARSER_CONTEXT *) parser, (PT_NODE *) idx_info->where); +// parser->custom_print = save_custom; +// if (filter_expr) +// { +// pred_index_info.pred_string = (char *) filter_expr->bytes; +// if (strlen (pred_index_info.pred_string) > MAX_FILTER_PREDICATE_STRING_LENGTH) +// { +// error = ER_SM_INVALID_FILTER_PREDICATE_LENGTH; +// PT_ERRORmf ((PARSER_CONTEXT *) parser, idx_info->where, MSGCAT_SET_ERROR, +// -(ER_SM_INVALID_FILTER_PREDICATE_LENGTH), MAX_FILTER_PREDICATE_STRING_LENGTH); +// goto end; +// } +// } + +// pt_enter_packing_buf (); +// free_packing_buff = true; +// filter_predicate = +// pt_to_pred_with_context ((PARSER_CONTEXT *) parser, (PT_NODE *) idx_info->where, +// (PT_NODE *) idx_info->indexed_class); +// if (filter_predicate) +// { +// error = +// xts_map_filter_pred_to_stream (filter_predicate, &(pred_index_info.pred_stream), +// &(pred_index_info.pred_stream_size)); +// if (error != NO_ERROR) +// { +// PT_ERRORm ((PARSER_CONTEXT *) parser, idx_info->where, MSGCAT_SET_PARSER_RUNTIME, +// MSGCAT_RUNTIME_RESOURCES_EXHAUSTED); +// goto end; +// } +// pred_index_info.att_ids = filter_predicate->attrids_pred; +// pred_index_info.num_attrs = filter_predicate->num_attrs_pred; +// p_pred_index_info = &pred_index_info; +// } +// else +// { +// assert (er_errid () != NO_ERROR); +// error = er_errid (); +// goto end; +// } +// } + +// error = sm_create_histogram (obj, (const char **) attnames, histogram_info->bucket_count, histogram_info->histogram_type); +// } +// else +// { +// assert (do_histogram == DO_HISTOGRAM_DROP); +// error = sm_drop_histogram (obj, (const char **) attnames); +// } + +// end: + +// /* free function index info */ +// if (func_index_info) +// { +// sm_free_function_index_info (func_index_info); +// db_ws_free (func_index_info); +// func_index_info = NULL; +// } + +// /* free 'stream' that is allocated inside of xts_map_xasl_to_stream() */ +// if (pred_index_info.pred_stream) +// { +// free_and_init (pred_index_info.pred_stream); +// } + +// if (free_packing_buff) +// { +// /* mark the end of another level of xasl packing */ +// pt_exit_packing_buf (); +// } + +// if (attnames != &attname_tmp) +// { +// free_and_init (attnames); +// } +// free_and_init (asc_desc); +// if (attrs_prefix_length) +// { +// free_and_init (attrs_prefix_length); +// } + +// if (cname != NULL) +// { +// free_and_init (cname); +// } + +// return error; +} + + +/** + * do_create_histogram() - Creates a histogram on a class. + * return: Error code if it fails + * parser(in): Parser context + * statement(in): Parse tree of a create histogram statement + */ +int +do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) +{ + PT_NODE *cls; + DB_OBJECT *obj; + const char *index_name = NULL; + int error = NO_ERROR; + + CHECK_MODIFICATION_ERROR (); + + /* class should be already available */ + assert (statement->info.histogram.target_table_spec); + + cls = statement->info.histogram.target_table_spec->info.spec.entity_name; + + obj = db_find_class (cls->info.name.original); + if (obj == NULL) + { + assert (er_errid () != NO_ERROR); + return er_errid (); + } + + //error = create_or_drop_histogram_helper (parser, &statement->info.histogram); + return error; +} + /* * do_create_partition() - Creates partitions * return: Error code if partitions are not created diff --git a/src/query/execute_statement.c b/src/query/execute_statement.c index 47c53b3295a..8f42e086788 100644 --- a/src/query/execute_statement.c +++ b/src/query/execute_statement.c @@ -20,6 +20,7 @@ * execute_statement.c - functions to do execute */ +#include "parse_tree.h" #ident "$Id$" #include "config.h" @@ -3158,6 +3159,7 @@ do_statement (PARSER_CONTEXT * parser, PT_NODE * statement) case PT_CREATE_SERIAL: case PT_CREATE_TRIGGER: case PT_CREATE_USER: + case PT_CREATE_HISTOGRAM: case PT_ALTER: case PT_ALTER_INDEX: case PT_ALTER_SERIAL: @@ -3235,6 +3237,10 @@ do_statement (PARSER_CONTEXT * parser, PT_NODE * statement) error = do_create_index (parser, statement); break; + case PT_CREATE_HISTOGRAM: + error = do_create_histogram (parser, statement); + break; + case PT_EVALUATE: error = do_evaluate (parser, statement); break; @@ -3855,6 +3861,7 @@ do_execute_statement (PARSER_CONTEXT * parser, PT_NODE * statement) case PT_CREATE_SERIAL: case PT_CREATE_TRIGGER: case PT_CREATE_USER: + case PT_CREATE_HISTOGRAM: case PT_ALTER: case PT_ALTER_INDEX: case PT_ALTER_SERIAL: @@ -3928,6 +3935,9 @@ do_execute_statement (PARSER_CONTEXT * parser, PT_NODE * statement) case PT_CREATE_USER: err = do_create_user (parser, statement); break; + case PT_CREATE_HISTOGRAM: + err = do_create_histogram (parser, statement); + break; case PT_ALTER: /* err = do_alter(parser, statement); */ /* execute internal statements before and after do_alter() */ diff --git a/src/query/execute_statement.h b/src/query/execute_statement.h index 31c14f4de2f..50c546ee8fd 100644 --- a/src/query/execute_statement.h +++ b/src/query/execute_statement.h @@ -119,6 +119,8 @@ extern int do_delete (PARSER_CONTEXT * parser, PT_NODE * statement); extern int do_prepare_delete (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * parent); extern int do_execute_delete (PARSER_CONTEXT * parser, PT_NODE * statement); +extern int do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement); + extern int do_drop (PARSER_CONTEXT * parser, PT_NODE * statement); extern int do_drop_variable (PARSER_CONTEXT * parser, PT_NODE * statement); From c8f77000d3f3e5895b18e4f21dfb1bfc16e24788 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 4 Sep 2025 18:17:14 +0900 Subject: [PATCH 005/112] =?UTF-8?q?(feature)=20histogram=20spec=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20schema=20adder=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/schema_manager.c | 9 + src/object/schema_manager.h | 2 + src/object/schema_system_catalog_install.cpp | 14 +- ...hema_system_catalog_install_query_spec.cpp | 6 +- src/query/execute_schema.c | 205 ++++-------------- 5 files changed, 62 insertions(+), 174 deletions(-) diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index b8f5152a839..6d7acb9c06e 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -15487,6 +15487,15 @@ sm_save_constraint_info (SM_CONSTRAINT_INFO ** save_info, const SM_CLASS_CONSTRA return error_code; } + +int +sm_add_histogram (const DB_OBJECT * obj, int class_of, const char *attr_name, int data_type, int histogram_type, + int bucket_count) +{ + return NO_ERROR; +} + + /* * sm_save_function_index_info() - Saves the information necessary to recreate * a function index constraint diff --git a/src/object/schema_manager.h b/src/object/schema_manager.h index d03a3213048..f633ddc790b 100644 --- a/src/object/schema_manager.h +++ b/src/object/schema_manager.h @@ -112,6 +112,8 @@ extern int sm_add_constraint (MOP classop, DB_CONSTRAINT_TYPE constraint_type, c const char **att_names, const int *asc_desc, const int *attrs_prefix_length, int class_attributes, SM_PREDICATE_INFO * predicate_info, SM_FUNCTION_INFO * fi_info, const char *comment, SM_INDEX_STATUS index_status); +extern int sm_add_histogram (const DB_OBJECT * obj, int class_of, const char *attr_name, int data_type, + int histogram_type, int bucket_count); extern int sm_drop_constraint (MOP classop, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, bool class_attributes, bool mysql_index_name); extern int sm_drop_index (MOP classop, const char *constraint_name); diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index 9cdc1caea94..8ae5beb127e 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -1269,15 +1269,15 @@ namespace cubschema // columns { {"class_of", CT_CLASS_NAME}, - {"def_index", "integer"}, + {"key_attr", CT_ATTRIBUTE_NAME}, {"data_type", "integer"}, - {"histogram_type", "varchar(32)"}, + {"histogram_type","integer"}, {"bucket_count", "integer"}, - {"histogram_values", "varchar(2048)"}, + {"histogram_values", "format_varchar (1073741823)"}, }, // constraint { - {DB_CONSTRAINT_INDEX, "", {"class_of", "def_index", nullptr}, false} + {DB_CONSTRAINT_INDEX, "", {"class_of", "key_attr", nullptr}, false} }, // authorization { @@ -2069,11 +2069,11 @@ namespace cubschema // columns { {"class_of", CT_CLASS_NAME}, - {"def_index", "integer"}, + {"key_attr", CT_ATTRIBUTE_NAME}, {"data_type", "integer"}, - {"histogram_type", "varchar(32)"}, + {"histogram_type","integer"}, {"bucket_count", "integer"}, - {"histogram_values", "varchar(2048)"}, + {"histogram_values", "format_varchar (1073741823)"}, // query specs {attribute_kind::QUERY_SPEC, sm_define_view_db_histogram_spec ()} }, diff --git a/src/object/schema_system_catalog_install_query_spec.cpp b/src/object/schema_system_catalog_install_query_spec.cpp index a6fa356a0a0..b4206c27cee 100644 --- a/src/object/schema_system_catalog_install_query_spec.cpp +++ b/src/object/schema_system_catalog_install_query_spec.cpp @@ -1592,9 +1592,9 @@ sm_define_view_db_histogram_spec (void) sprintf (stmt, "SELECT " "[h].[class_of] AS [class_of], " - "[h].[def_index] AS [def_index], " + "[h].[attr_name] AS [attr_name], " "[h].[data_type] AS [data_type], " - "[h].[histogram_type] AS [histogram_type], " + "[h].[histogram_type] AS [histogram_type], " // TODO : integer -> varchar(32) "[h].[bucket_count] AS [bucket_count], " "[h].[histogram_values] AS [histogram_values] " "FROM " @@ -1602,7 +1602,7 @@ sm_define_view_db_histogram_spec (void) "[%s] AS [h] " "ORDER BY " /* Is it possible to remove ORDER BY? */ "[h].[class_of], " - "[h].[def_index]", + "[h].[attr_name]", CT_DB_HISTOGRAM_NAME); // *INDENT-ON* diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 9a9fa2af3dd..6fac41e443f 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3878,169 +3878,46 @@ do_alter_index (PARSER_CONTEXT * parser, const PT_NODE * statement) * histogram_info(in): Histogram information */ static int -create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, PT_HISTOGRAM_INFO * const histogram_info, DO_HISTOGRAM do_histogram) -{ - assert (false); // TODO: implement - return NO_ERROR; -// int error = NO_ERROR; -// int nnames = 0; -// bool *already_exists = NULL; -// char **attnames = NULL; -// char *cname = NULL; -// bool free_packing_buff = false; -// PRED_EXPR_WITH_CONTEXT *filter_predicate = NULL; -// SM_PREDICATE_INFO pred_index_info = { NULL, NULL, 0, NULL, 0 }; -// SM_PREDICATE_INFO *p_pred_index_info = NULL; -// SM_FUNCTION_INFO *func_index_info = NULL; -// int is_partition = DB_NOT_PARTITIONED_CLASS; - -// error = sm_partitioned_class_type (obj, &is_partition, NULL, NULL); -// if (error != NO_ERROR) -// { -// return error; -// } -// if (is_partition == DB_PARTITION_CLASS) -// { -// er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NOT_ALLOWED_ACCESS_TO_PARTITION, 0); -// return ER_NOT_ALLOWED_ACCESS_TO_PARTITION; -// } - -// char *attname_tmp = NULL; -// if (do_histogram != DO_HISTOGRAM_CREATE) -// { -// nnames = 0; -// attnames = &attname_tmp; -// attnames[0] = NULL; -// } -// else -// { -// assert (histogram_info); - -// nnames = pt_length_of_list (histogram_info->target_columns); -// attnames = (char **) malloc ((nnames + 1) * sizeof (const char *)); -// already_exists = (bool *) malloc ((nnames + 1) * sizeof (bool)); - -// if (attnames == NULL) -// { -// er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (nnames + 1) * sizeof (const char *)); -// return ER_OUT_OF_VIRTUAL_MEMORY; -// } - -// int i = 0; -// const PT_NODE *c = histogram_info->target_columns; -// while (c != NULL) -// { -// /* column name node */ -// attnames[i] = (char *) c->info.name.original; -// i++; -// c = c->next; -// } -// attnames[i] = NULL; -// } - -// // TODO: already exists - -// if (do_histogram == DO_HISTOGRAM_CREATE) -// { -// if (histogram_info->where) -// { -// PARSER_VARCHAR *filter_expr = NULL; -// unsigned int save_custom; - -// /* free at parser_free_parser */ -// /* make sure paren_type is 0 so parenthesis are not printed */ -// idx_info->where->info.expr.paren_type = 0; -// save_custom = parser->custom_print; -// parser->custom_print |= PT_CHARSET_COLLATE_FULL; - -// filter_expr = pt_print_bytes ((PARSER_CONTEXT *) parser, (PT_NODE *) idx_info->where); -// parser->custom_print = save_custom; -// if (filter_expr) -// { -// pred_index_info.pred_string = (char *) filter_expr->bytes; -// if (strlen (pred_index_info.pred_string) > MAX_FILTER_PREDICATE_STRING_LENGTH) -// { -// error = ER_SM_INVALID_FILTER_PREDICATE_LENGTH; -// PT_ERRORmf ((PARSER_CONTEXT *) parser, idx_info->where, MSGCAT_SET_ERROR, -// -(ER_SM_INVALID_FILTER_PREDICATE_LENGTH), MAX_FILTER_PREDICATE_STRING_LENGTH); -// goto end; -// } -// } - -// pt_enter_packing_buf (); -// free_packing_buff = true; -// filter_predicate = -// pt_to_pred_with_context ((PARSER_CONTEXT *) parser, (PT_NODE *) idx_info->where, -// (PT_NODE *) idx_info->indexed_class); -// if (filter_predicate) -// { -// error = -// xts_map_filter_pred_to_stream (filter_predicate, &(pred_index_info.pred_stream), -// &(pred_index_info.pred_stream_size)); -// if (error != NO_ERROR) -// { -// PT_ERRORm ((PARSER_CONTEXT *) parser, idx_info->where, MSGCAT_SET_PARSER_RUNTIME, -// MSGCAT_RUNTIME_RESOURCES_EXHAUSTED); -// goto end; -// } -// pred_index_info.att_ids = filter_predicate->attrids_pred; -// pred_index_info.num_attrs = filter_predicate->num_attrs_pred; -// p_pred_index_info = &pred_index_info; -// } -// else -// { -// assert (er_errid () != NO_ERROR); -// error = er_errid (); -// goto end; -// } -// } - -// error = sm_create_histogram (obj, (const char **) attnames, histogram_info->bucket_count, histogram_info->histogram_type); -// } -// else -// { -// assert (do_histogram == DO_HISTOGRAM_DROP); -// error = sm_drop_histogram (obj, (const char **) attnames); -// } - -// end: - -// /* free function index info */ -// if (func_index_info) -// { -// sm_free_function_index_info (func_index_info); -// db_ws_free (func_index_info); -// func_index_info = NULL; -// } - -// /* free 'stream' that is allocated inside of xts_map_xasl_to_stream() */ -// if (pred_index_info.pred_stream) -// { -// free_and_init (pred_index_info.pred_stream); -// } - -// if (free_packing_buff) -// { -// /* mark the end of another level of xasl packing */ -// pt_exit_packing_buf (); -// } - -// if (attnames != &attname_tmp) -// { -// free_and_init (attnames); -// } -// free_and_init (asc_desc); -// if (attrs_prefix_length) -// { -// free_and_init (attrs_prefix_length); -// } - -// if (cname != NULL) -// { -// free_and_init (cname); -// } - -// return error; +create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, + PT_HISTOGRAM_INFO * const histogram_info, DO_HISTOGRAM do_histogram) +{ + int error = NO_ERROR; + int class_of, data_type, histogram_type, bucket_count, nnames; + char *attname = NULL; + int is_partition = DB_NOT_PARTITIONED_CLASS; + /* check histogram is allowed on this class */ + error = sm_partitioned_class_type (obj, &is_partition, NULL, NULL); + if (error != NO_ERROR) + { + return error; + } + if (is_partition == DB_PARTITION_CLASS) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NOT_ALLOWED_ACCESS_TO_PARTITION, 0); + return ER_NOT_ALLOWED_ACCESS_TO_PARTITION; + } + + /* fill infos for catlaog table TODO: data_type, */ + nnames = pt_length_of_list (histogram_info->target_columns); + histogram_type = histogram_info->histogram_type; + bucket_count = histogram_info->bucket_count; + + for (int i = 0; i < nnames; i++) + { + attname = (char *) histogram_info->target_columns->info.name.original; + error = sm_add_histogram (obj, class_of, attname, data_type, histogram_type, bucket_count); + if (error != NO_ERROR) + { + return error; + } + } + + if (error != NO_ERROR) + { + return error; + } + + return NO_ERROR; } @@ -4072,7 +3949,7 @@ do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) return er_errid (); } - //error = create_or_drop_histogram_helper (parser, &statement->info.histogram); + error = create_or_drop_histogram_helper (parser, obj, &statement->info.histogram, DO_HISTOGRAM_CREATE); return error; } From 0256f1c333898854765a0f896f5b12eb10dbafc7 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 4 Sep 2025 18:25:53 +0900 Subject: [PATCH 006/112] =?UTF-8?q?(feature)=20histogram=20=EC=BB=AC?= =?UTF-8?q?=EB=9F=BC=20=EC=98=AC=EB=B0=94=EB=A5=B8=20=EB=B0=A9=ED=96=A5?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/schema_system_catalog_install.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index 8ae5beb127e..7fdb7dd11f9 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -1273,11 +1273,11 @@ namespace cubschema {"data_type", "integer"}, {"histogram_type","integer"}, {"bucket_count", "integer"}, - {"histogram_values", "format_varchar (1073741823)"}, + {"histogram_values", format_varchar (1073741823) } }, // constraint { - {DB_CONSTRAINT_INDEX, "", {"class_of", "key_attr", nullptr}, false} + {DB_CONSTRAINT_UNIQUE, "", {"class_of", "key_attr", nullptr}, false} }, // authorization { @@ -2073,8 +2073,7 @@ namespace cubschema {"data_type", "integer"}, {"histogram_type","integer"}, {"bucket_count", "integer"}, - {"histogram_values", "format_varchar (1073741823)"}, - // query specs + {"histogram_values", format_varchar (1024)}, {attribute_kind::QUERY_SPEC, sm_define_view_db_histogram_spec ()} }, // constraint From be8009365266e46ea0dde90ad390b28c19a1f0b2 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 5 Sep 2025 18:04:47 +0900 Subject: [PATCH 007/112] =?UTF-8?q?(feature)=20extra=20schema=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/class_object.c | 7 ++ src/object/class_object.h | 13 ++++ src/object/schema_manager.c | 64 ++++++++++++++++- src/object/schema_manager.h | 3 +- src/object/schema_system_catalog_install.cpp | 3 +- src/object/schema_template.c | 74 ++++++++++++++++++++ src/object/schema_template.h | 4 ++ src/object/transform.c | 19 ++++- src/parser/semantic_check.c | 15 ---- src/query/execute_schema.c | 13 ++-- src/storage/oid.c | 4 +- src/storage/oid.h | 2 +- src/transaction/boot_cl.c | 2 + 13 files changed, 194 insertions(+), 29 deletions(-) diff --git a/src/object/class_object.c b/src/object/class_object.c index ef6febf56d0..fe9a7f063d3 100644 --- a/src/object/class_object.c +++ b/src/object/class_object.c @@ -8299,6 +8299,13 @@ classobj_check_index_exist (SM_CLASS_CONSTRAINT * constraints, char **out_shared return error; } +int +classobj_check_histogram_exist (SM_ATTRIBUTE * attributes, char attr_name) +{ + assert (false); // TODO: implement this + return NO_ERROR; +} + /* * classobj_make_function_index_info() - * return: diff --git a/src/object/class_object.h b/src/object/class_object.h index 896828e9ec2..e446f8220f9 100644 --- a/src/object/class_object.h +++ b/src/object/class_object.h @@ -911,6 +911,18 @@ struct sm_descriptor SM_NAME_SPACE name_space; /* component type */ }; + +/* histogram */ +typedef struct sm_histogram_info SM_HISTOGRAM_INFO; + +struct sm_histogram_info +{ + const char *attr_name; + int data_type; + int histogram_type; + int bucket_count; +}; + /* free_and_init routine */ #define classobj_free_threaded_array_and_init(list, clear) \ do \ @@ -1120,4 +1132,5 @@ extern SM_PARTITION *classobj_copy_partition_info (SM_PARTITION * partition_info extern int classobj_change_constraint_status (DB_SEQ * properties, SM_CLASS_CONSTRAINT * cons, SM_INDEX_STATUS index_status); +extern int classobj_check_histogram_exist (SM_ATTRIBUTE * attributes, const char *attr_name); #endif /* _CLASS_OBJECT_H_ */ diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 6d7acb9c06e..b053403c208 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -83,6 +83,7 @@ #endif /* defined (SUPPRESS_STRLEN_WARNING) */ #define SM_ADD_CONSTRAINT_SAVEPOINT_NAME "aDDcONSTRAINT" +#define SM_ADD_HISTOGRAM_SAVEPOINT_NAME "aDDhISTOGRAM" #define SM_ADD_UNIQUE_CONSTRAINT_SAVEPOINT_NAME "aDDuNIQUEcONSTRAINT" #define SM_DROP_CLASS_MOP_SAVEPOINT_NAME "dELETEcLASSmOP" #define SM_TRUNCATE_SAVEPOINT_NAME "SmtRUnCATE" @@ -3129,6 +3130,7 @@ sm_mark_system_class_for_catalog (void) CT_STORED_PROC_NAME, CT_STORED_PROC_ARGS_NAME, CT_PARTITION_NAME, + CT_DB_HISTOGRAM_NAME, CTV_CLASS_NAME, CTV_SUPER_CLASS_NAME, CTV_VCLASS_NAME, @@ -3148,6 +3150,7 @@ sm_mark_system_class_for_catalog (void) CT_COLLATION_NAME, CT_DB_SERVER_NAME, CTV_DB_SERVER_NAME, + CTV_DB_HISTOGRAM_NAME, NULL }; @@ -4429,7 +4432,7 @@ sm_update_all_catalog_statistics (bool with_fullscan) CT_STORED_PROC_NAME, CT_STORED_PROC_ARGS_NAME, CT_PARTITION_NAME, CT_SERIAL_NAME, CT_USER_NAME, CT_AUTHORIZATION_NAME, CT_TRIGGER_NAME, CT_PASSWORD_NAME, CT_HA_APPLY_INFO_NAME, - CT_DB_SERVER_NAME, NULL + CT_DB_SERVER_NAME, CT_DB_HISTOGRAM_NAME, NULL }; for (i = 0; classes[i] != NULL && error == NO_ERROR; i++) @@ -15489,9 +15492,64 @@ sm_save_constraint_info (SM_CONSTRAINT_INFO ** save_info, const SM_CLASS_CONSTRA int -sm_add_histogram (const DB_OBJECT * obj, int class_of, const char *attr_name, int data_type, int histogram_type, - int bucket_count) +sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogram_type, int bucket_count) { + bool set_savepoint = false; + int error = NO_ERROR; + DB_AUTH auth; + SM_TEMPLATE *def = NULL; + + if (attr_name == NULL) + { + ERROR0 (error, ER_OBJ_INVALID_ARGUMENTS); + return error; + } + + error = tran_system_savepoint (SM_ADD_HISTOGRAM_SAVEPOINT_NAME); + if (error != NO_ERROR) + { + return error; + } + + set_savepoint = true; + def = smt_edit_class_mop (classop, AU_ALTER); + if (def == NULL) + { + ASSERT_ERROR_AND_SET (error); + goto error_exit; + } + + error = smt_check_histogram_exist (def, attr_name); + if (error != NO_ERROR) + { + smt_quit (def); + goto error_exit; + } + +// /* 히스토그램을 카탈로그 클래스에 추가 */ +// error = smt_add_constraint (def, attr_name, data_type, histogram_type, bucket_count); +// if (error != NO_ERROR) +// { +// smt_quit (def); +// goto error_exit; +// } + +// /* 통계 업데이트 | 히스토그램 정보 업데이트 하기 */ +// error = sm_update_statistics_with_modify_histogram (newmop, STATS_WITH_SAMPlING); +// if (error != NO_ERROR) +// { +// smt_quit (def); +// goto error_exit; +// } + + return error; + +error_exit: + if (set_savepoint && error != ER_TM_SERVER_DOWN_UNILATERALLY_ABORTED && error != ER_LK_UNILATERALLY_ABORTED) + { + (void) tran_abort_upto_system_savepoint (SM_ADD_HISTOGRAM_SAVEPOINT_NAME); + } + return NO_ERROR; } diff --git a/src/object/schema_manager.h b/src/object/schema_manager.h index f633ddc790b..6454b9f6b27 100644 --- a/src/object/schema_manager.h +++ b/src/object/schema_manager.h @@ -112,8 +112,7 @@ extern int sm_add_constraint (MOP classop, DB_CONSTRAINT_TYPE constraint_type, c const char **att_names, const int *asc_desc, const int *attrs_prefix_length, int class_attributes, SM_PREDICATE_INFO * predicate_info, SM_FUNCTION_INFO * fi_info, const char *comment, SM_INDEX_STATUS index_status); -extern int sm_add_histogram (const DB_OBJECT * obj, int class_of, const char *attr_name, int data_type, - int histogram_type, int bucket_count); +extern int sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogram_type, int bucket_count); extern int sm_drop_constraint (MOP classop, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, bool class_attributes, bool mysql_index_name); extern int sm_drop_index (MOP classop, const char *constraint_name); diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index 7fdb7dd11f9..a02d21f7e6c 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -397,7 +397,8 @@ namespace cubschema {"query_specs", format_sequence (CT_QUERYSPEC_NAME)}, {"indexes", format_sequence (CT_INDEX_NAME)}, {"comment", format_varchar (2048)}, - {"partition", format_sequence (CT_PARTITION_NAME)} + {"partition", format_sequence (CT_PARTITION_NAME)}, + {"histograms", format_sequence (CT_DB_HISTOGRAM_NAME)} }, // constraints { diff --git a/src/object/schema_template.c b/src/object/schema_template.c index a32278182f4..d9db3dae49e 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -1963,6 +1963,80 @@ smt_check_index_exist (SM_TEMPLATE * template_, char **out_shared_cons_name, DB_ return error; } + +int +smt_check_histogram_exist (SM_TEMPLATE * template_, const char *attr_name) +{ + int error = NO_ERROR; + assert (false); // TODO: implement this 여기서 히스토그램 관련 모든 컬럼들을 페치해오고 아래 함수에서 뒤진다. + + SM_CLASS *class_; + SM_CLASS_CONSTRAINT *check_cons; + SM_CLASS_CONSTRAINT *temp_cons = NULL; + +// if (template_->op != NULL) +// { +// error = au_fetch_class (template_->op, &class_, AU_FETCH_READ, AU_INDEX); +// if (error != NO_ERROR) +// { +// return error; +// } + +// check_cons = class_->constraints; +// } +// else +// { +// error = classobj_make_class_constraints (template_->properties, template_->attributes, &check_cons); +// if (error != NO_ERROR) +// { +// return error; +// } + +// temp_cons = check_cons; +// } + + + error = classobj_check_histogram_exist (template_->attributes, attr_name); + + return error; +} + +int +smt_add_histogram (SM_TEMPLATE * template_, const char *attr_name, int data_type, int histogram_type, int bucket_count) +{ + int error = NO_ERROR; + assert (false); // TODO: implement this 여기서 히스토그램 관련 모든 컬럼들을 페치해오고 아래 함수에서 뒤진다. + SM_CLASS *class_; + SM_CLASS_CONSTRAINT *check_cons; + SM_CLASS_CONSTRAINT *temp_cons = NULL; + +// if (template_->op != NULL) +// { +// error = au_fetch_class (template_->op, &class_, AU_FETCH_READ, AU_INDEX); +// if (error != NO_ERROR) +// { +// return error; +// } + +// check_cons = class_->constraints; +// } +// else +// { +// error = classobj_make_class_constraints (template_->properties, template_->attributes, &check_cons); +// if (error != NO_ERROR) +// { +// return error; +// } + +// temp_cons = check_cons; +// } + + + error = classobj_check_histogram_exist (template_->attributes, attr_name); + + return error; +} + /* * smt_add_constraint() - Adds the integrity constraint flags for an attribute. * return: NO_ERROR on success, non-zero for ERROR diff --git a/src/object/schema_template.h b/src/object/schema_template.h index 45be1e62f47..c6381badaa1 100644 --- a/src/object/schema_template.h +++ b/src/object/schema_template.h @@ -84,6 +84,9 @@ extern int smt_add_constraint (SM_TEMPLATE * template_, DB_CONSTRAINT_TYPE const int class_attribute, SM_FOREIGN_KEY_INFO * fk_info, SM_PREDICATE_INFO * filter_index, SM_FUNCTION_INFO * function_index, const char *comment, SM_INDEX_STATUS index_status); +extern int smt_add_histogram (SM_TEMPLATE * template_, const char *attr_name, int data_type, int histogram_type, + int bucket_count); + extern int smt_drop_constraint (SM_TEMPLATE * template_, const char **att_names, const char *constraint_name, int class_attribute, SM_ATTRIBUTE_FLAG constraint); @@ -166,6 +169,7 @@ extern int smt_check_index_exist (SM_TEMPLATE * template_, char **out_shared_con DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, const int *asc_desc, const SM_PREDICATE_INFO * filter_index, const SM_FUNCTION_INFO * function_index); +extern int smt_check_histogram_exist (SM_TEMPLATE * template_, const char *attr_name); #if defined(ENABLE_UNUSED_FUNCTION) extern void smt_downcase_all_class_info (void); diff --git a/src/object/transform.c b/src/object/transform.c index 6a2169c5e02..d1bd29a08e7 100644 --- a/src/object/transform.c +++ b/src/object/transform.c @@ -306,7 +306,8 @@ static CT_ATTR ct_class_atts[] = { {"query_specs", NULL_ATTRID, DB_TYPE_SEQUENCE}, {"indexes", NULL_ATTRID, DB_TYPE_SEQUENCE}, {"comment", NULL_ATTRID, DB_TYPE_VARCHAR}, - {"partition", NULL_ATTRID, DB_TYPE_SEQUENCE} + {"partition", NULL_ATTRID, DB_TYPE_SEQUENCE}, + {"histograms", NULL_ATTRID, DB_TYPE_SEQUENCE} }; static CT_ATTR ct_attribute_atts[] = { @@ -416,6 +417,14 @@ static CT_ATTR ct_partition_atts[] = { {"comment", NULL_ATTRID, DB_TYPE_VARCHAR} }; +static CT_ATTR ct_histogram_atts[] = { + {"class_of", NULL_ATTRID, DB_TYPE_OBJECT}, + {"attr_name", NULL_ATTRID, DB_TYPE_VARCHAR}, + {"data_type", NULL_ATTRID, DB_TYPE_INTEGER}, + {"histogram_type", NULL_ATTRID, DB_TYPE_INTEGER}, + {"bucket_count", NULL_ATTRID, DB_TYPE_INTEGER} +}; + CT_CLASS ct_Class = { CT_CLASS_NAME, OID_INITIALIZER, @@ -507,6 +516,13 @@ CT_CLASS ct_Indexkey = { ct_indexkey_atts }; +CT_CLASS ct_Histogram = { + CT_DB_HISTOGRAM_NAME, + OID_INITIALIZER, + (sizeof (ct_histogram_atts) / sizeof (ct_histogram_atts[0])), + ct_histogram_atts +}; + CT_CLASS *ct_Classes[] = { &ct_Class, &ct_Attribute, @@ -519,6 +535,7 @@ CT_CLASS *ct_Classes[] = { &ct_Index, &ct_Indexkey, &ct_Partition, + &ct_Histogram, NULL }; diff --git a/src/parser/semantic_check.c b/src/parser/semantic_check.c index 4135c83072f..2b26e3e7afb 100644 --- a/src/parser/semantic_check.c +++ b/src/parser/semantic_check.c @@ -9169,21 +9169,6 @@ pt_check_create_histogram (PARSER_CONTEXT * parser, PT_NODE * node) return; } - /* Check if the columns are valid. We only allow attribute names. we're only interested in the node type */ - for (col = node->info.histogram.target_columns; col != NULL; col = col->next) - { - if (col_expr->node_type == PT_NAME) - { - /* make sure this is not a parameter */ - if (col_expr->info.name.meta_class != PT_NORMAL) - { - PT_ERRORmf (parser, col_expr, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INVALID_INDEX_COLUMN, - pt_short_print (parser, col_expr)); - return; - } - } - } - name->info.name.db_object = db_obj; /* check that histogram already exists */ diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 6fac41e443f..da0cb39b6ec 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3882,8 +3882,9 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, PT_HISTOGRAM_INFO * const histogram_info, DO_HISTOGRAM do_histogram) { int error = NO_ERROR; - int class_of, data_type, histogram_type, bucket_count, nnames; + int data_type, histogram_type, bucket_count, nnames = 0; char *attname = NULL; + PT_NODE *cur_column = NULL; int is_partition = DB_NOT_PARTITIONED_CLASS; /* check histogram is allowed on this class */ error = sm_partitioned_class_type (obj, &is_partition, NULL, NULL); @@ -3897,19 +3898,21 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, return ER_NOT_ALLOWED_ACCESS_TO_PARTITION; } - /* fill infos for catlaog table TODO: data_type, */ + /* fill infos for catlaog table TODO: data_type, duplication check */ nnames = pt_length_of_list (histogram_info->target_columns); histogram_type = histogram_info->histogram_type; bucket_count = histogram_info->bucket_count; - + cur_column = histogram_info->target_columns; for (int i = 0; i < nnames; i++) { - attname = (char *) histogram_info->target_columns->info.name.original; - error = sm_add_histogram (obj, class_of, attname, data_type, histogram_type, bucket_count); + attname = (char *) cur_column->info.name.original; + data_type = cur_column->type_enum; + error = sm_add_histogram (obj, attname, data_type, histogram_type, bucket_count); if (error != NO_ERROR) { return error; } + cur_column = cur_column->next; } if (error != NO_ERROR) diff --git a/src/storage/oid.c b/src/storage/oid.c index 4a8ab80a126..13cb6bae499 100644 --- a/src/storage/oid.c +++ b/src/storage/oid.c @@ -67,7 +67,7 @@ static OID oid_Authorizations_class = { 0, 0, 0 }; static OID oid_DB_root_class = { 0, 0, 0 }; static OID oid_DBServer_class = { 0, 0, 0 }; static OID oid_Synonym_class = { 0, 0, 0 }; - +static OID oid_DB_histogram_class = { 0, 0, 0 }; static OID oid_Rep_Read_Tran = { 0, (short int) 0x8000, 0 }; const OID oid_Null_oid = { NULL_PAGEID, NULL_SLOTID, NULL_VOLID }; @@ -82,6 +82,7 @@ OID *oid_Serial_class_oid = &oid_Serial_class; OID *oid_Partition_class_oid = &oid_Partition_class; OID *oid_User_class_oid = &oid_User_class; OID *oid_Sp_code_class_oid = &oid_Stored_proc_code_class; +OID *oid_DB_histogram_class_oid = &oid_DB_histogram_class; const OID_CACHE_ENTRY oid_Cache[OID_CACHE_SIZE] = { {&oid_Root_class, NULL}, /* Root class is not identifiable by a name */ @@ -113,6 +114,7 @@ const OID_CACHE_ENTRY oid_Cache[OID_CACHE_SIZE] = { {&oid_DBServer_class, CT_DB_SERVER_NAME}, {&oid_Synonym_class, CT_SYNONYM_NAME}, {&oid_Stored_proc_code_class, CT_STORED_PROC_CODE_NAME}, + {&oid_DB_histogram_class, CT_DB_HISTOGRAM_NAME} }; /* diff --git a/src/storage/oid.h b/src/storage/oid.h index 5d4acb935c9..09cd4798422 100644 --- a/src/storage/oid.h +++ b/src/storage/oid.h @@ -202,7 +202,7 @@ enum OID_CACHE_DB_SERVER_CLASS_ID, OID_CACHE_SYNONYM_CLASS_ID, OID_CACHE_STORED_PROC_CODE_CLASS_ID, - + OID_CACHE_DB_HISTOGRAM_CLASS_ID, OID_CACHE_SIZE }; diff --git a/src/transaction/boot_cl.c b/src/transaction/boot_cl.c index c3aea6c16c0..993f8b8f85b 100644 --- a/src/transaction/boot_cl.c +++ b/src/transaction/boot_cl.c @@ -1850,6 +1850,7 @@ boot_destroy_catalog_classes (void) CT_PARTITION_NAME, CT_STORED_PROC_NAME, CT_STORED_PROC_ARGS_NAME, + CT_DB_HISTOGRAM_NAME, CTV_CLASS_NAME, CTV_SUPER_CLASS_NAME, CTV_VCLASS_NAME, @@ -1871,6 +1872,7 @@ boot_destroy_catalog_classes (void) CTV_DB_SERVER_NAME, CT_SYNONYM_NAME, CTV_SYNONYM_NAME, + CTV_DB_HISTOGRAM_NAME, NULL }; From f908a0478cb2c330af8ca6371f6f5242ed110bfa Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 5 Sep 2025 18:42:17 +0900 Subject: [PATCH 008/112] =?UTF-8?q?(feature)=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80=20=ED=83=80=EC=9E=85=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=ED=9B=84=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/communication/network_sr.c | 9 --------- src/compat/dbi_compat.h | 1 + src/executables/csql_result.c | 2 ++ src/transaction/log_applier.c | 3 +++ 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/communication/network_sr.c b/src/communication/network_sr.c index a03783dad2c..9320f6c2857 100644 --- a/src/communication/network_sr.c +++ b/src/communication/network_sr.c @@ -453,15 +453,6 @@ net_server_init (void) req_p->action_attribute = (CHECK_DB_MODIFICATION | IN_TRANSACTION); req_p->processing_function = sqst_update_statistics; -// /* TODO: histogram */ -// req_p = &net_Requests[NET_SERVER_CT_GET_HISTOGRAM]; -// req_p->action_attribute = IN_TRANSACTION; -// req_p->processing_function = sct_get_histogram; - -// req_p = &net_Requests[NET_SERVER_CT_UPDATE_HISTOGRAM]; -// req_p->action_attribute = (CHECK_DB_MODIFICATION | IN_TRANSACTION); -// req_p->processing_function = sct_update_histogram; - /* query manager */ req_p = &net_Requests[NET_SERVER_QM_QUERY_PREPARE]; req_p->action_attribute = IN_TRANSACTION; diff --git a/src/compat/dbi_compat.h b/src/compat/dbi_compat.h index babbea9497b..70a35663e39 100644 --- a/src/compat/dbi_compat.h +++ b/src/compat/dbi_compat.h @@ -63,6 +63,7 @@ extern "C" #define SQLX_CMD_REGISTER_DATABASE CUBRID_STMT_REGISTER_DATABASE #define SQLX_CMD_CREATE_CLASS CUBRID_STMT_CREATE_CLASS #define SQLX_CMD_CREATE_INDEX CUBRID_STMT_CREATE_INDEX +#define SQLX_CMD_CREATE_HISTOGRAM CUBRID_STMT_CREATE_HISTOGRAM #define SQLX_CMD_CREATE_TRIGGER CUBRID_STMT_CREATE_TRIGGER #define SQLX_CMD_CREATE_SERIAL CUBRID_STMT_CREATE_SERIAL #define SQLX_CMD_DROP_DATABASE CUBRID_STMT_DROP_DATABASE diff --git a/src/executables/csql_result.c b/src/executables/csql_result.c index da13ff77437..d022358fa1c 100644 --- a/src/executables/csql_result.c +++ b/src/executables/csql_result.c @@ -109,6 +109,8 @@ static CSQL_CMD_STRING_TABLE csql_Cmd_string_table[] = { {CUBRID_STMT_ROLLBACK_WORK, "ROLLBACK"}, {CUBRID_STMT_GRANT, "GRANT"}, {CUBRID_STMT_REVOKE, "REVOKE"}, + {CUBRID_STMT_CREATE_HISTOGRAM, "CREATE HISTOGRAM"}, + //{CUBRID_STMT_DROP_HISTOGRAM, "DROP HISTOGRAM"}, TODO {CUBRID_STMT_CREATE_USER, "CREATE USER"}, {CUBRID_STMT_DROP_USER, "DROP USER"}, {CUBRID_STMT_ALTER_USER, "ALTER USER"}, diff --git a/src/transaction/log_applier.c b/src/transaction/log_applier.c index 92b39c27963..c26aacc8494 100644 --- a/src/transaction/log_applier.c +++ b/src/transaction/log_applier.c @@ -5526,6 +5526,9 @@ la_apply_statement_log (LA_ITEM * item) case CUBRID_STMT_ALTER_SERIAL: case CUBRID_STMT_DROP_SERIAL: + case CUBRID_STMT_CREATE_HISTOGRAM: + //case CUBRID_STMT_DROP_HISTOGRAM: + case CUBRID_STMT_DROP_DATABASE: case CUBRID_STMT_CREATE_STORED_PROCEDURE: From 35dd1bd187161d4fddbc813bdb2d0678e386050a Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 11 Sep 2025 19:29:23 +0900 Subject: [PATCH 009/112] =?UTF-8?q?(bugfix)=20schema=20executor=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - histogram 관련 오류 수정 (db_class fetch 방법 관련) --- src/object/schema_manager.c | 24 ++- src/object/schema_system_catalog_install.cpp | 4 +- ...hema_system_catalog_install_query_spec.cpp | 4 +- src/object/schema_template.c | 170 ++++++++++++------ src/object/schema_template.h | 5 +- src/object/transform.c | 2 +- src/query/execute_schema.c | 9 +- 7 files changed, 138 insertions(+), 80 deletions(-) diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index b053403c208..5eb1ea6ad29 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -15497,7 +15497,8 @@ sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogr bool set_savepoint = false; int error = NO_ERROR; DB_AUTH auth; - SM_TEMPLATE *def = NULL; + SM_CLASS *class_ = NULL; + DB_OBJECT *db_class = NULL; if (attr_name == NULL) { @@ -15512,27 +15513,23 @@ sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogr } set_savepoint = true; - def = smt_edit_class_mop (classop, AU_ALTER); - if (def == NULL) + error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT); + if (error != NO_ERROR) { - ASSERT_ERROR_AND_SET (error); goto error_exit; } - error = smt_check_histogram_exist (def, attr_name); + error = smt_check_histogram_exist (classop, attr_name); if (error != NO_ERROR) { - smt_quit (def); goto error_exit; } -// /* 히스토그램을 카탈로그 클래스에 추가 */ -// error = smt_add_constraint (def, attr_name, data_type, histogram_type, bucket_count); -// if (error != NO_ERROR) -// { -// smt_quit (def); -// goto error_exit; -// } + error = smt_add_histogram (classop, attr_name, data_type, histogram_type, bucket_count); + if (error != NO_ERROR) + { + goto error_exit; + } // /* 통계 업데이트 | 히스토그램 정보 업데이트 하기 */ // error = sm_update_statistics_with_modify_histogram (newmop, STATS_WITH_SAMPlING); @@ -15541,7 +15538,6 @@ sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogr // smt_quit (def); // goto error_exit; // } - return error; error_exit: diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index a02d21f7e6c..b007210f7e5 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -1270,7 +1270,7 @@ namespace cubschema // columns { {"class_of", CT_CLASS_NAME}, - {"key_attr", CT_ATTRIBUTE_NAME}, + {"key_attr", format_varchar (255)}, {"data_type", "integer"}, {"histogram_type","integer"}, {"bucket_count", "integer"}, @@ -2070,7 +2070,7 @@ namespace cubschema // columns { {"class_of", CT_CLASS_NAME}, - {"key_attr", CT_ATTRIBUTE_NAME}, + {"key_attr", format_varchar (255)}, {"data_type", "integer"}, {"histogram_type","integer"}, {"bucket_count", "integer"}, diff --git a/src/object/schema_system_catalog_install_query_spec.cpp b/src/object/schema_system_catalog_install_query_spec.cpp index b4206c27cee..df4566fc216 100644 --- a/src/object/schema_system_catalog_install_query_spec.cpp +++ b/src/object/schema_system_catalog_install_query_spec.cpp @@ -1592,7 +1592,7 @@ sm_define_view_db_histogram_spec (void) sprintf (stmt, "SELECT " "[h].[class_of] AS [class_of], " - "[h].[attr_name] AS [attr_name], " + "[h].[key_attr] AS [key_attr], " "[h].[data_type] AS [data_type], " "[h].[histogram_type] AS [histogram_type], " // TODO : integer -> varchar(32) "[h].[bucket_count] AS [bucket_count], " @@ -1602,7 +1602,7 @@ sm_define_view_db_histogram_spec (void) "[%s] AS [h] " "ORDER BY " /* Is it possible to remove ORDER BY? */ "[h].[class_of], " - "[h].[attr_name]", + "[h].[key_attr]", CT_DB_HISTOGRAM_NAME); // *INDENT-ON* diff --git a/src/object/schema_template.c b/src/object/schema_template.c index d9db3dae49e..41f1bede942 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -1965,75 +1965,135 @@ smt_check_index_exist (SM_TEMPLATE * template_, char **out_shared_cons_name, DB_ int -smt_check_histogram_exist (SM_TEMPLATE * template_, const char *attr_name) +smt_check_histogram_exist (MOP classop, const char *attr_name) { int error = NO_ERROR; - assert (false); // TODO: implement this 여기서 히스토그램 관련 모든 컬럼들을 페치해오고 아래 함수에서 뒤진다. - - SM_CLASS *class_; - SM_CLASS_CONSTRAINT *check_cons; - SM_CLASS_CONSTRAINT *temp_cons = NULL; - -// if (template_->op != NULL) -// { -// error = au_fetch_class (template_->op, &class_, AU_FETCH_READ, AU_INDEX); -// if (error != NO_ERROR) -// { -// return error; -// } - -// check_cons = class_->constraints; -// } -// else -// { -// error = classobj_make_class_constraints (template_->properties, template_->attributes, &check_cons); -// if (error != NO_ERROR) -// { -// return error; -// } - -// temp_cons = check_cons; -// } + DB_OBJECT *histogram_class, *histogram_obj = NULL; + DB_VALUE value[2]; + DB_VALUE *value_ptrs[2] = { &value[0], &value[1] }; + const char *search_attrs[2] = { "class_of", "key_attr" }; + histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); + if (histogram_class == NULL) + { + error = ER_QPROC_DB_SERIAL_NOT_FOUND; //TODO + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + goto end; + } - error = classobj_check_histogram_exist (template_->attributes, attr_name); + /* class_of, key_attr */ + db_make_object (&value[0], classop); + db_make_string (&value[1], attr_name); + histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_READ); + if (histogram_obj != NULL) + { + error = ER_QPROC_DB_SERIAL_NOT_FOUND; //TODO + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + goto end; + } +end: return error; } int -smt_add_histogram (SM_TEMPLATE * template_, const char *attr_name, int data_type, int histogram_type, int bucket_count) +smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histogram_type, int bucket_count) { - int error = NO_ERROR; - assert (false); // TODO: implement this 여기서 히스토그램 관련 모든 컬럼들을 페치해오고 아래 함수에서 뒤진다. - SM_CLASS *class_; - SM_CLASS_CONSTRAINT *check_cons; - SM_CLASS_CONSTRAINT *temp_cons = NULL; - -// if (template_->op != NULL) -// { -// error = au_fetch_class (template_->op, &class_, AU_FETCH_READ, AU_INDEX); -// if (error != NO_ERROR) -// { -// return error; -// } - -// check_cons = class_->constraints; -// } -// else -// { -// error = classobj_make_class_constraints (template_->properties, template_->attributes, &check_cons); -// if (error != NO_ERROR) -// { -// return error; -// } + int au_save, error = NO_ERROR; + bool au_disable_flag = false; + DB_OBJECT *ret_obj = NULL, *histogram_class = NULL, *histogram_object = NULL; + DB_VALUE value; + MOP class_of; + DB_OTMPL *obj_tmpl = NULL; + db_make_null (&value); + + /* temporarily disable authorization to access db_serial class */ + AU_DISABLE (au_save); + au_disable_flag = true;; + + histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); + if (histogram_class == NULL) + { + error = ER_QPROC_DB_SERIAL_NOT_FOUND; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + goto end; + } -// temp_cons = check_cons; -// } + obj_tmpl = dbt_create_object_internal ((MOP) histogram_class); + if (obj_tmpl == NULL) + { + error = er_errid (); + goto end; + } - error = classobj_check_histogram_exist (template_->attributes, attr_name); + db_make_object (&value, classop); + error = dbt_put_internal (obj_tmpl, "class_of", &value); + pr_clear_value (&value); + if (error != NO_ERROR) + { + assert (false); + goto end; + } + /* key_attr */ + db_make_string (&value, attr_name); + error = dbt_put_internal (obj_tmpl, "key_attr", &value); + pr_clear_value (&value); + if (error != NO_ERROR) + { + assert (false); + goto end; + } + /* data_type */ + db_make_int (&value, data_type); + error = dbt_put_internal (obj_tmpl, "data_type", &value); + pr_clear_value (&value); + if (error != NO_ERROR) + { + goto end; + } + /* histogram_type */ + db_make_int (&value, histogram_type); + error = dbt_put_internal (obj_tmpl, "histogram_type", &value); + pr_clear_value (&value); + if (error != NO_ERROR) + { + goto end; + } + /* bucket_count */ + db_make_int (&value, bucket_count); + error = dbt_put_internal (obj_tmpl, "bucket_count", &value); + pr_clear_value (&value); + if (error != NO_ERROR) + { + goto end; + } + /* histogram_values */ + db_make_null (&value); + error = dbt_put_internal (obj_tmpl, "histogram_values", &value); + pr_clear_value (&value); + if (error != NO_ERROR) + { + goto end; + } + ret_obj = dbt_finish_object (obj_tmpl); + if (ret_obj == NULL) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + } + else if (histogram_object != NULL) + { + histogram_object = ret_obj; + } +end: + if (obj_tmpl != NULL && ret_obj == NULL) + { + dbt_abort_object (obj_tmpl); + } + AU_ENABLE (au_save); + au_disable_flag = false; return error; } diff --git a/src/object/schema_template.h b/src/object/schema_template.h index c6381badaa1..1c9486a071d 100644 --- a/src/object/schema_template.h +++ b/src/object/schema_template.h @@ -84,8 +84,7 @@ extern int smt_add_constraint (SM_TEMPLATE * template_, DB_CONSTRAINT_TYPE const int class_attribute, SM_FOREIGN_KEY_INFO * fk_info, SM_PREDICATE_INFO * filter_index, SM_FUNCTION_INFO * function_index, const char *comment, SM_INDEX_STATUS index_status); -extern int smt_add_histogram (SM_TEMPLATE * template_, const char *attr_name, int data_type, int histogram_type, - int bucket_count); +extern int smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histogram_type, int bucket_count); extern int smt_drop_constraint (SM_TEMPLATE * template_, const char **att_names, const char *constraint_name, int class_attribute, SM_ATTRIBUTE_FLAG constraint); @@ -169,7 +168,7 @@ extern int smt_check_index_exist (SM_TEMPLATE * template_, char **out_shared_con DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, const int *asc_desc, const SM_PREDICATE_INFO * filter_index, const SM_FUNCTION_INFO * function_index); -extern int smt_check_histogram_exist (SM_TEMPLATE * template_, const char *attr_name); +extern int smt_check_histogram_exist (MOP classop, const char *attr_name); #if defined(ENABLE_UNUSED_FUNCTION) extern void smt_downcase_all_class_info (void); diff --git a/src/object/transform.c b/src/object/transform.c index d1bd29a08e7..364d9c0eb95 100644 --- a/src/object/transform.c +++ b/src/object/transform.c @@ -419,7 +419,7 @@ static CT_ATTR ct_partition_atts[] = { static CT_ATTR ct_histogram_atts[] = { {"class_of", NULL_ATTRID, DB_TYPE_OBJECT}, - {"attr_name", NULL_ATTRID, DB_TYPE_VARCHAR}, + {"key_attr", NULL_ATTRID, DB_TYPE_VARCHAR}, {"data_type", NULL_ATTRID, DB_TYPE_INTEGER}, {"histogram_type", NULL_ATTRID, DB_TYPE_INTEGER}, {"bucket_count", NULL_ATTRID, DB_TYPE_INTEGER} diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index da0cb39b6ec..9adca29e252 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3886,6 +3886,7 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, char *attname = NULL; PT_NODE *cur_column = NULL; int is_partition = DB_NOT_PARTITIONED_CLASS; + DB_OBJECT *histogram_class = NULL; /* check histogram is allowed on this class */ error = sm_partitioned_class_type (obj, &is_partition, NULL, NULL); if (error != NO_ERROR) @@ -3934,8 +3935,8 @@ int do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) { PT_NODE *cls; - DB_OBJECT *obj; - const char *index_name = NULL; + DB_OBJECT *obj, *db_class; + DB_VALUE value; int error = NO_ERROR; CHECK_MODIFICATION_ERROR (); @@ -3945,7 +3946,9 @@ do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) cls = statement->info.histogram.target_table_spec->info.spec.entity_name; - obj = db_find_class (cls->info.name.original); + db_class = sm_find_class (CT_CLASS_NAME); + db_make_string (&value, cls->info.name.original); + obj = db_find_unique (db_class, "unique_name", &value); if (obj == NULL) { assert (er_errid () != NO_ERROR); From e373e4f187fd32dc0b849d6a41d7b28416e5f36c Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 12 Sep 2025 20:10:54 +0900 Subject: [PATCH 010/112] =?UTF-8?q?(feature/bugfix)=20=ED=9E=88=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EA=B7=B8=EB=9E=A8=20unique=20check=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/object_accessor.c | 101 ++++++++++++++++++++++++++++------ src/object/object_primitive.c | 13 ++++- src/object/schema_manager.c | 2 +- src/object/schema_template.c | 4 -- src/query/execute_schema.c | 5 +- src/query/execute_statement.c | 3 +- src/query/execute_statement.h | 2 + src/transaction/log_applier.c | 2 +- 8 files changed, 104 insertions(+), 28 deletions(-) diff --git a/src/object/object_accessor.c b/src/object/object_accessor.c index 8a1d68ce137..85634c6cd12 100644 --- a/src/object/object_accessor.c +++ b/src/object/object_accessor.c @@ -55,7 +55,7 @@ #include "trigger_manager.h" #include "view_transform.h" #include "network_interface_cl.h" - +#include "execute_statement.h" #include "dbtype.h" /* @@ -3675,24 +3675,26 @@ obj_make_key_value (DB_VALUE * key, const DB_VALUE * values[], int size) MOP obj_find_multi_attr (MOP op, int size, const char *attr_names[], const DB_VALUE * values[], AU_FETCHMODE fetchmode) { - SM_CLASS *class_; + int error = NO_ERROR; SM_CLASS_CONSTRAINT *cons; MOP obj = NULL; - DB_VALUE key; SM_ATTRIBUTE **attp; const char **namep; - int i; - if (op == NULL || attr_names == NULL || values == NULL || size < 1) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ARGUMENTS, 0); - return NULL; - } - - db_make_null (&key); - if (obj_make_key_value (&key, values, size) == NULL) - { - return NULL; + SM_CLASS *class_ = NULL; + int i = 0; + BTID *unique_btid = NULL; + DB_VALUE *unique_key = NULL; + BTREE_SEARCH result; + SCAN_OPERATION_TYPE op_type = S_SELECT; + OID *oids; + int oid_count; + + DB_OTMPL *obj_tmpl = dbt_create_object_internal (op); + if (obj_tmpl == NULL) + { + error = ER_FAILED; + goto end_find; } if (au_fetch_class (op, &class_, AU_FETCH_READ, AU_SELECT) != NO_ERROR) @@ -3735,12 +3737,77 @@ obj_find_multi_attr (MOP op, int size, const char *attr_names[], const DB_VALUE goto end_find; } - obj = obj_find_object_by_cons_and_key (op, cons, &key, fetchmode); + + unique_btid = (BTID *) db_private_alloc (NULL, sizeof (BTID)); + if (unique_btid == NULL) + { + error = ER_FAILED; + goto end_find; + } + unique_key = (DB_VALUE *) db_private_alloc (NULL, sizeof (DB_VALUE)); + if (unique_key == NULL) + { + error = ER_FAILED; + goto end_find; + } + + BTID_COPY (unique_btid, &cons->index_btid); + db_make_null (unique_key); + + for (i = 0; i < size; i++) + { + error = dbt_put_internal (obj_tmpl, attr_names[i], (DB_VALUE *) values[i]); + if (error != NO_ERROR) + { + goto end_find; + } + } + + /* multiple key, need to create a MIDXKEY */ + error = do_create_midxkey_for_constraint (obj_tmpl, cons, unique_key); + if (error != NO_ERROR) + { + goto end_find; + } + + if (fetchmode == AU_FETCH_UPDATE) + { + op_type = S_UPDATE; + } + else + { + op_type = S_SELECT; + } + + result = + btree_find_multi_uniques (ws_oid (obj_tmpl->classobj), obj_tmpl->pruning_type, unique_btid, unique_key, size, + op_type, &oids, &oid_count); + + if (result == BTREE_ERROR_OCCURRED) + { + error = ER_FAILED; + } + else if (result == BTREE_KEY_NOTFOUND) + { + error = ER_OBJ_OBJECT_NOT_FOUND; + } + else if (result == BTREE_KEY_FOUND) + { + obj = ws_mop (oids, NULL); + } end_find: - if (size > 1) /* must clear a multi-column index key */ - pr_clear_value (&key); + if (unique_key != NULL) + { + pr_clear_value (unique_key); + db_private_free (NULL, unique_key); + } + if (unique_btid != NULL) + { + db_private_free (NULL, unique_btid); + } + assert (oid_count < 2); return obj; } diff --git a/src/object/object_primitive.c b/src/object/object_primitive.c index 38d3152d354..40f162f89dc 100644 --- a/src/object/object_primitive.c +++ b/src/object/object_primitive.c @@ -6693,11 +6693,22 @@ static int mr_index_writeval_oid (OR_BUF * buf, DB_VALUE * value) { OID *oidp = NULL; + DB_OBJECT *obj = NULL; int rc = NO_ERROR; assert (DB_VALUE_TYPE (value) == DB_TYPE_OID || DB_VALUE_TYPE (value) == DB_TYPE_OBJECT); - oidp = db_get_oid (value); + if (DB_VALUE_TYPE (value) == DB_TYPE_OBJECT) + { +#if !defined (SERVER_MODE) + obj = db_get_object (value); + oidp = WS_OID (obj); +#endif + } + else + { + oidp = db_get_oid (value); + } rc = or_put_data (buf, (char *) (&oidp->pageid), tp_Integer.disksize); if (rc == NO_ERROR) diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 5eb1ea6ad29..5e57cc7a0a2 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -15546,7 +15546,7 @@ sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogr (void) tran_abort_upto_system_savepoint (SM_ADD_HISTOGRAM_SAVEPOINT_NAME); } - return NO_ERROR; + return error; } diff --git a/src/object/schema_template.c b/src/object/schema_template.c index 41f1bede942..257ee082752 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -2000,16 +2000,13 @@ int smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histogram_type, int bucket_count) { int au_save, error = NO_ERROR; - bool au_disable_flag = false; DB_OBJECT *ret_obj = NULL, *histogram_class = NULL, *histogram_object = NULL; DB_VALUE value; - MOP class_of; DB_OTMPL *obj_tmpl = NULL; db_make_null (&value); /* temporarily disable authorization to access db_serial class */ AU_DISABLE (au_save); - au_disable_flag = true;; histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); if (histogram_class == NULL) @@ -2093,7 +2090,6 @@ smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histog dbt_abort_object (obj_tmpl); } AU_ENABLE (au_save); - au_disable_flag = false; return error; } diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 9adca29e252..2d349357855 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3937,8 +3937,8 @@ do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) PT_NODE *cls; DB_OBJECT *obj, *db_class; DB_VALUE value; - int error = NO_ERROR; - + int error = NO_ERROR, save; + AU_DISABLE (save); CHECK_MODIFICATION_ERROR (); /* class should be already available */ @@ -3956,6 +3956,7 @@ do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) } error = create_or_drop_histogram_helper (parser, obj, &statement->info.histogram, DO_HISTOGRAM_CREATE); + AU_ENABLE (save); return error; } diff --git a/src/query/execute_statement.c b/src/query/execute_statement.c index 8f42e086788..09ee8f383b5 100644 --- a/src/query/execute_statement.c +++ b/src/query/execute_statement.c @@ -11230,7 +11230,6 @@ static PT_NODE *test_check_option (PARSER_CONTEXT * parser, PT_NODE * node, void static int insert_local (PARSER_CONTEXT * parser, PT_NODE * statement); static PT_NODE *do_create_odku_stmt (PARSER_CONTEXT * parser, PT_NODE * insert); static int do_find_unique_constraint_violations (DB_OTMPL * tmpl, bool for_update, OID ** oids, int *oids_count); -static int do_create_midxkey_for_constraint (DB_OTMPL * tmpl, SM_CLASS_CONSTRAINT * constraint, DB_VALUE * key); static int do_on_duplicate_key_update (PARSER_CONTEXT * parser, DB_OTMPL * tpl, PT_NODE * update_stmt); static int do_replace_into (PARSER_CONTEXT * parser, DB_OTMPL * tmpl, PT_NODE * spec, PT_NODE * class_specs); static int is_replace_or_odku_allowed (DB_OBJECT * obj, int *allowed); @@ -11932,7 +11931,7 @@ do_set_insert_server_not_allowed (PARSER_CONTEXT * parser, PT_NODE * node, void * constraint (in) : constraint * key (in/out) : the MIDX key */ -static int +int do_create_midxkey_for_constraint (DB_OTMPL * tmpl, SM_CLASS_CONSTRAINT * constraint, DB_VALUE * key) { DB_MIDXKEY midxkey; diff --git a/src/query/execute_statement.h b/src/query/execute_statement.h index 50c546ee8fd..f092e972c8f 100644 --- a/src/query/execute_statement.h +++ b/src/query/execute_statement.h @@ -210,4 +210,6 @@ extern int do_find_serial_by_query (const char *name, char *buf, int buf_size); extern int do_find_trigger_by_query (const char *name, char *buf, int buf_size); extern int do_find_synonym_by_query (const char *name, char *buf, int buf_size); extern int do_find_stored_procedure_by_query (const char *name, char *buf, int buf_size); + +extern int do_create_midxkey_for_constraint (DB_OTMPL * tmpl, SM_CLASS_CONSTRAINT * constraint, DB_VALUE * key); #endif /* _EXECUTE_STATEMENT_H_ */ diff --git a/src/transaction/log_applier.c b/src/transaction/log_applier.c index c26aacc8494..7df8b47ea46 100644 --- a/src/transaction/log_applier.c +++ b/src/transaction/log_applier.c @@ -5527,7 +5527,7 @@ la_apply_statement_log (LA_ITEM * item) case CUBRID_STMT_DROP_SERIAL: case CUBRID_STMT_CREATE_HISTOGRAM: - //case CUBRID_STMT_DROP_HISTOGRAM: + //case CUBRID_STMT_DROP_HISTOGRAM: case CUBRID_STMT_DROP_DATABASE: From 1c44eed57f57d9ed2a759a5239a16c8e4eaf8fdb Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 25 Sep 2025 17:01:46 +0900 Subject: [PATCH 011/112] =?UTF-8?q?(fix)=20CBRD-26217:=20histogram=20db=5F?= =?UTF-8?q?class=5Fobject=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EB=90=98=EB=8F=84=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/class_object.h | 25 ++++++++--------- src/object/schema_template.c | 52 +++++++++++++++++++++++++++++++++--- src/query/execute_schema.c | 8 ++++++ 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/src/object/class_object.h b/src/object/class_object.h index e446f8220f9..fde3e5da765 100644 --- a/src/object/class_object.h +++ b/src/object/class_object.h @@ -550,6 +550,15 @@ struct sm_class_constraint SM_INDEX_STATUS index_status; }; +/* histogram */ +typedef struct sm_class_histogram SM_CLASS_HISTOGRAM; + +struct sm_class_histogram +{ + struct sm_class_histogram *next; + DB_OBJECT *histogram_object; +}; + /* * Holds information about a method argument. This will be used * in a SM_METHOD_SIGNATURE signature structure. @@ -761,6 +770,7 @@ struct sm_class struct parser_context *virtual_query_cache; struct tr_schema_cache *triggers; /* Trigger cache */ SM_CLASS_CONSTRAINT *constraints; /* Constraint cache */ + SM_CLASS_HISTOGRAM *histograms; /* Histogram info */ const char *comment; /* table comment */ SM_CLASS_CONSTRAINT *fk_ref; /* fk ref cache */ SM_PARTITION *partition; /* partition information */ @@ -812,6 +822,7 @@ struct sm_template DB_OBJLIST *ext_references; DB_SEQ *properties; + DB_OBJLIST *histograms; int *super_id_map; /* super class id mapping table */ @@ -911,18 +922,6 @@ struct sm_descriptor SM_NAME_SPACE name_space; /* component type */ }; - -/* histogram */ -typedef struct sm_histogram_info SM_HISTOGRAM_INFO; - -struct sm_histogram_info -{ - const char *attr_name; - int data_type; - int histogram_type; - int bucket_count; -}; - /* free_and_init routine */ #define classobj_free_threaded_array_and_init(list, clear) \ do \ @@ -967,6 +966,8 @@ extern int classobj_put_index (DB_SEQ ** properties, SM_CLASS_CONSTRAINT * con, extern int classobj_find_prop_constraint (DB_SEQ * properties, const char *prop_name, const char *cnstr_name, DB_VALUE * cnstr_val); +extern int classobj_put_histogram (DB_OBJLIST * histograms, SM_CLASS_HISTOGRAM * histogram); + #if defined (ENABLE_RENAME_CONSTRAINT) extern int classobj_rename_constraint (DB_SEQ * properties, const char *prop_name, const char *old_name, const char *new_name); diff --git a/src/object/schema_template.c b/src/object/schema_template.c index 257ee082752..91034652a3e 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -2000,9 +2000,10 @@ int smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histogram_type, int bucket_count) { int au_save, error = NO_ERROR; - DB_OBJECT *ret_obj = NULL, *histogram_class = NULL, *histogram_object = NULL; + DB_OBJECT *ret_obj = NULL, *histogram_class = NULL, *class_obj = NULL; DB_VALUE value; - DB_OTMPL *obj_tmpl = NULL; + DB_OTMPL *obj_tmpl = NULL, *class_obj_tmpl = NULL; + DB_SEQ *histograms = NULL; db_make_null (&value); /* temporarily disable authorization to access db_serial class */ @@ -2080,15 +2081,58 @@ smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histog assert (er_errid () != NO_ERROR); error = er_errid (); } - else if (histogram_object != NULL) + + /* edit the class */ + class_obj_tmpl = dbt_edit_object (classop); + if (class_obj_tmpl == NULL) + { + error = er_errid (); + goto end; + } + + /* make sequence of histograms */ + db_get (classop, "histograms", &value); + histograms = db_get_set (&value); + if (histograms == NULL) + { + histograms = set_create_sequence (0); + } + pr_clear_value (&value); + + /* put histograms in sequence*/ + db_make_object (&value, ret_obj); + set_put_element (histograms, set_size (histograms), &value); + pr_clear_value (&value); + + db_make_sequence (&value, histograms); + error = dbt_put_internal (class_obj_tmpl, "histograms", &value); + pr_clear_value (&value); + + if (error != NO_ERROR) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + goto end; + } + + class_obj = dbt_finish_object (class_obj_tmpl); + if (class_obj == NULL) { - histogram_object = ret_obj; + assert (er_errid () != NO_ERROR); + error = er_errid (); + goto end; } + end: if (obj_tmpl != NULL && ret_obj == NULL) { dbt_abort_object (obj_tmpl); } + if (class_obj_tmpl != NULL && class_obj == NULL) + { + dbt_abort_object (class_obj_tmpl); + } + AU_ENABLE (au_save); return error; } diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 2d349357855..8c2ade68309 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3956,6 +3956,14 @@ do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) } error = create_or_drop_histogram_helper (parser, obj, &statement->info.histogram, DO_HISTOGRAM_CREATE); + + if (error != NO_ERROR) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + return error; + } + AU_ENABLE (save); return error; } From ddb4599f716017047c2806cd39c7e537baf18040 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 25 Sep 2025 17:59:06 +0900 Subject: [PATCH 012/112] (bugfix) class_object.c, schema_template.c --- src/object/class_object.c | 7 ------- src/object/schema_template.c | 13 ++++++++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/object/class_object.c b/src/object/class_object.c index fe9a7f063d3..ef6febf56d0 100644 --- a/src/object/class_object.c +++ b/src/object/class_object.c @@ -8299,13 +8299,6 @@ classobj_check_index_exist (SM_CLASS_CONSTRAINT * constraints, char **out_shared return error; } -int -classobj_check_histogram_exist (SM_ATTRIBUTE * attributes, char attr_name) -{ - assert (false); // TODO: implement this - return NO_ERROR; -} - /* * classobj_make_function_index_info() - * return: diff --git a/src/object/schema_template.c b/src/object/schema_template.c index 91034652a3e..185e181fc1e 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -2003,7 +2003,7 @@ smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histog DB_OBJECT *ret_obj = NULL, *histogram_class = NULL, *class_obj = NULL; DB_VALUE value; DB_OTMPL *obj_tmpl = NULL, *class_obj_tmpl = NULL; - DB_SEQ *histograms = NULL; + DB_SEQ *histograms = NULL, *new_histograms = NULL; db_make_null (&value); /* temporarily disable authorization to access db_serial class */ @@ -2095,16 +2095,19 @@ smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histog histograms = db_get_set (&value); if (histograms == NULL) { - histograms = set_create_sequence (0); + new_histograms = set_create_sequence (0); + } + else + { + new_histograms = set_copy (histograms); } pr_clear_value (&value); - /* put histograms in sequence*/ db_make_object (&value, ret_obj); - set_put_element (histograms, set_size (histograms), &value); + set_add_element (new_histograms, &value); pr_clear_value (&value); - db_make_sequence (&value, histograms); + db_make_sequence (&value, new_histograms); error = dbt_put_internal (class_obj_tmpl, "histograms", &value); pr_clear_value (&value); From d2d117e3214fc509bb640cf65471e833a62062a0 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 1 Oct 2025 15:26:32 +0900 Subject: [PATCH 013/112] (d) --- src/base/error_code.h | 3 + src/object/schema_manager.c | 47 ++++++++++ src/object/schema_system_catalog_install.cpp | 3 +- src/object/schema_template.c | 99 +++++++++----------- src/query/execute_schema.c | 64 ++++++++++++- 5 files changed, 157 insertions(+), 59 deletions(-) diff --git a/src/base/error_code.h b/src/base/error_code.h index a4401d473d5..b3c5b9e6403 100644 --- a/src/base/error_code.h +++ b/src/base/error_code.h @@ -1750,6 +1750,9 @@ #define ER_DBLINK_TRAN -1367 +#define ER_SYNONYM_ALREADY_EXIST -1348 +#define ER_SYNONYM_NOT_EXIST -1349 + #define ER_LAST_ERROR -1368 diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 5e57cc7a0a2..06b11752a0b 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -15550,6 +15550,53 @@ sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogr } +int +sm_drop_histogram (MOP classop, const char *attr_name) +{ + bool set_savepoint = false; + int error = NO_ERROR; + DB_AUTH auth; + SM_CLASS *class_ = NULL; + DB_OBJECT *db_class = NULL; + + if (attr_name == NULL) + { + ERROR0 (error, ER_OBJ_INVALID_ARGUMENTS); + return error; + } + + error = tran_system_savepoint (SM_ADD_HISTOGRAM_SAVEPOINT_NAME); + if (error != NO_ERROR) + { + return error; + } + + set_savepoint = true; + error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT); + if (error != NO_ERROR) + { + goto error_exit; + } + + error = smt_check_histogram_exist_and_delete (classop, attr_name); + if (error != NO_ERROR) + { + goto error_exit; + } + + return error; + +error_exit: + if (set_savepoint && error != ER_TM_SERVER_DOWN_UNILATERALLY_ABORTED && error != ER_LK_UNILATERALLY_ABORTED) + { + (void) tran_abort_upto_system_savepoint (SM_ADD_HISTOGRAM_SAVEPOINT_NAME); + } + + return error; +} + + + /* * sm_save_function_index_info() - Saves the information necessary to recreate * a function index constraint diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index 89273593ae6..18a76c35a8e 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -397,8 +397,7 @@ namespace cubschema {"query_specs", format_sequence (CT_QUERYSPEC_NAME)}, {"indexes", format_sequence (CT_INDEX_NAME)}, {"comment", format_varchar (2048)}, - {"partition", format_sequence (CT_PARTITION_NAME)}, - {"histograms", format_sequence (CT_DB_HISTOGRAM_NAME)} + {"partition", format_sequence (CT_PARTITION_NAME)} }, // constraints { diff --git a/src/object/schema_template.c b/src/object/schema_template.c index 185e181fc1e..82d41ddb008 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -1976,11 +1976,46 @@ smt_check_histogram_exist (MOP classop, const char *attr_name) histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); if (histogram_class == NULL) { - error = ER_QPROC_DB_SERIAL_NOT_FOUND; //TODO + error = ER_BO_MISSING_OR_INVALID_CATALOG; er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); goto end; } + /* class_of, key_attr */ + db_make_object (&value[0], classop); + db_make_string (&value[1], attr_name); + + histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_READ); + if (histogram_obj != NULL) + { + error = ER_LC_CLASSNAME_EXIST; + char error_histogram[256]; + sprintf(error_histogram, "histogram of %s(%s)", sm_get_ch_name(classop), attr_name); + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, error_histogram); + goto end; + } +end: + return error; +} + +int +smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name) +{ + int error = NO_ERROR; + DB_OBJECT *histogram_class, *histogram_obj = NULL; + DB_VALUE value[2]; + DB_VALUE *value_ptrs[2] = { &value[0], &value[1] }; + const char *search_attrs[2] = { "class_of", "key_attr" }; + + histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); + if (histogram_class == NULL) + { + error = ER_BO_MISSING_OR_INVALID_CATALOG; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + goto end; + } + + /* class_of, key_attr */ db_make_object (&value[0], classop); db_make_string (&value[1], attr_name); @@ -1992,6 +2027,14 @@ smt_check_histogram_exist (MOP classop, const char *attr_name) er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); goto end; } + else + { + error = db_drop (histogram_obj); + if (error != NO_ERROR) + { + goto end; + } + } end: return error; } @@ -2000,10 +2043,9 @@ int smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histogram_type, int bucket_count) { int au_save, error = NO_ERROR; - DB_OBJECT *ret_obj = NULL, *histogram_class = NULL, *class_obj = NULL; + DB_OBJECT *ret_obj = NULL, *histogram_class = NULL; DB_VALUE value; - DB_OTMPL *obj_tmpl = NULL, *class_obj_tmpl = NULL; - DB_SEQ *histograms = NULL, *new_histograms = NULL; + DB_OTMPL *obj_tmpl = NULL; db_make_null (&value); /* temporarily disable authorization to access db_serial class */ @@ -2082,60 +2124,11 @@ smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histog error = er_errid (); } - /* edit the class */ - class_obj_tmpl = dbt_edit_object (classop); - if (class_obj_tmpl == NULL) - { - error = er_errid (); - goto end; - } - - /* make sequence of histograms */ - db_get (classop, "histograms", &value); - histograms = db_get_set (&value); - if (histograms == NULL) - { - new_histograms = set_create_sequence (0); - } - else - { - new_histograms = set_copy (histograms); - } - pr_clear_value (&value); - - db_make_object (&value, ret_obj); - set_add_element (new_histograms, &value); - pr_clear_value (&value); - - db_make_sequence (&value, new_histograms); - error = dbt_put_internal (class_obj_tmpl, "histograms", &value); - pr_clear_value (&value); - - if (error != NO_ERROR) - { - assert (er_errid () != NO_ERROR); - error = er_errid (); - goto end; - } - - class_obj = dbt_finish_object (class_obj_tmpl); - if (class_obj == NULL) - { - assert (er_errid () != NO_ERROR); - error = er_errid (); - goto end; - } - end: if (obj_tmpl != NULL && ret_obj == NULL) { dbt_abort_object (obj_tmpl); } - if (class_obj_tmpl != NULL && class_obj == NULL) - { - dbt_abort_object (class_obj_tmpl); - } - AU_ENABLE (au_save); return error; } diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 8c2ade68309..8d74245f7ff 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3908,10 +3908,21 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, { attname = (char *) cur_column->info.name.original; data_type = cur_column->type_enum; - error = sm_add_histogram (obj, attname, data_type, histogram_type, bucket_count); - if (error != NO_ERROR) + if (do_histogram == DO_HISTOGRAM_DROP) { - return error; + error = sm_drop_histogram (obj, attname); + if (error != NO_ERROR) + { + return error; + } + } + else + { + error = sm_add_histogram (obj, attname, data_type, histogram_type, bucket_count); + if (error != NO_ERROR) + { + return error; + } } cur_column = cur_column->next; } @@ -3956,7 +3967,7 @@ do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) } error = create_or_drop_histogram_helper (parser, obj, &statement->info.histogram, DO_HISTOGRAM_CREATE); - + if (error != NO_ERROR) { assert (er_errid () != NO_ERROR); @@ -3968,6 +3979,51 @@ do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) return error; } + +/** + * do_create_histogram() - Creates a histogram on a class. + * return: Error code if it fails + * parser(in): Parser context + * statement(in): Parse tree of a create histogram statement + */ +int +do_drop_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) +{ + PT_NODE *cls; + DB_OBJECT *obj, *db_class; + DB_VALUE value; + int error = NO_ERROR, save; + AU_DISABLE (save); + CHECK_MODIFICATION_ERROR (); + + /* class should be already available */ + assert (statement->info.histogram.target_table_spec); + + cls = statement->info.histogram.target_table_spec->info.spec.entity_name; + + db_class = sm_find_class (CT_CLASS_NAME); + db_make_string (&value, cls->info.name.original); + obj = db_find_unique (db_class, "unique_name", &value); + if (obj == NULL) + { + assert (er_errid () != NO_ERROR); + return er_errid (); + } + + error = create_or_drop_histogram_helper (parser, obj, &statement->info.histogram, DO_HISTOGRAM_DROP); + + if (error != NO_ERROR) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + return error; + } + + AU_ENABLE (save); + return error; +} + + /* * do_create_partition() - Creates partitions * return: Error code if partitions are not created From 07c18dec6891122893b5ab8f437f95b858f6a5d7 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 14 Oct 2025 10:23:40 +0900 Subject: [PATCH 014/112] =?UTF-8?q?(add)=20bugfix=20=EC=9A=A9=20=EC=BB=A4?= =?UTF-8?q?=EB=B0=8B=20(diff=EC=9E=98=20=EC=B0=BE=EC=95=84=EB=B3=B4?= =?UTF-8?q?=EA=B8=B0=20=EC=9C=84=ED=95=B4=EC=84=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/ddl_log.c | 1 + src/compat/dbi_compat.h | 1 + src/compat/dbtype_def.h | 2 +- src/executables/csql_result.c | 2 +- src/object/schema_manager.h | 1 + src/object/schema_template.c | 6 ++- src/object/schema_template.h | 1 + src/parser/csql_grammar.y | 37 +++++++++++++++++ src/parser/name_resolution.c | 15 +++++++ src/parser/parse_tree.h | 1 + src/parser/parse_tree_cl.c | 76 ++++++++++++++++++++++++++++++++++- src/parser/parser_message.h | 1 + src/parser/parser_support.c | 3 +- src/parser/semantic_check.c | 25 ++++++++++++ src/query/execute_statement.c | 8 ++++ src/query/execute_statement.h | 2 +- src/transaction/log_applier.c | 2 +- 17 files changed, 175 insertions(+), 9 deletions(-) diff --git a/src/base/ddl_log.c b/src/base/ddl_log.c index ac1ca460c1e..76be812a808 100644 --- a/src/base/ddl_log.c +++ b/src/base/ddl_log.c @@ -1434,6 +1434,7 @@ logddl_is_ddl_type (int node_type, PT_NODE * node) case PT_CREATE_INDEX: case PT_CREATE_SERIAL: case PT_CREATE_HISTOGRAM: + case PT_DROP_HISTOGRAM: case PT_CREATE_STORED_PROCEDURE: case PT_CREATE_SYNONYM: case PT_CREATE_TRIGGER: diff --git a/src/compat/dbi_compat.h b/src/compat/dbi_compat.h index 70a35663e39..8b8521d11a4 100644 --- a/src/compat/dbi_compat.h +++ b/src/compat/dbi_compat.h @@ -64,6 +64,7 @@ extern "C" #define SQLX_CMD_CREATE_CLASS CUBRID_STMT_CREATE_CLASS #define SQLX_CMD_CREATE_INDEX CUBRID_STMT_CREATE_INDEX #define SQLX_CMD_CREATE_HISTOGRAM CUBRID_STMT_CREATE_HISTOGRAM +#define SQLX_CMD_DROP_HISTOGRAM CUBRID_STMT_DROP_HISTOGRAM #define SQLX_CMD_CREATE_TRIGGER CUBRID_STMT_CREATE_TRIGGER #define SQLX_CMD_CREATE_SERIAL CUBRID_STMT_CREATE_SERIAL #define SQLX_CMD_DROP_DATABASE CUBRID_STMT_DROP_DATABASE diff --git a/src/compat/dbtype_def.h b/src/compat/dbtype_def.h index 4a36f12151d..60dd09364dc 100644 --- a/src/compat/dbtype_def.h +++ b/src/compat/dbtype_def.h @@ -120,7 +120,7 @@ extern "C" CUBRID_STMT_SET_SYS_PARAMS, CUBRID_STMT_ALTER_INDEX, CUBRID_STMT_CREATE_HISTOGRAM, - + CUBRID_STMT_DROP_HISTOGRAM, CUBRID_STMT_CREATE_STORED_PROCEDURE, CUBRID_STMT_DROP_STORED_PROCEDURE, CUBRID_STMT_PREPARE_STATEMENT, diff --git a/src/executables/csql_result.c b/src/executables/csql_result.c index d022358fa1c..ab74f0318c0 100644 --- a/src/executables/csql_result.c +++ b/src/executables/csql_result.c @@ -110,7 +110,7 @@ static CSQL_CMD_STRING_TABLE csql_Cmd_string_table[] = { {CUBRID_STMT_GRANT, "GRANT"}, {CUBRID_STMT_REVOKE, "REVOKE"}, {CUBRID_STMT_CREATE_HISTOGRAM, "CREATE HISTOGRAM"}, - //{CUBRID_STMT_DROP_HISTOGRAM, "DROP HISTOGRAM"}, TODO + {CUBRID_STMT_DROP_HISTOGRAM, "DROP HISTOGRAM"}, {CUBRID_STMT_CREATE_USER, "CREATE USER"}, {CUBRID_STMT_DROP_USER, "DROP USER"}, {CUBRID_STMT_ALTER_USER, "ALTER USER"}, diff --git a/src/object/schema_manager.h b/src/object/schema_manager.h index 6454b9f6b27..f1661e485c3 100644 --- a/src/object/schema_manager.h +++ b/src/object/schema_manager.h @@ -113,6 +113,7 @@ extern int sm_add_constraint (MOP classop, DB_CONSTRAINT_TYPE constraint_type, c int class_attributes, SM_PREDICATE_INFO * predicate_info, SM_FUNCTION_INFO * fi_info, const char *comment, SM_INDEX_STATUS index_status); extern int sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogram_type, int bucket_count); +extern int sm_drop_histogram (MOP classop, const char *attr_name); extern int sm_drop_constraint (MOP classop, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, bool class_attributes, bool mysql_index_name); extern int sm_drop_index (MOP classop, const char *constraint_name); diff --git a/src/object/schema_template.c b/src/object/schema_template.c index 82d41ddb008..c9cdc606898 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -2023,8 +2023,10 @@ smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name) histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_READ); if (histogram_obj != NULL) { - error = ER_QPROC_DB_SERIAL_NOT_FOUND; //TODO - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + error = ER_LC_UNKNOWN_CLASSNAME; + char error_histogram[256]; + sprintf(error_histogram, "histogram of %s(%s)", sm_get_ch_name(classop), attr_name); + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, error_histogram); goto end; } else diff --git a/src/object/schema_template.h b/src/object/schema_template.h index 1c9486a071d..240349d40ef 100644 --- a/src/object/schema_template.h +++ b/src/object/schema_template.h @@ -169,6 +169,7 @@ extern int smt_check_index_exist (SM_TEMPLATE * template_, char **out_shared_con const char **att_names, const int *asc_desc, const SM_PREDICATE_INFO * filter_index, const SM_FUNCTION_INFO * function_index); extern int smt_check_histogram_exist (MOP classop, const char *attr_name); +extern int smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name); #if defined(ENABLE_UNUSED_FUNCTION) extern void smt_downcase_all_class_info (void); diff --git a/src/parser/csql_grammar.y b/src/parser/csql_grammar.y index 3ef121573ed..f66418541b2 100644 --- a/src/parser/csql_grammar.y +++ b/src/parser/csql_grammar.y @@ -4829,6 +4829,43 @@ drop_stmt $$ = node; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} + | DROP /* 1 */ + { /* 2 */ + DBG_TRACE_GRAMMAR(create_stmt, | CREATE); + PT_NODE* node = parser_new_node (this_parser, PT_DROP_HISTOGRAM); + parser_push_hint_node (node); + push_msg (MSGCAT_SYNTAX_INVALID_DROP_HISTOGRAM); + } + HISTOGRAM /* 3 */ + { pop_msg(); } /* 4 */ + ON_ /* 5 */ + only_class_name /* 6 */ + '(' histogram_column_list ')' /* 8 */ + opt_comment_spec /* 9 */ + {{ DBG_TRACE_GRAMMAR (create_stmt, | DROP HISTOGRAM ON_ ~); + + PT_NODE *node = parser_pop_hint_node (); + PARSER_SAVE_ERR_CONTEXT (node, @$.buffer_pos) + PT_NODE *ocs = parser_new_node(this_parser, PT_SPEC); + + if (node && ocs) + { + PT_NODE *col, *temp; + int arg_count = 0, prefix_col_count = 0; + ocs->info.spec.entity_name = $6; + PARSER_SAVE_ERR_CONTEXT (ocs, @6.buffer_pos) + ocs->info.spec.meta_class = PT_CLASS; + node->info.histogram.target_table_spec = ocs; + col = $8; + + prefix_col_count = parser_count_prefix_columns (col, &arg_count); + node->info.histogram.target_columns = col; + } + + $$ = node; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} | DROP FUNCTION procedure_or_function_name_list {{ DBG_TRACE_GRAMMAR(drop_stmt, | DROP FUNCTION procedure_or_function_name_list); diff --git a/src/parser/name_resolution.c b/src/parser/name_resolution.c index 8f4db800e25..3c9eb992125 100644 --- a/src/parser/name_resolution.c +++ b/src/parser/name_resolution.c @@ -3310,6 +3310,21 @@ pt_bind_names (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue *continue_walk = PT_LIST_WALK; break; + case PT_DROP_HISTOGRAM: + scopestack.specs = node->info.histogram.target_table_spec; + bind_arg->scopes = &scopestack; + spec_frame.next = bind_arg->spec_frames; + spec_frame.extra_specs = NULL; + bind_arg->spec_frames = &spec_frame; + pt_bind_scope (parser, bind_arg); + + parser_walk_leaves (parser, node, pt_bind_names, bind_arg, pt_bind_names_post, bind_arg); + + bind_arg->spec_frames = bind_arg->spec_frames->next; + bind_arg->scopes = bind_arg->scopes->next; + + *continue_walk = PT_LIST_WALK; + break; case PT_METHOD_CALL: /* * We accept two different method call syntax: diff --git a/src/parser/parse_tree.h b/src/parser/parse_tree.h index b23e3fb9605..d6e6d12b9f6 100644 --- a/src/parser/parse_tree.h +++ b/src/parser/parse_tree.h @@ -999,6 +999,7 @@ enum pt_node_type PT_UPDATE_STATS = CUBRID_STMT_UPDATE_STATS, PT_GET_STATS = CUBRID_STMT_GET_STATS, PT_CREATE_HISTOGRAM = CUBRID_STMT_CREATE_HISTOGRAM, + PT_DROP_HISTOGRAM = CUBRID_STMT_DROP_HISTOGRAM, PT_INSERT = CUBRID_STMT_INSERT, PT_SELECT = CUBRID_STMT_SELECT, PT_UPDATE = CUBRID_STMT_UPDATE, diff --git a/src/parser/parse_tree_cl.c b/src/parser/parse_tree_cl.c index f4321740ef5..9042d7067c9 100644 --- a/src/parser/parse_tree_cl.c +++ b/src/parser/parse_tree_cl.c @@ -294,6 +294,7 @@ static PT_NODE *pt_init_constraint (PT_NODE * node); static PT_NODE *pt_init_create_entity (PT_NODE * p); static PT_NODE *pt_init_create_index (PT_NODE * p); static PT_NODE *pt_init_create_histogram (PT_NODE * p); +static PT_NODE *pt_init_drop_histogram (PT_NODE * p); static PT_NODE *pt_init_data_default (PT_NODE * p); static PT_NODE *pt_init_datatype (PT_NODE * p); static PT_NODE *pt_init_delete (PT_NODE * p); @@ -343,6 +344,7 @@ static PARSER_VARCHAR *pt_print_col_def_constraint (PARSER_CONTEXT * parser, PT_ static PARSER_VARCHAR *pt_print_create_entity (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_index (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p); +static PARSER_VARCHAR *pt_print_drop_histogram (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_serial (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_trigger (PARSER_CONTEXT * parser, PT_NODE * p); @@ -3076,6 +3078,8 @@ pt_show_node_type (PT_NODE * node) return "CREATE_INDEX"; case PT_CREATE_HISTOGRAM: return "CREATE_HISTOGRAM"; + case PT_DROP_HISTOGRAM: + return "DROP_HISTOGRAM"; case PT_CREATE_USER: return "CREATE_USER"; case PT_CREATE_TRIGGER: @@ -5036,6 +5040,7 @@ pt_init_apply_f (void) pt_apply_func_array[PT_CREATE_ENTITY] = pt_apply_create_entity; pt_apply_func_array[PT_CREATE_INDEX] = pt_apply_create_index; pt_apply_func_array[PT_CREATE_HISTOGRAM] = pt_apply_create_histogram; //TODO + pt_apply_func_array[PT_DROP_HISTOGRAM] = pt_apply_create_histogram; pt_apply_func_array[PT_CREATE_USER] = pt_apply_create_user; pt_apply_func_array[PT_CREATE_TRIGGER] = pt_apply_create_trigger; pt_apply_func_array[PT_CREATE_SERIAL] = pt_apply_create_serial; @@ -5170,7 +5175,8 @@ pt_init_init_f (void) pt_init_func_array[PT_COMMIT_WORK] = pt_init_func_null_function; pt_init_func_array[PT_CREATE_ENTITY] = pt_init_create_entity; pt_init_func_array[PT_CREATE_INDEX] = pt_init_create_index; - pt_init_func_array[PT_CREATE_HISTOGRAM] = pt_init_create_histogram; //TODO + pt_init_func_array[PT_CREATE_HISTOGRAM] = pt_init_create_histogram; + pt_init_func_array[PT_DROP_HISTOGRAM] = pt_init_drop_histogram; pt_init_func_array[PT_CREATE_USER] = pt_init_func_null_function; pt_init_func_array[PT_CREATE_TRIGGER] = pt_init_func_null_function; pt_init_func_array[PT_CREATE_SERIAL] = pt_init_func_null_function; @@ -5301,7 +5307,8 @@ pt_init_print_f (void) pt_print_func_array[PT_COMMIT_WORK] = pt_print_commit_work; pt_print_func_array[PT_CREATE_ENTITY] = pt_print_create_entity; pt_print_func_array[PT_CREATE_INDEX] = pt_print_create_index; - pt_print_func_array[PT_CREATE_HISTOGRAM] = pt_print_create_histogram; //TODO + pt_print_func_array[PT_CREATE_HISTOGRAM] = pt_print_create_histogram; + pt_print_func_array[PT_DROP_HISTOGRAM] = pt_print_drop_histogram; pt_print_func_array[PT_CREATE_USER] = pt_print_create_user; pt_print_func_array[PT_CREATE_TRIGGER] = pt_print_create_trigger; pt_print_func_array[PT_CREATE_SERIAL] = pt_print_create_serial; @@ -7348,6 +7355,20 @@ pt_init_create_histogram (PT_NODE * p) return p; } +/* CREATE_HISTOGRAM */ +/* + * pt_init_drop_histogram () - + * return: + * p(in): + */ +static PT_NODE * +pt_init_drop_histogram (PT_NODE * p) +{ + p->info.histogram.histogram_type = 0; + p->info.histogram.bucket_count = 0; + return p; +} + /* * pt_apply_create_histogram () - * return: @@ -7415,6 +7436,57 @@ pt_print_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p) return b; } +/* + * pt_apply_create_histogram () - + * return: + * parser(in): + * p(in): + * g(in): + * arg(in): + */ +static PARSER_VARCHAR * +pt_print_drop_histogram (PARSER_CONTEXT * parser, PT_NODE * p) +{ + PARSER_VARCHAR *b = 0, *tbl = 0, *cl = 0; + unsigned int saved_cp = parser->custom_print; + PT_NODE *target_columns; + + parser->custom_print |= PT_SUPPRESS_RESOLVED; + + if (!(parser->custom_print & PT_SUPPRESS_INDEX)) + { + b = pt_append_nulstring (parser, b, "drop"); + } + + b = pt_append_nulstring (parser, b, " histogram"); + + if (p->info.histogram.target_table_spec) + { + tbl = pt_print_bytes (parser, p->info.histogram.target_table_spec); + } + + if (!(parser->custom_print & PT_SUPPRESS_INDEX)) + { + b = pt_append_nulstring (parser, b, " on "); + b = pt_append_varchar (parser, b, tbl); + } + + + if (p->info.histogram.target_columns) + { + target_columns = p->info.histogram.target_columns; + cl = pt_print_bytes_l (parser, target_columns); + } + + b = pt_append_nulstring (parser, b, " ("); + b = pt_append_varchar (parser, b, cl); + b = pt_append_nulstring (parser, b, ") "); + + parser->custom_print = saved_cp; + + return b; +} + /* CREATE_INDEX */ /* * pt_apply_create_index () - diff --git a/src/parser/parser_message.h b/src/parser/parser_message.h index 871897b2bfb..45329dcdd68 100644 --- a/src/parser/parser_message.h +++ b/src/parser/parser_message.h @@ -175,6 +175,7 @@ #define MSGCAT_SYNTAX_INVALID_LEVEL MSGCAT_SYNTAX_NO(138) #define MSGCAT_SYNTAX_NO_PRECISION_IN_SP_FUNCTION MSGCAT_SYNTAX_NO(139) #define MSGCAT_SYNTAX_INVALID_CREATE_HISTOGRAM MSGCAT_SYNTAX_NO(140) +#define MSGCAT_SYNTAX_INVALID_DROP_HISTOGRAM MSGCAT_SYNTAX_NO(141) /* Message id in the set MSGCAT_SET_PARSER_SEMANTIC */ diff --git a/src/parser/parser_support.c b/src/parser/parser_support.c index d67b23d97f7..ff022533f4f 100644 --- a/src/parser/parser_support.c +++ b/src/parser/parser_support.c @@ -1514,7 +1514,8 @@ pt_is_ddl_statement (const PT_NODE * node) case PT_REMOVE_TRIGGER: case PT_RENAME_TRIGGER: case PT_UPDATE_STATS: - case PT_CREATE_HISTOGRAM: //TODO + case PT_CREATE_HISTOGRAM: + case PT_DROP_HISTOGRAM: /* TODO: check it */ case PT_CREATE_SERVER: case PT_DROP_SERVER: diff --git a/src/parser/semantic_check.c b/src/parser/semantic_check.c index fe4723f9a38..6921c019140 100644 --- a/src/parser/semantic_check.c +++ b/src/parser/semantic_check.c @@ -12428,6 +12428,31 @@ pt_check_with_info (PARSER_CONTEXT * parser, PT_NODE * node, SEMANTIC_CHK_INFO * } } break; + case PT_DROP_HISTOGRAM: + if (parser->host_var_count) + { + PT_ERRORm (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_HOSTVAR_IN_DDL); + } + else + { + sc_info_ptr->system_class = false; + node = pt_resolve_names (parser, node, sc_info_ptr); + if (!pt_has_error (parser) && node->node_type == PT_CREATE_HISTOGRAM) + { + pt_check_create_histogram (parser, node); + } + + if (!pt_has_error (parser)) + { + node = pt_semantic_type (parser, node, info); + } + + if (node && !pt_has_error (parser)) + { + node = parser_walk_tree (parser, node, NULL, NULL, pt_semantic_check_local, sc_info_ptr); + } + } + break; case PT_SAVEPOINT: if ((node->info.savepoint.save_name) && (node->info.savepoint.save_name->info.name.meta_class == PT_PARAMETER)) { diff --git a/src/query/execute_statement.c b/src/query/execute_statement.c index 09ee8f383b5..a79a91c301f 100644 --- a/src/query/execute_statement.c +++ b/src/query/execute_statement.c @@ -3160,6 +3160,7 @@ do_statement (PARSER_CONTEXT * parser, PT_NODE * statement) case PT_CREATE_TRIGGER: case PT_CREATE_USER: case PT_CREATE_HISTOGRAM: + case PT_DROP_HISTOGRAM: case PT_ALTER: case PT_ALTER_INDEX: case PT_ALTER_SERIAL: @@ -3241,6 +3242,9 @@ do_statement (PARSER_CONTEXT * parser, PT_NODE * statement) error = do_create_histogram (parser, statement); break; + case PT_DROP_HISTOGRAM: + error = do_drop_histogram (parser, statement); + break; case PT_EVALUATE: error = do_evaluate (parser, statement); break; @@ -3862,6 +3866,7 @@ do_execute_statement (PARSER_CONTEXT * parser, PT_NODE * statement) case PT_CREATE_TRIGGER: case PT_CREATE_USER: case PT_CREATE_HISTOGRAM: + case PT_DROP_HISTOGRAM: case PT_ALTER: case PT_ALTER_INDEX: case PT_ALTER_SERIAL: @@ -3938,6 +3943,9 @@ do_execute_statement (PARSER_CONTEXT * parser, PT_NODE * statement) case PT_CREATE_HISTOGRAM: err = do_create_histogram (parser, statement); break; + case PT_DROP_HISTOGRAM: + err = do_drop_histogram (parser, statement); + break; case PT_ALTER: /* err = do_alter(parser, statement); */ /* execute internal statements before and after do_alter() */ diff --git a/src/query/execute_statement.h b/src/query/execute_statement.h index f092e972c8f..de7e032f687 100644 --- a/src/query/execute_statement.h +++ b/src/query/execute_statement.h @@ -120,7 +120,7 @@ extern int do_prepare_delete (PARSER_CONTEXT * parser, PT_NODE * statement, PT_N extern int do_execute_delete (PARSER_CONTEXT * parser, PT_NODE * statement); extern int do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement); - +extern int do_drop_histogram (PARSER_CONTEXT * parser, PT_NODE * statement); extern int do_drop (PARSER_CONTEXT * parser, PT_NODE * statement); extern int do_drop_variable (PARSER_CONTEXT * parser, PT_NODE * statement); diff --git a/src/transaction/log_applier.c b/src/transaction/log_applier.c index 7df8b47ea46..01c26f3cc5f 100644 --- a/src/transaction/log_applier.c +++ b/src/transaction/log_applier.c @@ -5527,7 +5527,7 @@ la_apply_statement_log (LA_ITEM * item) case CUBRID_STMT_DROP_SERIAL: case CUBRID_STMT_CREATE_HISTOGRAM: - //case CUBRID_STMT_DROP_HISTOGRAM: + case CUBRID_STMT_DROP_HISTOGRAM: case CUBRID_STMT_DROP_DATABASE: From df1fdb5049fc3aab88067fcd9764837b823aebf8 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 14 Oct 2025 11:59:47 +0900 Subject: [PATCH 015/112] =?UTF-8?q?(bugfix)=20=EB=B2=84=EA=B7=B8=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/transform.c | 3 +-- src/parser/semantic_check.c | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/object/transform.c b/src/object/transform.c index 364d9c0eb95..9bd3fd7cb79 100644 --- a/src/object/transform.c +++ b/src/object/transform.c @@ -306,8 +306,7 @@ static CT_ATTR ct_class_atts[] = { {"query_specs", NULL_ATTRID, DB_TYPE_SEQUENCE}, {"indexes", NULL_ATTRID, DB_TYPE_SEQUENCE}, {"comment", NULL_ATTRID, DB_TYPE_VARCHAR}, - {"partition", NULL_ATTRID, DB_TYPE_SEQUENCE}, - {"histograms", NULL_ATTRID, DB_TYPE_SEQUENCE} + {"partition", NULL_ATTRID, DB_TYPE_SEQUENCE} }; static CT_ATTR ct_attribute_atts[] = { diff --git a/src/parser/semantic_check.c b/src/parser/semantic_check.c index 6921c019140..f4622972485 100644 --- a/src/parser/semantic_check.c +++ b/src/parser/semantic_check.c @@ -9171,8 +9171,6 @@ pt_check_create_histogram (PARSER_CONTEXT * parser, PT_NODE * node) name->info.name.db_object = db_obj; - /* check that histogram already exists */ - // TODO pt_check_user_owns_class (parser, name); if (pt_has_error (parser)) From aee4856f578104ad824181a615758939e259681c Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 14 Oct 2025 12:56:03 +0900 Subject: [PATCH 016/112] =?UTF-8?q?(bugfix/indent)=20=EB=B0=98=EB=8C=80?= =?UTF-8?q?=EB=A1=9C=20=ED=91=9C=EC=8B=9C=EB=90=98=EC=96=B4=EC=9E=88?= =?UTF-8?q?=EB=8D=98=20bool=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/schema_template.c | 22 +++++++++++----------- src/query/execute_statement.c | 12 ++++++------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/object/schema_template.c b/src/object/schema_template.c index c9cdc606898..c57a7a7aeea 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -1990,7 +1990,7 @@ smt_check_histogram_exist (MOP classop, const char *attr_name) { error = ER_LC_CLASSNAME_EXIST; char error_histogram[256]; - sprintf(error_histogram, "histogram of %s(%s)", sm_get_ch_name(classop), attr_name); + sprintf (error_histogram, "histogram of %s(%s)", sm_get_ch_name (classop), attr_name); er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, error_histogram); goto end; } @@ -2009,11 +2009,11 @@ smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name) histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); if (histogram_class == NULL) - { - error = ER_BO_MISSING_OR_INVALID_CATALOG; - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); - goto end; - } + { + error = ER_BO_MISSING_OR_INVALID_CATALOG; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + goto end; + } /* class_of, key_attr */ @@ -2021,11 +2021,11 @@ smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name) db_make_string (&value[1], attr_name); histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_READ); - if (histogram_obj != NULL) + if (histogram_obj == NULL) { error = ER_LC_UNKNOWN_CLASSNAME; char error_histogram[256]; - sprintf(error_histogram, "histogram of %s(%s)", sm_get_ch_name(classop), attr_name); + sprintf (error_histogram, "histogram of %s(%s)", sm_get_ch_name (classop), attr_name); er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, error_histogram); goto end; } @@ -2033,9 +2033,9 @@ smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name) { error = db_drop (histogram_obj); if (error != NO_ERROR) - { - goto end; - } + { + goto end; + } } end: return error; diff --git a/src/query/execute_statement.c b/src/query/execute_statement.c index a79a91c301f..c5617db728a 100644 --- a/src/query/execute_statement.c +++ b/src/query/execute_statement.c @@ -3160,7 +3160,7 @@ do_statement (PARSER_CONTEXT * parser, PT_NODE * statement) case PT_CREATE_TRIGGER: case PT_CREATE_USER: case PT_CREATE_HISTOGRAM: - case PT_DROP_HISTOGRAM: + case PT_DROP_HISTOGRAM: case PT_ALTER: case PT_ALTER_INDEX: case PT_ALTER_SERIAL: @@ -3242,9 +3242,9 @@ do_statement (PARSER_CONTEXT * parser, PT_NODE * statement) error = do_create_histogram (parser, statement); break; - case PT_DROP_HISTOGRAM: - error = do_drop_histogram (parser, statement); - break; + case PT_DROP_HISTOGRAM: + error = do_drop_histogram (parser, statement); + break; case PT_EVALUATE: error = do_evaluate (parser, statement); break; @@ -3944,8 +3944,8 @@ do_execute_statement (PARSER_CONTEXT * parser, PT_NODE * statement) err = do_create_histogram (parser, statement); break; case PT_DROP_HISTOGRAM: - err = do_drop_histogram (parser, statement); - break; + err = do_drop_histogram (parser, statement); + break; case PT_ALTER: /* err = do_alter(parser, statement); */ /* execute internal statements before and after do_alter() */ From ecf979fe4c2a15b481f649bd566bb578f52cee24 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 14 Oct 2025 15:15:01 +0900 Subject: [PATCH 017/112] =?UTF-8?q?(feature/bugfix)=20histogram=EC=9D=B4?= =?UTF-8?q?=20class=20drop=EC=8B=9C=20drop=EB=90=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20class=20=EC=A0=84=EC=B2=B4=EC=9D=98=20meta?= =?UTF-8?q?=20=EC=A0=95=EB=B3=B4=EA=B0=80=20histogram=EC=97=90=20=ED=8F=AC?= =?UTF-8?q?=ED=95=A8=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/schema_manager.c | 17 +++++++++++++++++ src/object/schema_system_catalog_install.cpp | 2 +- src/query/execute_schema.c | 8 ++------ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 06b11752a0b..43ed975f275 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -13672,6 +13672,23 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) } } + + /* remove histogram object if exist */ + for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) + { + int save; + AU_DISABLE (save); + error = smt_check_histogram_exist_and_delete (op, att->header.name); + if (error != NO_ERROR) + { + if (error != ER_LC_UNKNOWN_CLASSNAME) + { + goto end; + } + } + AU_ENABLE (save); + } + /* remove auto_increment serial object if exist */ for (att = class_->ordered_attributes; att; att = att->order_link) { diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index 18a76c35a8e..5612a701335 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -1268,7 +1268,7 @@ namespace cubschema CT_DB_HISTOGRAM_NAME, // columns { - {"class_of", CT_CLASS_NAME}, + {"class_of", "object"}, {"key_attr", format_varchar (255)}, {"data_type", "integer"}, {"histogram_type","integer"}, diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 8d74245f7ff..46b3d06cd71 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3957,9 +3957,7 @@ do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) cls = statement->info.histogram.target_table_spec->info.spec.entity_name; - db_class = sm_find_class (CT_CLASS_NAME); - db_make_string (&value, cls->info.name.original); - obj = db_find_unique (db_class, "unique_name", &value); + obj = db_find_class (cls->info.name.original); if (obj == NULL) { assert (er_errid () != NO_ERROR); @@ -4001,9 +3999,7 @@ do_drop_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) cls = statement->info.histogram.target_table_spec->info.spec.entity_name; - db_class = sm_find_class (CT_CLASS_NAME); - db_make_string (&value, cls->info.name.original); - obj = db_find_unique (db_class, "unique_name", &value); + obj = db_find_class (cls->info.name.original); if (obj == NULL) { assert (er_errid () != NO_ERROR); From 53458add9791b412360a033447c059f3ae99e6f7 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 14 Oct 2025 15:50:17 +0900 Subject: [PATCH 018/112] =?UTF-8?q?(bugfix):=20=EB=B2=84=EA=B7=B8=EC=9D=98?= =?UTF-8?q?=20=EC=9B=90=EC=9D=B8=EC=9C=BC=EB=A1=9C=20=EB=B3=B4=EC=9D=B4?= =?UTF-8?q?=EB=8A=94=20=EC=A0=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/schema_manager.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 43ed975f275..cef99f5f213 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -13684,6 +13684,7 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) if (error != ER_LC_UNKNOWN_CLASSNAME) { goto end; + AU_ENABLE (save); } } AU_ENABLE (save); From cfa59e35c9649dfa8a42c98426849f57fd22b9bd Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 15 Oct 2025 13:08:43 +0900 Subject: [PATCH 019/112] =?UTF-8?q?(feature/bugfix)=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/class_object.h | 2 -- src/object/schema_manager.c | 32 ++++++++++---------- src/object/schema_system_catalog_install.cpp | 2 +- src/storage/oid.c | 3 -- src/storage/oid.h | 1 - 5 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/object/class_object.h b/src/object/class_object.h index fde3e5da765..9743f9d3098 100644 --- a/src/object/class_object.h +++ b/src/object/class_object.h @@ -770,7 +770,6 @@ struct sm_class struct parser_context *virtual_query_cache; struct tr_schema_cache *triggers; /* Trigger cache */ SM_CLASS_CONSTRAINT *constraints; /* Constraint cache */ - SM_CLASS_HISTOGRAM *histograms; /* Histogram info */ const char *comment; /* table comment */ SM_CLASS_CONSTRAINT *fk_ref; /* fk ref cache */ SM_PARTITION *partition; /* partition information */ @@ -822,7 +821,6 @@ struct sm_template DB_OBJLIST *ext_references; DB_SEQ *properties; - DB_OBJLIST *histograms; int *super_id_map; /* super class id mapping table */ diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index cef99f5f213..130d6f955a8 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -13673,22 +13673,22 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) } - /* remove histogram object if exist */ - for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) - { - int save; - AU_DISABLE (save); - error = smt_check_histogram_exist_and_delete (op, att->header.name); - if (error != NO_ERROR) - { - if (error != ER_LC_UNKNOWN_CLASSNAME) - { - goto end; - AU_ENABLE (save); - } - } - AU_ENABLE (save); - } +// /* remove histogram object if exist */ +// for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) +// { +// int save; +// AU_DISABLE (save); +// error = smt_check_histogram_exist_and_delete (op, att->header.name); +// if (error != NO_ERROR) +// { +// if (error != ER_LC_UNKNOWN_CLASSNAME) +// { +// goto end; +// AU_ENABLE (save); +// } +// } +// AU_ENABLE (save); +// } /* remove auto_increment serial object if exist */ for (att = class_->ordered_attributes; att; att = att->order_link) diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index 5612a701335..fc0f25e0e33 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -2068,7 +2068,7 @@ namespace cubschema CTV_DB_HISTOGRAM_NAME, // columns { - {"class_of", CT_CLASS_NAME}, + {"class_of", "object"}, {"key_attr", format_varchar (255)}, {"data_type", "integer"}, {"histogram_type","integer"}, diff --git a/src/storage/oid.c b/src/storage/oid.c index 13cb6bae499..0ac4181b034 100644 --- a/src/storage/oid.c +++ b/src/storage/oid.c @@ -67,7 +67,6 @@ static OID oid_Authorizations_class = { 0, 0, 0 }; static OID oid_DB_root_class = { 0, 0, 0 }; static OID oid_DBServer_class = { 0, 0, 0 }; static OID oid_Synonym_class = { 0, 0, 0 }; -static OID oid_DB_histogram_class = { 0, 0, 0 }; static OID oid_Rep_Read_Tran = { 0, (short int) 0x8000, 0 }; const OID oid_Null_oid = { NULL_PAGEID, NULL_SLOTID, NULL_VOLID }; @@ -82,7 +81,6 @@ OID *oid_Serial_class_oid = &oid_Serial_class; OID *oid_Partition_class_oid = &oid_Partition_class; OID *oid_User_class_oid = &oid_User_class; OID *oid_Sp_code_class_oid = &oid_Stored_proc_code_class; -OID *oid_DB_histogram_class_oid = &oid_DB_histogram_class; const OID_CACHE_ENTRY oid_Cache[OID_CACHE_SIZE] = { {&oid_Root_class, NULL}, /* Root class is not identifiable by a name */ @@ -114,7 +112,6 @@ const OID_CACHE_ENTRY oid_Cache[OID_CACHE_SIZE] = { {&oid_DBServer_class, CT_DB_SERVER_NAME}, {&oid_Synonym_class, CT_SYNONYM_NAME}, {&oid_Stored_proc_code_class, CT_STORED_PROC_CODE_NAME}, - {&oid_DB_histogram_class, CT_DB_HISTOGRAM_NAME} }; /* diff --git a/src/storage/oid.h b/src/storage/oid.h index 09cd4798422..ea2a6fb4972 100644 --- a/src/storage/oid.h +++ b/src/storage/oid.h @@ -202,7 +202,6 @@ enum OID_CACHE_DB_SERVER_CLASS_ID, OID_CACHE_SYNONYM_CLASS_ID, OID_CACHE_STORED_PROC_CODE_CLASS_ID, - OID_CACHE_DB_HISTOGRAM_CLASS_ID, OID_CACHE_SIZE }; From 6b99e0b578e895240107e9f3591376ca77958084 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 15 Oct 2025 15:37:54 +0900 Subject: [PATCH 020/112] =?UTF-8?q?(refactor)=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC/=20=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/schema_manager.c | 44 ++++++++++++++----------------------- src/parser/semantic_check.c | 6 ++--- src/query/execute_schema.c | 8 +++---- src/storage/oid.c | 1 + 4 files changed, 24 insertions(+), 35 deletions(-) diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 130d6f955a8..c260a353e29 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -13673,22 +13673,22 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) } -// /* remove histogram object if exist */ -// for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) -// { -// int save; -// AU_DISABLE (save); -// error = smt_check_histogram_exist_and_delete (op, att->header.name); -// if (error != NO_ERROR) -// { -// if (error != ER_LC_UNKNOWN_CLASSNAME) -// { -// goto end; -// AU_ENABLE (save); -// } -// } -// AU_ENABLE (save); -// } + /* remove histogram object if exist */ + for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) + { + int save; + AU_DISABLE (save); + error = smt_check_histogram_exist_and_delete (op, att->header.name); + if (error != NO_ERROR) + { + if (error != ER_LC_UNKNOWN_CLASSNAME) + { + goto end; + AU_ENABLE (save); + } + } + AU_ENABLE (save); + } /* remove auto_increment serial object if exist */ for (att = class_->ordered_attributes; att; att = att->order_link) @@ -15514,9 +15514,7 @@ sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogr { bool set_savepoint = false; int error = NO_ERROR; - DB_AUTH auth; SM_CLASS *class_ = NULL; - DB_OBJECT *db_class = NULL; if (attr_name == NULL) { @@ -15549,13 +15547,7 @@ sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogr goto error_exit; } -// /* 통계 업데이트 | 히스토그램 정보 업데이트 하기 */ -// error = sm_update_statistics_with_modify_histogram (newmop, STATS_WITH_SAMPlING); -// if (error != NO_ERROR) -// { -// smt_quit (def); -// goto error_exit; -// } + /* TODO: Update Histogram Here */ return error; error_exit: @@ -15573,9 +15565,7 @@ sm_drop_histogram (MOP classop, const char *attr_name) { bool set_savepoint = false; int error = NO_ERROR; - DB_AUTH auth; SM_CLASS *class_ = NULL; - DB_OBJECT *db_class = NULL; if (attr_name == NULL) { diff --git a/src/parser/semantic_check.c b/src/parser/semantic_check.c index f4622972485..365be649e43 100644 --- a/src/parser/semantic_check.c +++ b/src/parser/semantic_check.c @@ -9115,14 +9115,14 @@ pt_check_create_index (PARSER_CONTEXT * parser, PT_NODE * node) static void pt_check_create_histogram (PARSER_CONTEXT * parser, PT_NODE * node) { - PT_NODE *name, *col, *col_expr; + PT_NODE *name; DB_OBJECT *db_obj; int is_partition = DB_NOT_PARTITIONED_CLASS; - /* check that there trying to create an index on a class */ + /* check that there trying to create an histogram on a class */ name = node->info.histogram.target_table_spec->info.spec.entity_name; - /* We cannot create index of a class by using synonym names. */ + /* We cannot create histogram of a class by using synonym names. */ if (db_find_synonym (name->info.name.original) != NULL) { PT_ERRORmf (parser, name, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_IS_NOT_A_CLASS, name->info.name.original); diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 46b3d06cd71..12d3b2c147e 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3886,7 +3886,7 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, char *attname = NULL; PT_NODE *cur_column = NULL; int is_partition = DB_NOT_PARTITIONED_CLASS; - DB_OBJECT *histogram_class = NULL; + /* check histogram is allowed on this class */ error = sm_partitioned_class_type (obj, &is_partition, NULL, NULL); if (error != NO_ERROR) @@ -3946,8 +3946,7 @@ int do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) { PT_NODE *cls; - DB_OBJECT *obj, *db_class; - DB_VALUE value; + DB_OBJECT *obj; int error = NO_ERROR, save; AU_DISABLE (save); CHECK_MODIFICATION_ERROR (); @@ -3988,8 +3987,7 @@ int do_drop_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) { PT_NODE *cls; - DB_OBJECT *obj, *db_class; - DB_VALUE value; + DB_OBJECT *obj; int error = NO_ERROR, save; AU_DISABLE (save); CHECK_MODIFICATION_ERROR (); diff --git a/src/storage/oid.c b/src/storage/oid.c index 0ac4181b034..4a8ab80a126 100644 --- a/src/storage/oid.c +++ b/src/storage/oid.c @@ -67,6 +67,7 @@ static OID oid_Authorizations_class = { 0, 0, 0 }; static OID oid_DB_root_class = { 0, 0, 0 }; static OID oid_DBServer_class = { 0, 0, 0 }; static OID oid_Synonym_class = { 0, 0, 0 }; + static OID oid_Rep_Read_Tran = { 0, (short int) 0x8000, 0 }; const OID oid_Null_oid = { NULL_PAGEID, NULL_SLOTID, NULL_VOLID }; From 91094370a85b4414886ce72049593f6de3c60579 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 15 Oct 2025 16:12:00 +0900 Subject: [PATCH 021/112] =?UTF-8?q?(feature:=20CBRD-26217)=20HISTOGRAM=20?= =?UTF-8?q?=EB=A7=88=EB=AC=B4=EB=A6=AC=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/schema_system_catalog_install.cpp | 6 +- src/parser/csql_grammar.y | 66 +++++++++++++++++++- src/query/execute_schema.c | 29 +++++++++ src/storage/oid.h | 1 + 4 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index fc0f25e0e33..3f8cd1600fd 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -1282,11 +1282,7 @@ namespace cubschema // authorization { // owner - Au_dba_user, - // grants - { - {Au_public_user, AU_SELECT, false} - } + Au_dba_user, {} }, // initializer nullptr diff --git a/src/parser/csql_grammar.y b/src/parser/csql_grammar.y index f66418541b2..6a13525b798 100644 --- a/src/parser/csql_grammar.y +++ b/src/parser/csql_grammar.y @@ -3163,7 +3163,7 @@ create_stmt if (node && ocs) { - PT_NODE *col, *temp; + PT_NODE *col; int arg_count = 0, prefix_col_count = 0; ocs->info.spec.entity_name = $6; PARSER_SAVE_ERR_CONTEXT (ocs, @6.buffer_pos) @@ -3178,6 +3178,38 @@ create_stmt $$ = node; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} + | CREATE /* 1 */ + { /* 2 */ + DBG_TRACE_GRAMMAR(create_stmt, | CREATE); + PT_NODE* node = parser_new_node (this_parser, PT_CREATE_HISTOGRAM); + parser_push_hint_node (node); + push_msg (MSGCAT_SYNTAX_INVALID_CREATE_HISTOGRAM); + } + HISTOGRAM /* 3 */ + { pop_msg(); } /* 4 */ + ON_ /* 5 */ + only_class_name /* 6 */ + opt_comment_spec /* 9 */ + {{ DBG_TRACE_GRAMMAR (create_stmt, | CREATE HISTOGRAM ON_ ~); + + PT_NODE *node = parser_pop_hint_node (); + PARSER_SAVE_ERR_CONTEXT (node, @$.buffer_pos) + PT_NODE *ocs = parser_new_node(this_parser, PT_SPEC); + + if (node && ocs) + { + int arg_count = 0, prefix_col_count = 0; + ocs->info.spec.entity_name = $6; + PARSER_SAVE_ERR_CONTEXT (ocs, @6.buffer_pos) + ocs->info.spec.meta_class = PT_CLASS; + node->info.histogram.target_table_spec = ocs; + node->info.histogram.target_columns = NULL; + } + + $$ = node; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} | CREATE /* 1 */ opt_or_replace /* 2 */ @@ -4866,6 +4898,38 @@ drop_stmt $$ = node; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} + | DROP /* 1 */ + { /* 2 */ + DBG_TRACE_GRAMMAR(create_stmt, | CREATE); + PT_NODE* node = parser_new_node (this_parser, PT_DROP_HISTOGRAM); + parser_push_hint_node (node); + push_msg (MSGCAT_SYNTAX_INVALID_DROP_HISTOGRAM); + } + HISTOGRAM /* 3 */ + { pop_msg(); } /* 4 */ + ON_ /* 5 */ + only_class_name /* 6 */ + opt_comment_spec /* 9 */ + {{ DBG_TRACE_GRAMMAR (create_stmt, | DROP HISTOGRAM ON_ ~); + + PT_NODE *node = parser_pop_hint_node (); + PARSER_SAVE_ERR_CONTEXT (node, @$.buffer_pos) + PT_NODE *ocs = parser_new_node(this_parser, PT_SPEC); + + if (node && ocs) + { + int arg_count = 0, prefix_col_count = 0; + ocs->info.spec.entity_name = $6; + PARSER_SAVE_ERR_CONTEXT (ocs, @6.buffer_pos) + ocs->info.spec.meta_class = PT_CLASS; + node->info.histogram.target_table_spec = ocs; + node->info.histogram.target_columns = NULL; + } + + $$ = node; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} | DROP FUNCTION procedure_or_function_name_list {{ DBG_TRACE_GRAMMAR(drop_stmt, | DROP FUNCTION procedure_or_function_name_list); diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 12d3b2c147e..eebd9e2bb42 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3904,6 +3904,35 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, histogram_type = histogram_info->histogram_type; bucket_count = histogram_info->bucket_count; cur_column = histogram_info->target_columns; + + if (nnames == 0) + { + SM_ATTRIBUTE *att; + SM_CLASS *class_ = NULL; + error = au_fetch_class (obj, &class_, AU_FETCH_READ, AU_SELECT); + for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) + { + attname = (char *) att->header.name; + data_type = 0; /* TODO: data_type */ + if (do_histogram == DO_HISTOGRAM_DROP) + { + error = sm_drop_histogram (obj, attname); + if (error != NO_ERROR) + { + return error; + } + } + else + { + error = sm_add_histogram (obj, attname, data_type, histogram_type, bucket_count); + if (error != NO_ERROR) + { + return error; + } + } + } + } + for (int i = 0; i < nnames; i++) { attname = (char *) cur_column->info.name.original; diff --git a/src/storage/oid.h b/src/storage/oid.h index ea2a6fb4972..5d4acb935c9 100644 --- a/src/storage/oid.h +++ b/src/storage/oid.h @@ -202,6 +202,7 @@ enum OID_CACHE_DB_SERVER_CLASS_ID, OID_CACHE_SYNONYM_CLASS_ID, OID_CACHE_STORED_PROC_CODE_CLASS_ID, + OID_CACHE_SIZE }; From 8a1b05eb3df150a4fece36cb997ccd680048f05b Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 15 Oct 2025 16:25:11 +0900 Subject: [PATCH 022/112] (bugfix) histogram not exist error fix --- src/object/schema_manager.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index c260a353e29..0f86e2177c2 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -13683,10 +13683,11 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) { if (error != ER_LC_UNKNOWN_CLASSNAME) { - goto end; AU_ENABLE (save); + goto end; } } + er_clear (); AU_ENABLE (save); } From b884cfeaba3a528da10fc8702023ea10c8cfaa46 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 15 Oct 2025 16:38:25 +0900 Subject: [PATCH 023/112] (bugfix) --- src/object/schema_manager.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 0f86e2177c2..b6df58b878d 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -13687,7 +13687,6 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) goto end; } } - er_clear (); AU_ENABLE (save); } From 224352081f731cecfaf8f68dd4935e8c2e65e8b6 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 17 Oct 2025 18:33:25 +0900 Subject: [PATCH 024/112] =?UTF-8?q?(bugfix):=20CBRD-26217:=20histogram=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EC=8B=9C=20=EC=97=90=EB=9F=AC=EB=A5=BC=20?= =?UTF-8?q?=EC=A7=81=EC=A0=91=20=ED=91=9C=EC=8B=9C=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/schema_manager.c | 4 ++-- src/object/schema_template.c | 15 +++++++++------ src/object/schema_template.h | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index b6df58b878d..377463430f7 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -13678,7 +13678,7 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) { int save; AU_DISABLE (save); - error = smt_check_histogram_exist_and_delete (op, att->header.name); + error = smt_check_histogram_exist_and_delete (op, att->header.name, true); if (error != NO_ERROR) { if (error != ER_LC_UNKNOWN_CLASSNAME) @@ -15586,7 +15586,7 @@ sm_drop_histogram (MOP classop, const char *attr_name) goto error_exit; } - error = smt_check_histogram_exist_and_delete (classop, attr_name); + error = smt_check_histogram_exist_and_delete (classop, attr_name, false); if (error != NO_ERROR) { goto error_exit; diff --git a/src/object/schema_template.c b/src/object/schema_template.c index c57a7a7aeea..6a47dd773cb 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -1999,7 +1999,7 @@ smt_check_histogram_exist (MOP classop, const char *attr_name) } int -smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name) +smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name, bool no_error_if_not_found) { int error = NO_ERROR; DB_OBJECT *histogram_class, *histogram_obj = NULL; @@ -2023,11 +2023,14 @@ smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name) histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_READ); if (histogram_obj == NULL) { - error = ER_LC_UNKNOWN_CLASSNAME; - char error_histogram[256]; - sprintf (error_histogram, "histogram of %s(%s)", sm_get_ch_name (classop), attr_name); - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, error_histogram); - goto end; + if (!no_error_if_not_found) + { + error = ER_LC_UNKNOWN_CLASSNAME; + char error_histogram[256]; + sprintf (error_histogram, "histogram of %s(%s)", sm_get_ch_name (classop), attr_name); + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, error_histogram); + goto end; + } } else { diff --git a/src/object/schema_template.h b/src/object/schema_template.h index 240349d40ef..ec12130e099 100644 --- a/src/object/schema_template.h +++ b/src/object/schema_template.h @@ -169,7 +169,7 @@ extern int smt_check_index_exist (SM_TEMPLATE * template_, char **out_shared_con const char **att_names, const int *asc_desc, const SM_PREDICATE_INFO * filter_index, const SM_FUNCTION_INFO * function_index); extern int smt_check_histogram_exist (MOP classop, const char *attr_name); -extern int smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name); +extern int smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name, bool no_error_if_not_found); #if defined(ENABLE_UNUSED_FUNCTION) extern void smt_downcase_all_class_info (void); From 67feccce6e4d1fba8b7b60d739a4693d3ff8c42a Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 21 Oct 2025 08:52:24 +0900 Subject: [PATCH 025/112] =?UTF-8?q?(bugfix)=20MIDKEY=EC=9D=98=20=EA=B0=9C?= =?UTF-8?q?=EC=88=98=EA=B0=80=20=EB=AC=B4=EC=A1=B0=EA=B1=B4=201=EA=B0=9C?= =?UTF-8?q?=EB=A1=9C=20=EA=B3=A0=EC=A0=95=EB=90=98=EA=B8=B0=20=EB=95=8C?= =?UTF-8?q?=EB=AC=B8=EC=97=90,=20packed=20value=EA=B0=80=20=EB=9E=9C?= =?UTF-8?q?=EB=8D=A4=EC=9C=BC=EB=A1=9C=20=EA=B9=A8=EC=A7=80=EB=8A=94=20?= =?UTF-8?q?=ED=98=84=EC=83=81=20=EB=B0=9C=EC=83=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/object_accessor.c | 6 ++++- src/object/object_representation.c | 1 + src/object/schema_manager.c | 38 +++++++++++++++++++++++------- src/object/schema_template.c | 3 +-- src/query/execute_statement.c | 7 +++++- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/object/object_accessor.c b/src/object/object_accessor.c index 85634c6cd12..d2f4c677e4a 100644 --- a/src/object/object_accessor.c +++ b/src/object/object_accessor.c @@ -3780,7 +3780,7 @@ obj_find_multi_attr (MOP op, int size, const char *attr_names[], const DB_VALUE } result = - btree_find_multi_uniques (ws_oid (obj_tmpl->classobj), obj_tmpl->pruning_type, unique_btid, unique_key, size, + btree_find_multi_uniques (ws_oid (obj_tmpl->classobj), obj_tmpl->pruning_type, unique_btid, unique_key, 1, op_type, &oids, &oid_count); if (result == BTREE_ERROR_OCCURRED) @@ -3797,6 +3797,10 @@ obj_find_multi_attr (MOP op, int size, const char *attr_names[], const DB_VALUE } end_find: + if (obj_tmpl != NULL) + { + dbt_abort_object (obj_tmpl); + } if (unique_key != NULL) { pr_clear_value (unique_key); diff --git a/src/object/object_representation.c b/src/object/object_representation.c index 4bd06a2c5bd..0ede6f0d428 100644 --- a/src/object/object_representation.c +++ b/src/object/object_representation.c @@ -4866,6 +4866,7 @@ or_put_value (OR_BUF * buf, DB_VALUE * value, int collapse_null, int include_dom dbval_type = DB_VALUE_DOMAIN_TYPE (value); type = pr_type_from_id (dbval_type); + assert (dbval_type <= DB_TYPE_LAST); if (type == NULL) { diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 377463430f7..46be70dc0cf 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -13572,6 +13572,11 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) char *fk_name = NULL; const char *table_name; MOP save_user, owner; + DB_OBJECT *histogram_class, *histogram_obj = NULL; + DB_VALUE value[2]; + DB_VALUE *value_ptrs[2] = { &value[0], &value[1] }; + const char *search_attrs[2] = { "class_of", "key_attr" }; + int au_save; if (op == NULL) { @@ -13672,23 +13677,38 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) } } - - /* remove histogram object if exist */ + histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); + if (histogram_class == NULL) + { + error = ER_BO_MISSING_OR_INVALID_CATALOG; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + goto end; + } + AU_DISABLE (au_save); for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) { - int save; - AU_DISABLE (save); - error = smt_check_histogram_exist_and_delete (op, att->header.name, true); - if (error != NO_ERROR) + + /* class_of, key_attr */ + db_make_object (&value[0], op); + db_make_string (&value[1], att->header.name); + histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_WRITE); + + if (histogram_obj != NULL) { - if (error != ER_LC_UNKNOWN_CLASSNAME) + error = db_drop (histogram_obj); + db_value_clear (&value[0]); + db_value_clear (&value[1]); + if (error != NO_ERROR) { - AU_ENABLE (save); + AU_ENABLE (au_save); goto end; } + } - AU_ENABLE (save); + db_value_clear (&value[0]); + db_value_clear (&value[1]); } + AU_ENABLE (au_save); /* remove auto_increment serial object if exist */ for (att = class_->ordered_attributes; att; att = att->order_link) diff --git a/src/object/schema_template.c b/src/object/schema_template.c index 6a47dd773cb..bc663da2218 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -2006,7 +2006,6 @@ smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name, bool n DB_VALUE value[2]; DB_VALUE *value_ptrs[2] = { &value[0], &value[1] }; const char *search_attrs[2] = { "class_of", "key_attr" }; - histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); if (histogram_class == NULL) { @@ -2020,7 +2019,7 @@ smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name, bool n db_make_object (&value[0], classop); db_make_string (&value[1], attr_name); - histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_READ); + histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_WRITE); if (histogram_obj == NULL) { if (!no_error_if_not_found) diff --git a/src/query/execute_statement.c b/src/query/execute_statement.c index c5617db728a..c47d8dcb84c 100644 --- a/src/query/execute_statement.c +++ b/src/query/execute_statement.c @@ -11966,6 +11966,7 @@ do_create_midxkey_for_constraint (DB_OTMPL * tmpl, SM_CLASS_CONSTRAINT * constra } attr_dom = tp_domain_copy ((*attr)->domain, false); + assert (attr_dom->type->id <= DB_TYPE_LAST); if (attr_dom == NULL) { error = ER_FAILED; @@ -12041,11 +12042,13 @@ do_create_midxkey_for_constraint (DB_OTMPL * tmpl, SM_CLASS_CONSTRAINT * constra error = ER_FAILED; goto error_return; } - midxkey.domain = tp_domain_cache (midxkey.domain); + //midxkey.domain = tp_domain_cache (midxkey.domain); + assert (midxkey.domain->type->id <= DB_TYPE_LAST); midxkey.min_max_val.position = -1; midxkey.min_max_val.type = MIN_COLUMN; error = db_make_midxkey (key, &midxkey); + assert (key->domain.general_info.type <= DB_TYPE_LAST); if (error != NO_ERROR) { goto error_return; @@ -12054,6 +12057,7 @@ do_create_midxkey_for_constraint (DB_OTMPL * tmpl, SM_CLASS_CONSTRAINT * constra return NO_ERROR; error_return: + assert (false); if (midxkey.buf != NULL) { db_private_free (NULL, midxkey.buf); @@ -12069,6 +12073,7 @@ do_create_midxkey_for_constraint (DB_OTMPL * tmpl, SM_CLASS_CONSTRAINT * constra return error; } + /* * do_create_odku_stmt () - create an UPDATE statement for ON DUPLICATE KEY * UPDATE node From b0c3e27e8c485d9a2cacd78e44d4d924d152a734 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 21 Oct 2025 09:19:30 +0900 Subject: [PATCH 026/112] =?UTF-8?q?(review)=20ha=20log=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/query/execute_statement.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/query/execute_statement.c b/src/query/execute_statement.c index c47d8dcb84c..9f870ffdc62 100644 --- a/src/query/execute_statement.c +++ b/src/query/execute_statement.c @@ -16168,6 +16168,14 @@ do_replicate_statement (PARSER_CONTEXT * parser, PT_NODE * statement) repl_stmt.statement_type = CUBRID_STMT_DROP_INDEX; break; + case PT_CREATE_HISTOGRAM: + repl_stmt.statement_type = CUBRID_STMT_CREATE_HISTOGRAM; + break; + + case PT_DROP_HISTOGRAM: + repl_stmt.statement_type = CUBRID_STMT_DROP_HISTOGRAM; + break; + case PT_CREATE_SERIAL: repl_stmt.statement_type = CUBRID_STMT_CREATE_SERIAL; break; From 65f85265c77856eef7e5e5869703e6411a315600 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 21 Oct 2025 13:58:00 +0900 Subject: [PATCH 027/112] =?UTF-8?q?(bugfix)=20unload=5Fobject.c:=20catalog?= =?UTF-8?q?=20class=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/executables/unload_object.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/executables/unload_object.c b/src/executables/unload_object.c index cd4db0bee0d..a62d32b6402 100644 --- a/src/executables/unload_object.c +++ b/src/executables/unload_object.c @@ -140,6 +140,7 @@ static const char *prohibited_classes[] = { CT_DUAL_NAME, CT_DB_SERVER_NAME, CT_SYNONYM_NAME, + CT_DB_HISTOGRAM_NAME, /* catalog vclasses */ CTV_CLASS_NAME, CTV_SUPER_CLASS_NAME, @@ -161,6 +162,7 @@ static const char *prohibited_classes[] = { CTV_DB_CHARSET_NAME, CTV_DB_SERVER_NAME, CTV_SYNONYM_NAME, + CTV_DB_HISTOGRAM_NAME, NULL }; From 05ff54ee590aedd0c6f98d0e47b02f62f0ed6ee1 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 29 Oct 2025 18:40:59 +0900 Subject: [PATCH 028/112] =?UTF-8?q?(db=20histogram=20reader)=20class=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=EB=90=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_reader.cpp | 166 +++++++++++++++++++++++++++++ src/histogram/histogram_reader.hpp | 99 +++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 src/histogram/histogram_reader.cpp create mode 100644 src/histogram/histogram_reader.hpp diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp new file mode 100644 index 00000000000..6f448588451 --- /dev/null +++ b/src/histogram/histogram_reader.cpp @@ -0,0 +1,166 @@ +#include "histogram_reader.hpp" +#include +#include +#include "error_manager.h" +#include "object_representation.h" + +namespace hist +{ + const std::size_t BUCKET_RECORD_SIZE = 8 + 8 + 8; // data + cumulative + approx_ndv + // ---------- get_value template specialization ---------- + template<> + std::int32_t HistogramReader::get_value (const void *ptr) const + { + return OR_GET_INT (ptr); + } + + template<> + std::int64_t HistogramReader::get_value (const void *ptr) const + { + std::int64_t value; + OR_GET_INT64 (ptr, &value); + return value; + } + + template<> + double HistogramReader::get_value (const void *ptr) const + { + double value; + OR_GET_DOUBLE (ptr, &value); + return value; + } + + template<> + std::uint32_t HistogramReader::get_value (const void *ptr) const + { + return static_cast (OR_GET_INT (ptr)); + } + +// ---------- reset ---------- + int HistogramReader::reset (std::string_view blob) + { + int error = NO_ERROR; + blob_ = blob; + if (blob_.size() < sizeof (HeaderV1)) + { + error = ER_FAILED; + return error; + } + + /* read header */ + const auto *H = reinterpret_cast (blob_.data()); + if (std::string_view (H->magic, 4) != "HST1") + { + error = ER_FAILED; + return error; + } + if (get_value (&H->version) != 1) + { + error = ER_FAILED; + return error; + } + + nb_ = get_value (&H->nbuckets); + str_size_ = get_value (&H->str_size); + type_ = get_value (&H->type); + total_size_ = get_value (&H->total_size); + assert (total_size_ == blob_.size()); + + /* read index table for O(1) access to bucket record */ + const char *p = blob_.data() + sizeof (HeaderV1); + const char *end = blob_.data() + blob_.size(); + + index_base_ = reinterpret_cast (p); + p += sizeof (std::uint32_t) * nb_; + + bucket_area_begin_ = p; + + /* find the last record */ + std::uint32_t max_off = 0; + for (std::uint32_t i = 0; i < nb_; ++i) + { + max_off = std::max (max_off, get_value (index_base_ + i)); + } + const char *last = bucket_area_begin_ + max_off; + + if (last + BUCKET_RECORD_SIZE > end) + { + return ER_FAILED; + } + buckets_end_ = last + BUCKET_RECORD_SIZE; // data + cumulative + if (buckets_end_ + str_size_ != end) + { + return ER_FAILED; + } + + /* read string blob */ + str_blob_ = std::string_view{buckets_end_, static_cast (str_size_)}; + } + +// ---------- record navigation ---------- + const char *HistogramReader::bucket_rec (std::uint32_t i) const + { + assert (i < nb_); + std::uint32_t off = get_value (index_base_ + i); + const char *rec = bucket_area_begin_ + off; + assert (rec >= bucket_area_begin_ && rec < buckets_end_); + return rec; + } + + const char *HistogramReader::bucket_hi_value_ptr (std::uint32_t i) const + { + return bucket_rec (i); + } + +// ---------- access ---------- + double HistogramReader::bucket_cumulative (std::uint32_t i) const + { + const char *p = bucket_rec (i) + 8; + return get_value (p); + } + + double HistogramReader::bucket_approx_ndv (std::uint32_t i) const + { + assert (i < nb_); + const char *rec = bucket_rec (i); + const char *p = rec + 16; + return get_value (p); + } + + double HistogramReader::bucket_rows (std::uint32_t i) const + { + assert (i < nb_); + const double cur = bucket_cumulative (i); + const double prev = (i == 0) ? 0.0 : bucket_cumulative (i - 1); + return cur - prev; + } + +// ---------- bucket_hi template specialization ---------- + template<> + std::int64_t HistogramReader::bucket_hi (std::uint32_t i) const + { + return get_value(bucket_hi_value_ptr(i)); + } + + template<> + double HistogramReader::bucket_hi (std::uint32_t i) const + { + return get_value(bucket_hi_value_ptr(i)); + } + + template<> + std::string_view HistogramReader::bucket_hi (std::uint32_t i) const + { + const char *p = bucket_hi_value_ptr(i); + std::uint32_t len32 = get_value(p); + std::uint32_t off32 = get_value(p + 4); + + if (len32 <= 4) // inline data + { + return std::string_view{ p+4, static_cast(len32-4) }; + } + assert (off32 + len32 <= str_size_); + return std::string_view{str_blob_.data() + off32, static_cast(len32)}; + } + +} // namespace hist diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp new file mode 100644 index 00000000000..fe44c5badfd --- /dev/null +++ b/src/histogram/histogram_reader.hpp @@ -0,0 +1,99 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include "error_manager.h" +#include + +namespace hist +{ + +// ---- Flat binary layout (LE) ---- +// [Header] [Index table] [Buckets area] [String blob....] +// +// Header (fixed): +// magic : 'HST2' (4B) +// version : u32 (1) +// nbuckets : u32 +// str_size : u32 +// +// Index table (fixed-size): +// offsets[nbuckets] : u32 each, offset of bucket i record +// relative to bucket_area_begin (first record is usually 0) +// +// Buckets area (variable): +// For each i in [0, nbuckets): +// data : 8B (ptr or Value) +// cumulative: f64 +// approx_ndv: f64 (present only if has_ndv==1) +// +// String blob (trailing): +// str_size bytes; bucket string data points to (len, off) inside this blob. + + // 실제 타입을 사용하는 템플릿 + using HistogramTypes = std::variant; + using Type = std::uint32_t; + struct HeaderV1 + { + char magic[4]; // "HST1" + std::uint32_t version; + std::uint32_t nbuckets; + std::uint32_t str_size; + Type type; // Not Same to DB Type + std::uint32_t total_size; // total size of the histogram + }; + + class HistogramReader + { + public: + HistogramReader() = default; + int create (HistogramReader &reader, std::string_view blob) + { + int error = reader.reset (blob); + return error; + } + int reset (std::string_view blob); + + std::uint64_t bucket_count() const noexcept + { + return nb_; + } + std::uint64_t total_rows() const + { + return nb_ ? bucket_cumulative (nb_ - 1) : 0; + } + + double bucket_cumulative (std::uint32_t i) const; + double bucket_approx_ndv (std::uint32_t i) const; + + template + T bucket_hi (std::uint32_t i) const; + + double bucket_rows (std::uint32_t i) const; + + private: + template + T get_value (const void *ptr) const; + + const char *bucket_rec (std::uint32_t i) const; + const char *bucket_hi_value_ptr (std::uint32_t i) const; + + private: + std::string_view blob_{}; + std::string_view str_blob_{}; + const char *bucket_area_begin_ = nullptr; + const char *buckets_end_ = nullptr; + const std::uint32_t *index_base_ = nullptr; + + std::uint32_t nb_ = 0; + std::uint32_t str_size_ = 0; + Type type_ = 0; + std::uint32_t total_size_ = 0; + }; + + +} // namespace hist From 3f6d266d96d978a0d06e2b056a7bc518869b832e Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 29 Oct 2025 19:29:37 +0900 Subject: [PATCH 029/112] =?UTF-8?q?(=EC=A3=BC=EC=84=9D=EC=88=98=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_reader.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index fe44c5badfd..13774c49e83 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -27,7 +27,7 @@ namespace hist // // Buckets area (variable): // For each i in [0, nbuckets): -// data : 8B (ptr or Value) +// data_hi : 8B (ptr or Value) // cumulative: f64 // approx_ndv: f64 (present only if has_ndv==1) // From 8fbee8ff7fba79b548ed474fca3b443030422ca9 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 30 Oct 2025 13:30:02 +0900 Subject: [PATCH 030/112] (histogram builder) add histogram builder class --- src/histogram/histogram_builder.cpp | 143 ++++++++++++++++++++++++++++ src/histogram/histogram_builder.hpp | 35 +++++++ src/histogram/histogram_query.sql | 39 ++++++++ src/histogram/histogram_reader.cpp | 33 +++---- src/histogram/histogram_reader.hpp | 16 ++-- 5 files changed, 236 insertions(+), 30 deletions(-) create mode 100644 src/histogram/histogram_builder.cpp create mode 100644 src/histogram/histogram_builder.hpp create mode 100644 src/histogram/histogram_query.sql diff --git a/src/histogram/histogram_builder.cpp b/src/histogram/histogram_builder.cpp new file mode 100644 index 00000000000..cc660f7dc90 --- /dev/null +++ b/src/histogram/histogram_builder.cpp @@ -0,0 +1,143 @@ +#include "histogram_builder.hpp" +#include "histogram_reader.hpp" +#include +#include +#include "object_domain.h" + +namespace hist +{ + + // Forward declarations of template specializations used below + template<> void HistogramBuilder::write (char *&dest, std::int32_t v); + template<> void HistogramBuilder::write (char *&dest, std::int64_t v); + template<> void HistogramBuilder::write (char *&dest, double v); + template<> void HistogramBuilder::write (char *&dest, std::string v); + + void HistogramBuilder::add (HistogramTypes hi, double cumulative, double approx_ndv) + { + assert (cumulative >= 0.0); + buckets_.push_back (Bucket{hi, cumulative, approx_ndv}); + } + + char *HistogramBuilder::build (THREAD_ENTRY *thread_p, DB_TYPE type) + { + // ---- precompute record sizes ---- + const std::uint32_t bucket_area_size = hist::BUCKET_RECORD_SIZE * buckets_.size(); + + // ---- header ---- + HeaderV1 H{}; + std::memcpy (H.magic, "HST1", 4); + H.version = ntohl (1); + H.nbuckets = ntohl (static_cast (buckets_.size())); + H.type = ntohl (static_cast (type)); + H.str_size = 0; // Fix Later + H.total_size = 0; // Fix Later + + char *buffer = static_cast (db_private_alloc (thread_p, sizeof (H) + bucket_area_size)); // records + char *end_buffer = buffer + sizeof (H) + bucket_area_size; + char *buffer_ptr = buffer + sizeof (H); + char *str_blob_ptr; + // buckets area + for (const auto &b : buckets_) + { + const auto &bucket = b; + switch (type) + { + case DB_TYPE_INTEGER: + write (buffer_ptr, std::get (bucket.data_hi)); + break; + case DB_TYPE_DOUBLE: + write (buffer_ptr, std::get (bucket.data_hi)); + break; + case DB_TYPE_BIGINT: + write (buffer_ptr, std::get (bucket.data_hi)); + break; + case DB_TYPE_STRING: + write (buffer_ptr, std::get (bucket.data_hi)); + break; + default: + // not_implemented + assert (false); + break; + } + write (buffer_ptr, bucket.cumulative); + write (buffer_ptr, bucket.approx_ndv); + } + + assert (buffer_ptr != end_buffer); + + // build string blob + if (cur_str_off_ > 0) + { + assert (DB_TYPE_STRING == type); + str_blob_ptr = static_cast (db_private_alloc (thread_p, cur_str_off_)); + char *str_blob_ptr_end = str_blob_ptr + cur_str_off_; + for (const auto &b : buckets_) + { + const auto &bucket = b; + if (DB_TYPE_STRING == type) + { + if ( std::get (bucket.data_hi).length() > 4) + { + memcpy (str_blob_ptr, std::get (bucket.data_hi).data(), std::get (bucket.data_hi).length()); + str_blob_ptr += std::get (bucket.data_hi).length(); + } + } + } + // write string + assert (str_blob_ptr == str_blob_ptr_end); + buffer = static_cast (db_private_realloc (thread_p, buffer, sizeof (H) + bucket_area_size + cur_str_off_)); + memcpy (buffer + sizeof (H) + bucket_area_size, str_blob_ptr, cur_str_off_); + end_buffer += cur_str_off_; + db_private_free (thread_p, str_blob_ptr); + } + + H.str_size = ntohl (cur_str_off_); + H.total_size = ntohl (sizeof (H) + bucket_area_size + cur_str_off_); + memcpy (buffer, &H, sizeof (H)); + assert (buffer - end_buffer == H.total_size); + + // write header + return buffer; + } + +// ---------- endian writers for buffer ---------- + template<> + void HistogramBuilder::write (char *&dest, std::int32_t v) + { + OR_PUT_INT (dest, v); + dest += OR_INT64_SIZE; + } + + template<> + void HistogramBuilder::write (char *&dest, std::int64_t v) + { + OR_PUT_INT64 (dest, v); + dest += OR_INT64_SIZE; + } + + template<> + void HistogramBuilder::write (char *&dest, double v) + { + OR_PUT_DOUBLE (dest, v); + dest += OR_DOUBLE_SIZE; + } + + template<> + void HistogramBuilder::write (char *&dest, std::string v) + { + // write length and offset or inline data + OR_PUT_INT (dest, v.length()); + dest += OR_INT_SIZE; + if (v.length() <= 4) + { + memcpy (dest, v.data(), v.length()); + } + else + { + OR_PUT_INT (dest, cur_str_off_); + cur_str_off_ += v.length(); + } + dest += OR_INT_SIZE; + } +} // namespace hist diff --git a/src/histogram/histogram_builder.hpp b/src/histogram/histogram_builder.hpp new file mode 100644 index 00000000000..a0ed8538f6d --- /dev/null +++ b/src/histogram/histogram_builder.hpp @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include "histogram_reader.hpp" +#include "object_representation.h" + +namespace hist +{ + + class HistogramBuilder + { + public: + void add (HistogramTypes hi, double cumulative, double approx_ndv = std::numeric_limits::quiet_NaN()); + char *build (THREAD_ENTRY *thread_p, DB_TYPE type); + + private: + struct Bucket + { + HistogramTypes data_hi; + double cumulative; + double approx_ndv; + }; + + HeaderV1 header_; + std::vector buckets_; + std::int32_t cur_str_off_ = 0; + + // endian writers + template + void write (char *&dest, T v); + }; + +} // namespace histo diff --git a/src/histogram/histogram_query.sql b/src/histogram/histogram_query.sql new file mode 100644 index 00000000000..321c2ff6576 --- /dev/null +++ b/src/histogram/histogram_query.sql @@ -0,0 +1,39 @@ +WITH src AS ( + /* NULL 제외 + 샘플링(전수면 WHERE RAND()<... 제거) */ + SELECT /*+ RECOMPILE */ + t. /*COLUMN*/ AS val + FROM /*TABLE*/ AS t + WHERE t. /*COLUMN*/ IS NOT NULL + AND RAND() < /*SAMPLE_RATIO*/ -- 예: 0.02 (2%). 전수면 이 줄 삭제 +), +ranked AS ( + SELECT + val, + ROW_NUMBER() OVER (ORDER BY val) AS rn, + COUNT(*) OVER () AS n + FROM src +), +bucketed AS ( + SELECT + CAST(FLOOR((/*BUCKETS*/ * (rn - 1)) / n) AS INT) AS bid, -- 0..B-1 + val + FROM ranked +), +agg AS ( + SELECT + bid, + MAX(val) AS endpoint, -- 버킷 상한(hi) + COUNT(*) AS rows_in_bucket, + COUNT(DISTINCT val) AS approx_ndv -- 샘플 기준 NDV + FROM bucketed + GROUP BY bid +) +SELECT + bid, + endpoint, + rows_in_bucket, + SUM(rows_in_bucket) OVER (ORDER BY bid + ROWS UNBOUNDED PRECEDING) AS cumulative, + approx_ndv +FROM agg +ORDER BY bid; \ No newline at end of file diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index 6f448588451..c0b56a302de 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -6,7 +6,6 @@ namespace hist { - const std::size_t BUCKET_RECORD_SIZE = 8 + 8 + 8; // data + cumulative + approx_ndv // ---------- get_value template specialization ---------- template<> std::int32_t HistogramReader::get_value (const void *ptr) const @@ -62,7 +61,7 @@ namespace hist nb_ = get_value (&H->nbuckets); str_size_ = get_value (&H->str_size); - type_ = get_value (&H->type); + type_ = get_value (&H->type); total_size_ = get_value (&H->total_size); assert (total_size_ == blob_.size()); @@ -70,19 +69,13 @@ namespace hist const char *p = blob_.data() + sizeof (HeaderV1); const char *end = blob_.data() + blob_.size(); - index_base_ = reinterpret_cast (p); - p += sizeof (std::uint32_t) * nb_; bucket_area_begin_ = p; /* find the last record */ - std::uint32_t max_off = 0; - for (std::uint32_t i = 0; i < nb_; ++i) - { - max_off = std::max (max_off, get_value (index_base_ + i)); - } + std::uint32_t max_off = BUCKET_RECORD_SIZE*nb_; const char *last = bucket_area_begin_ + max_off; - + if (last + BUCKET_RECORD_SIZE > end) { return ER_FAILED; @@ -101,7 +94,7 @@ namespace hist const char *HistogramReader::bucket_rec (std::uint32_t i) const { assert (i < nb_); - std::uint32_t off = get_value (index_base_ + i); + std::uint32_t off = i*BUCKET_RECORD_SIZE; const char *rec = bucket_area_begin_ + off; assert (rec >= bucket_area_begin_ && rec < buckets_end_); return rec; @@ -139,28 +132,28 @@ namespace hist template<> std::int64_t HistogramReader::bucket_hi (std::uint32_t i) const { - return get_value(bucket_hi_value_ptr(i)); + return get_value (bucket_hi_value_ptr (i)); } template<> - double HistogramReader::bucket_hi (std::uint32_t i) const + double HistogramReader::bucket_hi (std::uint32_t i) const { - return get_value(bucket_hi_value_ptr(i)); + return get_value (bucket_hi_value_ptr (i)); } template<> std::string_view HistogramReader::bucket_hi (std::uint32_t i) const { - const char *p = bucket_hi_value_ptr(i); - std::uint32_t len32 = get_value(p); - std::uint32_t off32 = get_value(p + 4); - + const char *p = bucket_hi_value_ptr (i); + std::uint32_t len32 = get_value (p); + std::uint32_t off32 = get_value (p + 4); + if (len32 <= 4) // inline data { - return std::string_view{ p+4, static_cast(len32-4) }; + return std::string_view{ p+4, static_cast (len32-4) }; } assert (off32 + len32 <= str_size_); - return std::string_view{str_blob_.data() + off32, static_cast(len32)}; + return std::string_view{str_blob_.data() + off32, static_cast (len32)}; } } // namespace hist diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index 13774c49e83..cddd62ec312 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -1,4 +1,3 @@ -#pragma once #include #include #include @@ -8,7 +7,7 @@ #include #include "error_manager.h" #include - +#include "dbtype.h" namespace hist { @@ -33,17 +32,15 @@ namespace hist // // String blob (trailing): // str_size bytes; bucket string data points to (len, off) inside this blob. - - // 실제 타입을 사용하는 템플릿 - using HistogramTypes = std::variant; - using Type = std::uint32_t; + constexpr std::uint32_t BUCKET_RECORD_SIZE = 8 + 8 + 8; // data + cumulative + approx_ndv + using HistogramTypes = std::variant; struct HeaderV1 { char magic[4]; // "HST1" std::uint32_t version; std::uint32_t nbuckets; std::uint32_t str_size; - Type type; // Not Same to DB Type + std::uint32_t type; // Not Same to DB Type std::uint32_t total_size; // total size of the histogram }; @@ -72,7 +69,7 @@ namespace hist template T bucket_hi (std::uint32_t i) const; - + double bucket_rows (std::uint32_t i) const; private: @@ -87,12 +84,11 @@ namespace hist std::string_view str_blob_{}; const char *bucket_area_begin_ = nullptr; const char *buckets_end_ = nullptr; - const std::uint32_t *index_base_ = nullptr; std::uint32_t nb_ = 0; std::uint32_t str_size_ = 0; - Type type_ = 0; std::uint32_t total_size_ = 0; + TypeIndex type_ = DB_TYPE_UNKNOWN; }; From 83d4be0daadbd191acf451d59fd6875b83aa5803 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 31 Oct 2025 15:00:02 +0900 Subject: [PATCH 031/112] (build) --- CMakeLists.txt | 2 + cs/CMakeLists.txt | 12 ++++ src/histogram/histogram_builder.cpp | 8 --- src/histogram/histogram_cl.c | 96 +++++++++++++++++++++++++++++ src/histogram/histogram_cl.h | 44 +++++++++++++ src/histogram/histogram_query.sql | 60 +++++++++--------- src/histogram/histogram_reader.hpp | 5 +- 7 files changed, 186 insertions(+), 41 deletions(-) create mode 100644 src/histogram/histogram_cl.c create mode 100644 src/histogram/histogram_cl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bbcad83d632..e676169f359 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -403,6 +403,7 @@ set(PARALLEL_QUERY_DIR ${CMAKE_SOURCE_DIR}/src/query/parallel) set(PARALLEL_HASH_JOIN_DIR ${CMAKE_SOURCE_DIR}/src/query/parallel/px_hash_join) set(PARALLEL_HEAP_SCAN_DIR ${CMAKE_SOURCE_DIR}/src/query/parallel/px_heap_scan) set(PARALLEL_QUERY_EXECUTE_DIR ${CMAKE_SOURCE_DIR}/src/query/parallel/px_query_execute) +set(HISTOGRAM_DIR ${CMAKE_SOURCE_DIR}/src/histogram) include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories( @@ -434,6 +435,7 @@ include_directories( src/query/parallel/px_heap_scan src/query/parallel src/query/parallel/px_query_execute + src/histogram ) if(WITH_CCI) include_directories( diff --git a/cs/CMakeLists.txt b/cs/CMakeLists.txt index c3d3b49ff11..5b5ea0f4497 100644 --- a/cs/CMakeLists.txt +++ b/cs/CMakeLists.txt @@ -426,6 +426,18 @@ set(PARALLEL_QUERY_EXECUTE_HEADERS ${PARALLEL_QUERY_EXECUTE_DIR}/px_query_checker.hpp ) +set (HISTOGRAM_SOURCES + ${HISTOGRAM_DIR}/histogram_cl.c + ${HISTOGRAM_DIR}/histogram_builder.cpp + ${HISTOGRAM_DIR}/histogram_reader.cpp + ) + +set (HISTOGRAM_HEADERS + ${HISTOGRAM_DIR}/histogram_cl.h + ${HISTOGRAM_DIR}/histogram_builder.hpp + ${HISTOGRAM_DIR}/histogram_reader.hpp + ) + list(APPEND CONNECTION_SOURCES ${CONNECTION_DIR}/heartbeat.c) if(UNIX) list(APPEND EXECUTABLE_SOURCES ${EXECUTABLES_DIR}/checksumdb.c) diff --git a/src/histogram/histogram_builder.cpp b/src/histogram/histogram_builder.cpp index cc660f7dc90..89ef25f33b0 100644 --- a/src/histogram/histogram_builder.cpp +++ b/src/histogram/histogram_builder.cpp @@ -1,18 +1,10 @@ #include "histogram_builder.hpp" #include "histogram_reader.hpp" #include -#include #include "object_domain.h" namespace hist { - - // Forward declarations of template specializations used below - template<> void HistogramBuilder::write (char *&dest, std::int32_t v); - template<> void HistogramBuilder::write (char *&dest, std::int64_t v); - template<> void HistogramBuilder::write (char *&dest, double v); - template<> void HistogramBuilder::write (char *&dest, std::string v); - void HistogramBuilder::add (HistogramTypes hi, double cumulative, double approx_ndv) { assert (cumulative >= 0.0); diff --git a/src/histogram/histogram_cl.c b/src/histogram/histogram_cl.c new file mode 100644 index 00000000000..a440feabe4e --- /dev/null +++ b/src/histogram/histogram_cl.c @@ -0,0 +1,96 @@ +#include "dbtype_def.h" +#include "histogram_cl.h" +#include "db.h" +#include "histogram_builder.hpp" +#include "thread_entry.hpp" + + +/* + * analyze_all_classes + * + * return: + * with_fullscan(in): true iff WITH FULLSCAN + * + * NOTE: + */ + + +int +get_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, + int with_fullscan, char *histogram_blob) +{ + int error = NO_ERROR; + DB_QUERY_RESULT *query_result; + DB_QUERY_ERROR query_error; + hist::HistogramBuilder histogram_builder; + DB_TYPE type = DB_TYPE_UNKNOWN; + + char query_buf[1024]; + snprintf (query_buf, sizeof (query_buf), HISTOGRAM_QUERY_TEMPLATE, attr_name, tbl_name, attr_name, + max_number_of_buckets, max_number_of_buckets); + + error = db_compile_and_execute_local (query_buf, &query_result, &query_error); + + if (error != NO_ERROR) + { + return error; + } + + error = db_query_first_tuple (query_result); + if (error != DB_CURSOR_SUCCESS) + { + if (error == DB_CURSOR_END) + { + error = NO_ERROR; + } + else + { + ASSERT_ERROR (); + } + return error; + } + + + do + { + DB_VALUE value[5]; + error = db_query_get_tuple_value (query_result, 0, &value[0]); // bid + error = db_query_get_tuple_value (query_result, 1, &value[1]); // endpoint + error = db_query_get_tuple_value (query_result, 2, &value[2]); // rows_in_bucket + error = db_query_get_tuple_value (query_result, 3, &value[3]); // cumulative + error = db_query_get_tuple_value (query_result, 4, &value[4]); // approx_ndv + + if (error != NO_ERROR) + { + return error; + } + + switch (value[1].domain.general_info.type) + { + case DB_TYPE_INTEGER: + histogram_builder.add (db_get_int (&value[1]), db_get_double (&value[3]), db_get_double (&value[4])); + type = DB_TYPE_INTEGER; + break; + case DB_TYPE_BIGINT: + histogram_builder.add (db_get_int (&value[1]), db_get_double (&value[3]), db_get_double (&value[4])); + type = DB_TYPE_BIGINT; + break; + case DB_TYPE_DOUBLE: + histogram_builder.add (db_get_int (&value[1]), db_get_double (&value[3]), db_get_double (&value[4])); + type = DB_TYPE_DOUBLE; + break; + default: + assert (false); + break; + } + } + while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS); + + histogram_blob = histogram_builder.build (thread_p, type); + if (histogram_blob == NULL) + { + return ER_FAILED; + } + + return NO_ERROR; +} diff --git a/src/histogram/histogram_cl.h b/src/histogram/histogram_cl.h new file mode 100644 index 00000000000..9f7b3fbf53c --- /dev/null +++ b/src/histogram/histogram_cl.h @@ -0,0 +1,44 @@ +#include "thread_entry.hpp" + +static const char *HISTOGRAM_QUERY_TEMPLATE = + "WITH src AS (\n" + " SELECT /*+ RECOMPILE */\n" + " %s AS val\n" + " FROM %s\n" + " WHERE %s IS NOT NULL\n" + "),\n" + "cnt AS (\n" + " SELECT val, COUNT(*) AS c\n" + " FROM src\n" + " GROUP BY val\n" + "),\n" + "acc AS (\n" + " SELECT\n" + " val, c,\n" + " SUM(c) OVER (ORDER BY val) AS cum,\n" + " SUM(c) OVER () AS n\n" + " FROM cnt\n" + "),\n" + "param AS (\n" + " SELECT\n" + " CASE WHEN n > 0 THEN CEIL(n * 1.0 / %d) ELSE 1 END AS cap,\n" + " n\n" + " FROM acc\n" + " LIMIT 1\n" + "),\n" + "b AS (\n" + " SELECT\n" + " LEAST(FLOOR((acc.cum - 1) / param.cap), %d - 1) AS bid,\n" + " acc.val,\n" + " acc.c AS rows_for_val\n" + " FROM acc, param\n" + ")\n" + "SELECT\n" + " b.bid,\n" + " MAX(b.val) AS endpoint,\n" + " SUM(b.rows_for_val) AS rows_in_bucket,\n" + " SUM(SUM(b.rows_for_val)) OVER (ORDER BY b.bid) AS cumulative,\n" + " COUNT(*) AS approx_ndv\n" "FROM b\n" "GROUP BY b.bid\n" "ORDER BY b.bid\n"; + +int get_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, + int with_fullscan, char *histogram_blob); diff --git a/src/histogram/histogram_query.sql b/src/histogram/histogram_query.sql index 321c2ff6576..a86a633ee0d 100644 --- a/src/histogram/histogram_query.sql +++ b/src/histogram/histogram_query.sql @@ -1,39 +1,41 @@ WITH src AS ( - /* NULL 제외 + 샘플링(전수면 WHERE RAND()<... 제거) */ SELECT /*+ RECOMPILE */ - t. /*COLUMN*/ AS val - FROM /*TABLE*/ AS t - WHERE t. /*COLUMN*/ IS NOT NULL - AND RAND() < /*SAMPLE_RATIO*/ -- 예: 0.02 (2%). 전수면 이 줄 삭제 + t. AS val + FROM t + WHERE val IS NOT NULL ), -ranked AS ( - SELECT - val, - ROW_NUMBER() OVER (ORDER BY val) AS rn, - COUNT(*) OVER () AS n +cnt AS ( + SELECT val, COUNT(*) AS c FROM src + GROUP BY val +), +acc AS ( + SELECT + val, c, + SUM(c) OVER (ORDER BY val) AS cum, + SUM(c) OVER () AS n + FROM cnt ), -bucketed AS ( +param AS ( SELECT - CAST(FLOOR((/*BUCKETS*/ * (rn - 1)) / n) AS INT) AS bid, -- 0..B-1 - val - FROM ranked + CASE WHEN n > 0 THEN CEIL(n * 1.0 / ) ELSE 1 END AS cap, + n + FROM acc + LIMIT 1 ), -agg AS ( +b AS ( SELECT - bid, - MAX(val) AS endpoint, -- 버킷 상한(hi) - COUNT(*) AS rows_in_bucket, - COUNT(DISTINCT val) AS approx_ndv -- 샘플 기준 NDV - FROM bucketed - GROUP BY bid + LEAST( FLOOR( (acc.cum - 1) / param.cap ), - 1 ) AS bid, + acc.val, + acc.c AS rows_for_val + FROM acc, param ) SELECT - bid, - endpoint, - rows_in_bucket, - SUM(rows_in_bucket) OVER (ORDER BY bid - ROWS UNBOUNDED PRECEDING) AS cumulative, - approx_ndv -FROM agg -ORDER BY bid; \ No newline at end of file + b.bid, + MAX(b.val) AS endpoint, + SUM(b.rows_for_val) AS rows_in_bucket, + SUM(SUM(b.rows_for_val)) OVER (ORDER BY b.bid) AS cumulative, + COUNT(*) AS approx_ndv +FROM b +GROUP BY b.bid +ORDER BY b.bid; \ No newline at end of file diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index cddd62ec312..b647f75a605 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -20,9 +20,6 @@ namespace hist // nbuckets : u32 // str_size : u32 // -// Index table (fixed-size): -// offsets[nbuckets] : u32 each, offset of bucket i record -// relative to bucket_area_begin (first record is usually 0) // // Buckets area (variable): // For each i in [0, nbuckets): @@ -88,7 +85,7 @@ namespace hist std::uint32_t nb_ = 0; std::uint32_t str_size_ = 0; std::uint32_t total_size_ = 0; - TypeIndex type_ = DB_TYPE_UNKNOWN; + std::uint32_t type_ = DB_TYPE_UNKNOWN; }; From 8fe5365d4cd6a8aabd4192494ee815c0b8c623bf Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 31 Oct 2025 19:15:32 +0900 Subject: [PATCH 032/112] =?UTF-8?q?(histogram=5Fbuilder.cpp,=20histogram?= =?UTF-8?q?=5Freader.cpp)=20=EB=B9=8C=EB=93=9C=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0/=20=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0/?= =?UTF-8?q?=20=EB=8D=94=EB=AF=B8=EC=BD=94=EB=93=9C=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cs/CMakeLists.txt | 3 + sa/CMakeLists.txt | 14 ++ src/histogram/histogram_builder.cpp | 209 +++++++++++++++++++--------- src/histogram/histogram_builder.hpp | 11 +- src/histogram/histogram_cl.c | 69 +++++++-- src/histogram/histogram_cl.h | 4 +- src/histogram/histogram_query.sql | 10 +- src/histogram/histogram_reader.cpp | 17 +-- src/histogram/histogram_reader.hpp | 8 +- src/query/execute_schema.c | 2 + 10 files changed, 252 insertions(+), 95 deletions(-) diff --git a/cs/CMakeLists.txt b/cs/CMakeLists.txt index 5b5ea0f4497..eb25b6831c7 100644 --- a/cs/CMakeLists.txt +++ b/cs/CMakeLists.txt @@ -523,6 +523,7 @@ SET_SOURCE_FILES_PROPERTIES( ${API_SOURCES} ${PARALLEL_HEAP_SCAN_SOURCES} ${PARALLEL_QUERY_EXECUTE_SOURCES} + ${HISTOGRAM_SOURCES} PROPERTIES LANGUAGE CXX ) SET_SOURCE_FILES_PROPERTIES( @@ -569,6 +570,8 @@ add_library(cubridcs SHARED ${PARALLEL_HEAP_SCAN_HEADERS} ${PARALLEL_QUERY_EXECUTE_SOURCES} ${PARALLEL_QUERY_EXECUTE_HEADERS} + ${HISTOGRAM_SOURCES} + ${HISTOGRAM_HEADERS} ) set_target_properties(cubridcs PROPERTIES SOVERSION "${CUBRID_MAJOR_VERSION}.${CUBRID_MINOR_VERSION}") diff --git a/sa/CMakeLists.txt b/sa/CMakeLists.txt index 69ce3954cab..219797ba2df 100644 --- a/sa/CMakeLists.txt +++ b/sa/CMakeLists.txt @@ -539,6 +539,17 @@ set(XASL_HEADERS ${XASL_DIR}/xasl_iteration.hpp ) +set(HISTOGRAM_SOURCES + ${HISTOGRAM_DIR}/histogram_cl.c + ${HISTOGRAM_DIR}/histogram_reader.cpp + ${HISTOGRAM_DIR}/histogram_builder.cpp +) +set(HISTOGRAM_HEADERS + ${HISTOGRAM_DIR}/histogram_cl.h + ${HISTOGRAM_DIR}/histogram_reader.hpp + ${HISTOGRAM_DIR}/histogram_builder.hpp +) + set(LOADDB_SOURCES ${BISON_loader_grammar_OUTPUT_SOURCE} ${FLEX_loader_lexer_OUTPUTS} @@ -641,6 +652,7 @@ SET_SOURCE_FILES_PROPERTIES( ${PROBES_OBJECT} ${XASL_SOURCES} ${LOADDB_SOURCES} + ${HISTOGRAM_SOURCES} PROPERTIES LANGUAGE CXX ) @@ -694,6 +706,8 @@ add_library(cubridsa SHARED ${XASL_SOURCES} ${LOADDB_SOURCES} ${LOADDB_HEADERS} + ${HISTOGRAM_SOURCES} + ${HISTOGRAM_HEADERS} ) set_target_properties(cubridsa PROPERTIES SOVERSION "${CUBRID_MAJOR_VERSION}.${CUBRID_MINOR_VERSION}") diff --git a/src/histogram/histogram_builder.cpp b/src/histogram/histogram_builder.cpp index 89ef25f33b0..d21cb752fe0 100644 --- a/src/histogram/histogram_builder.cpp +++ b/src/histogram/histogram_builder.cpp @@ -5,10 +5,50 @@ namespace hist { - void HistogramBuilder::add (HistogramTypes hi, double cumulative, double approx_ndv) + // ---------- endian writers for buffer (explicit specializations before use) ---------- + template<> + void HistogramBuilder::write (char *&dest, std::int32_t v) + { + OR_PUT_INT (dest, v); + dest += OR_INT64_SIZE; // keep 8-byte slot for data_hi (4B value + 4B padding) + } + + template<> + void HistogramBuilder::write (char *&dest, std::int64_t v) { - assert (cumulative >= 0.0); - buckets_.push_back (Bucket{hi, cumulative, approx_ndv}); + OR_PUT_INT64 (dest, &v); // 포인터 전달 필요 + dest += OR_INT64_SIZE; + } + + template<> + void HistogramBuilder::write (char *&dest, double v) + { + OR_PUT_DOUBLE (dest, v); + dest += OR_DOUBLE_SIZE; + } + + template<> + void HistogramBuilder::write (char *&dest, std::string v) + { + // write length and offset or inline data + OR_PUT_INT (dest, v.length()); + dest += OR_INT_SIZE; + if (v.length() <= 4) + { + memcpy (dest, v.data(), v.length()); + } + else + { + OR_PUT_INT (dest, cur_str_off_); + cur_str_off_ += v.length(); + } + dest += OR_INT_SIZE; + } + + void HistogramBuilder::add (HistogramTypes data_hi, std::int64_t cumulative, std::int64_t approx_ndv) + { + assert (cumulative >= 0); + buckets_.push_back (Bucket{data_hi, cumulative, approx_ndv}); } char *HistogramBuilder::build (THREAD_ENTRY *thread_p, DB_TYPE type) @@ -26,59 +66,144 @@ namespace hist H.total_size = 0; // Fix Later char *buffer = static_cast (db_private_alloc (thread_p, sizeof (H) + bucket_area_size)); // records + if (buffer == NULL) + { + return NULL; + } + std::memset (buffer, 0, sizeof (H) + bucket_area_size); // initialize to zero char *end_buffer = buffer + sizeof (H) + bucket_area_size; char *buffer_ptr = buffer + sizeof (H); char *str_blob_ptr; // buckets area - for (const auto &b : buckets_) + if (buckets_.empty()) + { + return buffer; // return empty buffer if no buckets + } + + // Use index-based loop for safer access + for (size_t i = 0; i < buckets_.size(); ++i) { - const auto &bucket = b; + const Bucket b = buckets_[i]; switch (type) { case DB_TYPE_INTEGER: - write (buffer_ptr, std::get (bucket.data_hi)); - break; + { + // DB_TYPE_INTEGER는 std::int64_t로 저장됨 (HistogramTypes에 std::int32_t 없음) + if (std::holds_alternative (b.data_hi)) + { + // int64_t 값을 int32_t로 변환하여 저장 (실제로는 32bit 값이므로) + std::int64_t val = std::get (b.data_hi); + write (buffer_ptr, static_cast (val)); + } + else + { + assert (false); + return NULL; + } + } + break; case DB_TYPE_DOUBLE: - write (buffer_ptr, std::get (bucket.data_hi)); - break; + { + if (std::holds_alternative (b.data_hi)) + { + write (buffer_ptr, std::get (b.data_hi)); + } + else + { + assert (false); + return NULL; + } + } + break; case DB_TYPE_BIGINT: - write (buffer_ptr, std::get (bucket.data_hi)); - break; + { + if (std::holds_alternative (b.data_hi)) + { + write (buffer_ptr, std::get (b.data_hi)); + } + else + { + assert (false); + return NULL; + } + } + break; case DB_TYPE_STRING: - write (buffer_ptr, std::get (bucket.data_hi)); - break; + { + // variant에 string_view나 string이 있을 수 있음 + if (std::holds_alternative (b.data_hi)) + { + write (buffer_ptr, std::get (b.data_hi)); + } + else if (std::holds_alternative (b.data_hi)) + { + // string_view를 string으로 변환 + std::string_view sv = std::get (b.data_hi); + write (buffer_ptr, std::string (sv)); + } + else + { + assert (false); + return NULL; + } + } + break; default: // not_implemented assert (false); - break; + return NULL; } - write (buffer_ptr, bucket.cumulative); - write (buffer_ptr, bucket.approx_ndv); + write (buffer_ptr, b.cumulative); + write (buffer_ptr, b.approx_ndv); } - assert (buffer_ptr != end_buffer); + assert (buffer_ptr == end_buffer); // build string blob if (cur_str_off_ > 0) { assert (DB_TYPE_STRING == type); str_blob_ptr = static_cast (db_private_alloc (thread_p, cur_str_off_)); + if (str_blob_ptr == NULL) + { + return NULL; + } + std::memset (str_blob_ptr, 0, cur_str_off_); // initialize to zero char *str_blob_ptr_end = str_blob_ptr + cur_str_off_; for (const auto &b : buckets_) { - const auto &bucket = b; if (DB_TYPE_STRING == type) { - if ( std::get (bucket.data_hi).length() > 4) + std::string str_val; + if (std::holds_alternative (b.data_hi)) + { + str_val = std::get (b.data_hi); + } + else if (std::holds_alternative (b.data_hi)) + { + str_val = std::string (std::get (b.data_hi)); + } + else { - memcpy (str_blob_ptr, std::get (bucket.data_hi).data(), std::get (bucket.data_hi).length()); - str_blob_ptr += std::get (bucket.data_hi).length(); + assert (false); + return NULL; + } + + if (str_val.length() > 4) + { + memcpy (str_blob_ptr, str_val.data(), str_val.length()); + str_blob_ptr += str_val.length(); } } } // write string assert (str_blob_ptr == str_blob_ptr_end); buffer = static_cast (db_private_realloc (thread_p, buffer, sizeof (H) + bucket_area_size + cur_str_off_)); + if (buffer == NULL) + { + db_private_free (thread_p, str_blob_ptr); + return NULL; + } memcpy (buffer + sizeof (H) + bucket_area_size, str_blob_ptr, cur_str_off_); end_buffer += cur_str_off_; db_private_free (thread_p, str_blob_ptr); @@ -87,49 +212,9 @@ namespace hist H.str_size = ntohl (cur_str_off_); H.total_size = ntohl (sizeof (H) + bucket_area_size + cur_str_off_); memcpy (buffer, &H, sizeof (H)); - assert (buffer - end_buffer == H.total_size); + assert (end_buffer - buffer == sizeof (H) + bucket_area_size + cur_str_off_); // write header return buffer; } - -// ---------- endian writers for buffer ---------- - template<> - void HistogramBuilder::write (char *&dest, std::int32_t v) - { - OR_PUT_INT (dest, v); - dest += OR_INT64_SIZE; - } - - template<> - void HistogramBuilder::write (char *&dest, std::int64_t v) - { - OR_PUT_INT64 (dest, v); - dest += OR_INT64_SIZE; - } - - template<> - void HistogramBuilder::write (char *&dest, double v) - { - OR_PUT_DOUBLE (dest, v); - dest += OR_DOUBLE_SIZE; - } - - template<> - void HistogramBuilder::write (char *&dest, std::string v) - { - // write length and offset or inline data - OR_PUT_INT (dest, v.length()); - dest += OR_INT_SIZE; - if (v.length() <= 4) - { - memcpy (dest, v.data(), v.length()); - } - else - { - OR_PUT_INT (dest, cur_str_off_); - cur_str_off_ += v.length(); - } - dest += OR_INT_SIZE; - } } // namespace hist diff --git a/src/histogram/histogram_builder.hpp b/src/histogram/histogram_builder.hpp index a0ed8538f6d..aba03c3da43 100644 --- a/src/histogram/histogram_builder.hpp +++ b/src/histogram/histogram_builder.hpp @@ -8,19 +8,20 @@ namespace hist { - + using HistogramTypes = std::variant; class HistogramBuilder { public: - void add (HistogramTypes hi, double cumulative, double approx_ndv = std::numeric_limits::quiet_NaN()); + void add (HistogramTypes data_hi, std::int64_t cumulative, + std::int64_t approx_ndv = std::numeric_limits::quiet_NaN()); char *build (THREAD_ENTRY *thread_p, DB_TYPE type); private: struct Bucket { - HistogramTypes data_hi; - double cumulative; - double approx_ndv; + HistogramTypes data_hi; // std::variant: int32_t, int64_t, double, string 중 하나 + std::int64_t cumulative; + std::int64_t approx_ndv; }; HeaderV1 header_; diff --git a/src/histogram/histogram_cl.c b/src/histogram/histogram_cl.c index a440feabe4e..23d8d3ac6d6 100644 --- a/src/histogram/histogram_cl.c +++ b/src/histogram/histogram_cl.c @@ -2,7 +2,8 @@ #include "histogram_cl.h" #include "db.h" #include "histogram_builder.hpp" -#include "thread_entry.hpp" +#include "thread_compat.hpp" +#include "db_query.h" /* @@ -13,7 +14,21 @@ * * NOTE: */ +int +analyze_classes (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, + int with_fullscan) +{ + int error = NO_ERROR; + char *histogram_blob = NULL; + error = get_histogram (thread_p, tbl_name, attr_name, max_number_of_buckets, with_fullscan, histogram_blob); + if (error != NO_ERROR) + { + return error; + } + db_private_free (thread_p, histogram_blob); + return NO_ERROR; +} int get_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, @@ -31,7 +46,7 @@ get_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_n error = db_compile_and_execute_local (query_buf, &query_result, &query_error); - if (error != NO_ERROR) + if (error < 0) { return error; } @@ -54,11 +69,11 @@ get_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_n do { DB_VALUE value[5]; - error = db_query_get_tuple_value (query_result, 0, &value[0]); // bid - error = db_query_get_tuple_value (query_result, 1, &value[1]); // endpoint - error = db_query_get_tuple_value (query_result, 2, &value[2]); // rows_in_bucket - error = db_query_get_tuple_value (query_result, 3, &value[3]); // cumulative - error = db_query_get_tuple_value (query_result, 4, &value[4]); // approx_ndv + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *>("bid"), &value[0]); + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *>("endpoint"), &value[1]); + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *>("rows_in_bucket"), &value[2]); + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *>("cumulative"), &value[3]); + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *>("approx_ndv"), &value[4]); if (error != NO_ERROR) { @@ -68,17 +83,51 @@ get_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_n switch (value[1].domain.general_info.type) { case DB_TYPE_INTEGER: - histogram_builder.add (db_get_int (&value[1]), db_get_double (&value[3]), db_get_double (&value[4])); + { + // int를 std::int64_t로 변환하여 variant 생성 + hist::HistogramTypes hi = static_cast < std::int64_t > (db_get_int (&value[1])); + histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + } type = DB_TYPE_INTEGER; break; case DB_TYPE_BIGINT: - histogram_builder.add (db_get_int (&value[1]), db_get_double (&value[3]), db_get_double (&value[4])); + { + // int64_t를 variant로 생성 + std::int64_t val = db_get_bigint (&value[1]); + hist::HistogramTypes hi + { + val}; + histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + } type = DB_TYPE_BIGINT; break; case DB_TYPE_DOUBLE: - histogram_builder.add (db_get_int (&value[1]), db_get_double (&value[3]), db_get_double (&value[4])); + { + // double을 variant로 생성 + double val = db_get_double (&value[1]); + hist::HistogramTypes hi + { + val}; + histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + } type = DB_TYPE_DOUBLE; break; + case DB_TYPE_STRING: + { + // string을 variant로 생성 (복사 생성으로 안전하게) + const char *str = db_get_string (&value[1]); + if (str == NULL) + { + return ER_FAILED; + } + std::string str_val (str); // 복사 생성 - 안전 + hist::HistogramTypes hi + { + str_val}; + histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + } + type = DB_TYPE_STRING; + break; default: assert (false); break; diff --git a/src/histogram/histogram_cl.h b/src/histogram/histogram_cl.h index 9f7b3fbf53c..002f231eaa7 100644 --- a/src/histogram/histogram_cl.h +++ b/src/histogram/histogram_cl.h @@ -1,4 +1,4 @@ -#include "thread_entry.hpp" +#include "thread_compat.hpp" static const char *HISTOGRAM_QUERY_TEMPLATE = "WITH src AS (\n" @@ -40,5 +40,7 @@ static const char *HISTOGRAM_QUERY_TEMPLATE = " SUM(SUM(b.rows_for_val)) OVER (ORDER BY b.bid) AS cumulative,\n" " COUNT(*) AS approx_ndv\n" "FROM b\n" "GROUP BY b.bid\n" "ORDER BY b.bid\n"; +int analyze_classes (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, + int with_fullscan); int get_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, int with_fullscan, char *histogram_blob); diff --git a/src/histogram/histogram_query.sql b/src/histogram/histogram_query.sql index a86a633ee0d..c013976b051 100644 --- a/src/histogram/histogram_query.sql +++ b/src/histogram/histogram_query.sql @@ -1,8 +1,8 @@ WITH src AS ( SELECT /*+ RECOMPILE */ - t. AS val - FROM
t - WHERE val IS NOT NULL + t.a AS val + FROM t + WHERE t.a IS NOT NULL ), cnt AS ( SELECT val, COUNT(*) AS c @@ -18,14 +18,14 @@ acc AS ( ), param AS ( SELECT - CASE WHEN n > 0 THEN CEIL(n * 1.0 / ) ELSE 1 END AS cap, + CASE WHEN n > 0 THEN CEIL(n * 1.0 / 30) ELSE 1 END AS cap, n FROM acc LIMIT 1 ), b AS ( SELECT - LEAST( FLOOR( (acc.cum - 1) / param.cap ), - 1 ) AS bid, + LEAST( FLOOR( (acc.cum - 1) / param.cap ), 30 - 1 ) AS bid, acc.val, acc.c AS rows_for_val FROM acc, param diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index c0b56a302de..2f84eeb3cf2 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -61,7 +61,7 @@ namespace hist nb_ = get_value (&H->nbuckets); str_size_ = get_value (&H->str_size); - type_ = get_value (&H->type); + type_ = static_cast (get_value (&H->type)); total_size_ = get_value (&H->total_size); assert (total_size_ == blob_.size()); @@ -88,6 +88,7 @@ namespace hist /* read string blob */ str_blob_ = std::string_view{buckets_end_, static_cast (str_size_)}; + return NO_ERROR; } // ---------- record navigation ---------- @@ -106,25 +107,25 @@ namespace hist } // ---------- access ---------- - double HistogramReader::bucket_cumulative (std::uint32_t i) const + std::int64_t HistogramReader::bucket_cumulative (std::uint32_t i) const { const char *p = bucket_rec (i) + 8; - return get_value (p); + return get_value (p); } - double HistogramReader::bucket_approx_ndv (std::uint32_t i) const + std::int64_t HistogramReader::bucket_approx_ndv (std::uint32_t i) const { assert (i < nb_); const char *rec = bucket_rec (i); const char *p = rec + 16; - return get_value (p); + return get_value (p); } - double HistogramReader::bucket_rows (std::uint32_t i) const + std::int64_t HistogramReader::bucket_rows (std::uint32_t i) const { assert (i < nb_); - const double cur = bucket_cumulative (i); - const double prev = (i == 0) ? 0.0 : bucket_cumulative (i - 1); + const std::int64_t cur = bucket_cumulative (i); + const std::int64_t prev = (i == 0) ? 0 : bucket_cumulative (i - 1); return cur - prev; } diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index b647f75a605..7a382273860 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -1,3 +1,4 @@ +#pragma once #include #include #include @@ -30,7 +31,6 @@ namespace hist // String blob (trailing): // str_size bytes; bucket string data points to (len, off) inside this blob. constexpr std::uint32_t BUCKET_RECORD_SIZE = 8 + 8 + 8; // data + cumulative + approx_ndv - using HistogramTypes = std::variant; struct HeaderV1 { char magic[4]; // "HST1" @@ -61,13 +61,13 @@ namespace hist return nb_ ? bucket_cumulative (nb_ - 1) : 0; } - double bucket_cumulative (std::uint32_t i) const; - double bucket_approx_ndv (std::uint32_t i) const; + std::int64_t bucket_cumulative (std::uint32_t i) const; + std::int64_t bucket_approx_ndv (std::uint32_t i) const; template T bucket_hi (std::uint32_t i) const; - double bucket_rows (std::uint32_t i) const; + std::int64_t bucket_rows (std::uint32_t i) const; private: template diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index eebd9e2bb42..d2483493958 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -61,6 +61,7 @@ #include "dbtype.h" #include "jsp_cl.h" #include "msgcat_glossary.hpp" +#include "histogram_cl.h" #if defined (SUPPRESS_STRLEN_WARNING) #define strlen(s1) ((int) strlen(s1)) @@ -3948,6 +3949,7 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, else { error = sm_add_histogram (obj, attname, data_type, histogram_type, bucket_count); + error = analyze_classes (NULL, db_get_class_name(obj), attname, 30, false); if (error != NO_ERROR) { return error; From 14f2c9a99ade7801273526df43cb2e5d06ba9e42 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Mon, 3 Nov 2025 13:26:06 +0900 Subject: [PATCH 033/112] (temporary commit) --- src/query/execute_schema.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index d2483493958..03478e285a4 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3949,7 +3949,7 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, else { error = sm_add_histogram (obj, attname, data_type, histogram_type, bucket_count); - error = analyze_classes (NULL, db_get_class_name(obj), attname, 30, false); + error = analyze_classes (NULL, db_get_class_name (obj), attname, 30, false); if (error != NO_ERROR) { return error; From 3ed490942c9f71ab86e314fc79796a2b587ee0b4 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 6 Nov 2025 16:14:12 +0900 Subject: [PATCH 034/112] (temp commit) --- src/histogram/histogram_builder.cpp | 3 +- src/histogram/histogram_builder.hpp | 2 +- src/histogram/histogram_cl.c | 96 ++++++++++++++++++-- src/histogram/histogram_cl.h | 6 +- src/object/schema_manager.c | 1 - src/object/schema_system_catalog_install.cpp | 8 ++ src/query/execute_schema.c | 2 +- 7 files changed, 106 insertions(+), 12 deletions(-) diff --git a/src/histogram/histogram_builder.cpp b/src/histogram/histogram_builder.cpp index d21cb752fe0..a175b15cd26 100644 --- a/src/histogram/histogram_builder.cpp +++ b/src/histogram/histogram_builder.cpp @@ -51,7 +51,7 @@ namespace hist buckets_.push_back (Bucket{data_hi, cumulative, approx_ndv}); } - char *HistogramBuilder::build (THREAD_ENTRY *thread_p, DB_TYPE type) + char *HistogramBuilder::build (THREAD_ENTRY *thread_p, DB_TYPE type, int *histogram_total_length) { // ---- precompute record sizes ---- const std::uint32_t bucket_area_size = hist::BUCKET_RECORD_SIZE * buckets_.size(); @@ -213,6 +213,7 @@ namespace hist H.total_size = ntohl (sizeof (H) + bucket_area_size + cur_str_off_); memcpy (buffer, &H, sizeof (H)); assert (end_buffer - buffer == sizeof (H) + bucket_area_size + cur_str_off_); + *histogram_total_length = sizeof (H) + bucket_area_size + cur_str_off_; // write header return buffer; diff --git a/src/histogram/histogram_builder.hpp b/src/histogram/histogram_builder.hpp index aba03c3da43..acd7efc319b 100644 --- a/src/histogram/histogram_builder.hpp +++ b/src/histogram/histogram_builder.hpp @@ -14,7 +14,7 @@ namespace hist public: void add (HistogramTypes data_hi, std::int64_t cumulative, std::int64_t approx_ndv = std::numeric_limits::quiet_NaN()); - char *build (THREAD_ENTRY *thread_p, DB_TYPE type); + char *build (THREAD_ENTRY *thread_p, DB_TYPE type, int *histogram_total_length); private: struct Bucket diff --git a/src/histogram/histogram_cl.c b/src/histogram/histogram_cl.c index 23d8d3ac6d6..7f0fe35a3b8 100644 --- a/src/histogram/histogram_cl.c +++ b/src/histogram/histogram_cl.c @@ -4,7 +4,9 @@ #include "histogram_builder.hpp" #include "thread_compat.hpp" #include "db_query.h" - +#include "locator_cl.h" +#include "schema_manager.h" +#include "schema_system_catalog_constants.h" /* * analyze_all_classes @@ -16,11 +18,19 @@ */ int analyze_classes (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, - int with_fullscan) + int with_fullscan, MOP classop) { int error = NO_ERROR; char *histogram_blob = NULL; - error = get_histogram (thread_p, tbl_name, attr_name, max_number_of_buckets, with_fullscan, histogram_blob); + int histogram_total_length = 0; + error = + get_histogram (thread_p, tbl_name, attr_name, max_number_of_buckets, with_fullscan, &histogram_blob, + &histogram_total_length); + if (error != NO_ERROR) + { + return error; + } + error = set_histogram (thread_p, tbl_name, attr_name, histogram_blob, histogram_total_length, classop); if (error != NO_ERROR) { return error; @@ -32,7 +42,7 @@ analyze_classes (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr int get_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, - int with_fullscan, char *histogram_blob) + int with_fullscan, char **histogram_blob, int *histogram_total_length) { int error = NO_ERROR; DB_QUERY_RESULT *query_result; @@ -135,11 +145,85 @@ get_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_n } while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS); - histogram_blob = histogram_builder.build (thread_p, type); - if (histogram_blob == NULL) + *histogram_blob = histogram_builder.build (thread_p, type, histogram_total_length); + if (*histogram_blob == NULL) { return ER_FAILED; } return NO_ERROR; } + +int +set_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, char *histogram_blob, + int histogram_total_length, MOP classop) +{ + int error = NO_ERROR; + DB_OBJECT *histogram_class, *histogram_obj, *edit_histogram_object = NULL; + DB_OTMPL *obj_tmpl = NULL; + DB_VALUE value[2]; + DB_VALUE *value_ptrs[2] = { &value[0], &value[1] }; + DB_VALUE histogram_value; + const char *search_attrs[2] = { "class_of", "key_attr" }; + + histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); + if (histogram_class == NULL) + { + error = ER_BO_MISSING_OR_INVALID_CATALOG; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + goto end; + } + + /* class_of, key_attr */ + db_make_object (&value[0], classop); + db_make_string (&value[1], attr_name); + + histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_READ); + if (histogram_obj == NULL) + { + error = ER_LC_CLASSNAME_EXIST; + char error_histogram[256]; + sprintf (error_histogram, "histogram of %s(%s)", sm_get_ch_name (classop), attr_name); + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, error_histogram); + goto end; + } + + obj_tmpl = dbt_edit_object (histogram_obj); + if (obj_tmpl == NULL) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + goto end; + } + + db_make_varbit (&histogram_value, 1073741823, histogram_blob, histogram_total_length); + error = dbt_put (obj_tmpl, "histogram_values", &histogram_value); + if (error != NO_ERROR) + { + goto end; + } + + edit_histogram_object = dbt_finish_object (obj_tmpl); + if (edit_histogram_object == NULL) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + goto end; + } + + assert (edit_histogram_object == histogram_obj); + obj_tmpl = NULL; + + error = locator_flush_instance (edit_histogram_object); + if (error != NO_ERROR) + { + goto end; + } + +end: + db_value_clear (value_ptrs[0]); + db_value_clear (value_ptrs[1]); + db_value_clear (&histogram_value); + assert (error == NO_ERROR); // for debug + return error; +} diff --git a/src/histogram/histogram_cl.h b/src/histogram/histogram_cl.h index 002f231eaa7..d7eff558e20 100644 --- a/src/histogram/histogram_cl.h +++ b/src/histogram/histogram_cl.h @@ -41,6 +41,8 @@ static const char *HISTOGRAM_QUERY_TEMPLATE = " COUNT(*) AS approx_ndv\n" "FROM b\n" "GROUP BY b.bid\n" "ORDER BY b.bid\n"; int analyze_classes (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, - int with_fullscan); + int with_fullscan, MOP classop); int get_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, - int with_fullscan, char *histogram_blob); + int with_fullscan, char **histogram_blob, int *histogram_total_length); +int set_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, char *histogram_blob, + int histogram_total_length, MOP classop); diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 46be70dc0cf..75e01a018a2 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -15567,7 +15567,6 @@ sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogr goto error_exit; } - /* TODO: Update Histogram Here */ return error; error_exit: diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index 3f8cd1600fd..65005c32074 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -344,6 +344,14 @@ namespace cubschema return s; } + const inline std::string format_varbit (const int size) + { + std::string s ("varbit("); + s += std::to_string (size); + s += ")"; + return s; + } + const inline std::string format_numeric (const int prec, const int scale) { std::string s ("numeric("); diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 03478e285a4..3ebbf4eabcc 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3949,7 +3949,7 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, else { error = sm_add_histogram (obj, attname, data_type, histogram_type, bucket_count); - error = analyze_classes (NULL, db_get_class_name (obj), attname, 30, false); + error = analyze_classes (NULL, db_get_class_name (obj), attname, 30, false, obj); if (error != NO_ERROR) { return error; From bab60daf63666affe5a167c0fb33365a33ef5d5b Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 6 Nov 2025 21:00:32 +0900 Subject: [PATCH 035/112] =?UTF-8?q?(fix)=20CBRD-26217:=20histogram=20class?= =?UTF-8?q?=EC=97=90=20mcv=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 235 +++++++++++++++++++++++++++++++++ src/histogram/histogram_cl.hpp | 32 +++++ 2 files changed, 267 insertions(+) create mode 100644 src/histogram/histogram_cl.cpp create mode 100644 src/histogram/histogram_cl.hpp diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp new file mode 100644 index 00000000000..3790a9e5206 --- /dev/null +++ b/src/histogram/histogram_cl.cpp @@ -0,0 +1,235 @@ +#include "dbtype_def.h" +#include "histogram_cl.hpp" +#include "db.h" +#include "histogram_builder.hpp" +#include "thread_compat.hpp" +#include "db_query.h" +#include "locator_cl.h" +#include "schema_manager.h" +#include "schema_system_catalog_constants.h" +#include +#include + +/* + * analyze_all_classes + * + * return: + * with_fullscan(in): true iff WITH FULLSCAN + * + * NOTE: + */ +int +analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, + int with_fullscan, MOP classop) +{ + int error = NO_ERROR; + char *histogram_blob = NULL; + int histogram_total_length = 0; + error = + get_histogram (thread_p, tbl_name, attr_name, max_number_of_buckets, with_fullscan, &histogram_blob, + &histogram_total_length); + if (error != NO_ERROR) + { + return error; + } + error = set_histogram (thread_p, tbl_name, attr_name, histogram_blob, histogram_total_length, classop); + if (error != NO_ERROR) + { + return error; + } + db_private_free (thread_p, histogram_blob); + + return NO_ERROR; +} + +int +get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, + int with_fullscan, char **histogram_blob, int *histogram_total_length) +{ + int error = NO_ERROR; + DB_QUERY_RESULT *query_result; + DB_QUERY_ERROR query_error; + hist::HistogramBuilder histogram_builder; + DB_TYPE type = DB_TYPE_UNKNOWN; + bool sampling_scan = false; + int number_of_mcv = 3; // TODO + + char query_buf[1024]; + if (sampling_scan) + { + snprintf (query_buf, sizeof (query_buf), HISTOGRAM_WITH_SAMPLING_SCAN_QUERY_TEMPLATE, attr_name, tbl_name, + attr_name, number_of_mcv, max_number_of_buckets, max_number_of_buckets); + } + else + { + snprintf (query_buf, sizeof (query_buf), HISTOGRAM_QUERY_TEMPLATE, attr_name, tbl_name, attr_name, + number_of_mcv, max_number_of_buckets, max_number_of_buckets); + } + + error = db_compile_and_execute_local (query_buf, &query_result, &query_error); + + if (error < 0) + { + return error; + } + + error = db_query_first_tuple (query_result); + if (error != DB_CURSOR_SUCCESS) + { + if (error == DB_CURSOR_END) + { + error = NO_ERROR; + } + else + { + ASSERT_ERROR (); + } + return error; + } + + + do + { + DB_VALUE value[5]; + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("bid"), &value[0]); + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("endpoint"), &value[1]); + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("rows_in_bucket"), &value[2]); + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("cumulative"), &value[3]); + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("approx_ndv"), &value[4]); + + if (error != NO_ERROR) + { + return error; + } + + switch (value[1].domain.general_info.type) + { + case DB_TYPE_INTEGER: + { + // int를 std::int64_t로 변환하여 variant 생성 + hist::HistogramTypes hi = static_cast < std::int64_t > (db_get_int (&value[1])); + histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + } + type = DB_TYPE_INTEGER; + break; + case DB_TYPE_BIGINT: + { + // int64_t를 variant로 생성 + std::int64_t val = db_get_bigint (&value[1]); + hist::HistogramTypes hi {val}; + histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + } + type = DB_TYPE_BIGINT; + break; + case DB_TYPE_DOUBLE: + { + // double을 variant로 생성 + double val = db_get_double (&value[1]); + hist::HistogramTypes hi {val}; + histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + } + type = DB_TYPE_DOUBLE; + break; + case DB_TYPE_STRING: + { + // string을 variant로 생성 (복사 생성으로 안전하게) + const char *str = db_get_string (&value[1]); + if (str == NULL) + { + return ER_FAILED; + } + std::string str_val (str); // 복사 생성 - 안전 + hist::HistogramTypes hi {str_val}; + histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + } + type = DB_TYPE_STRING; + break; + default: + assert (false); + break; + } + } + while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS); + + *histogram_blob = histogram_builder.build (thread_p, type, histogram_total_length); + if (*histogram_blob == NULL) + { + return ER_FAILED; + } + + return NO_ERROR; +} + +int +set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, char *histogram_blob, + int histogram_total_length, MOP classop) +{ + int error = NO_ERROR; + DB_OBJECT *histogram_class, *histogram_obj, *edit_histogram_object = NULL; + DB_OTMPL *obj_tmpl = NULL; + DB_VALUE value[2]; + DB_VALUE *value_ptrs[2] = { &value[0], &value[1] }; + DB_VALUE histogram_value; + const char *search_attrs[2] = { "class_of", "key_attr" }; + + histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); + if (histogram_class == NULL) + { + error = ER_BO_MISSING_OR_INVALID_CATALOG; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + goto end; + } + + /* class_of, key_attr */ + db_make_object (&value[0], classop); + db_make_string (&value[1], attr_name); + + histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_READ); + if (histogram_obj == NULL) + { + error = ER_LC_CLASSNAME_EXIST; + char error_histogram[256]; + sprintf (error_histogram, "histogram of %s(%s)", sm_get_ch_name (classop), attr_name); + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, error_histogram); + goto end; + } + + obj_tmpl = dbt_edit_object (histogram_obj); + if (obj_tmpl == NULL) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + goto end; + } + + db_make_varbit (&histogram_value, 1073741823, histogram_blob, histogram_total_length); + error = dbt_put (obj_tmpl, "histogram_values", &histogram_value); + if (error != NO_ERROR) + { + goto end; + } + + edit_histogram_object = dbt_finish_object (obj_tmpl); + if (edit_histogram_object == NULL) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + goto end; + } + + assert (edit_histogram_object == histogram_obj); + obj_tmpl = NULL; + + error = locator_flush_instance (edit_histogram_object); + if (error != NO_ERROR) + { + goto end; + } + +end: + db_value_clear (value_ptrs[0]); + db_value_clear (value_ptrs[1]); + db_value_clear (&histogram_value); + assert (error == NO_ERROR); // for debug + return error; +} diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp new file mode 100644 index 00000000000..d9cbe02c281 --- /dev/null +++ b/src/histogram/histogram_cl.hpp @@ -0,0 +1,32 @@ +#include "thread_compat.hpp" +static const char *HISTOGRAM_QUERY_TEMPLATE = + "WITH src AS (SELECT %s AS val FROM %s WHERE %s IS NOT NULL), " + "cnt AS (SELECT val, COUNT(*) AS c FROM src GROUP BY val), " + "mcv_ranked AS (SELECT val, c, ROW_NUMBER() OVER (ORDER BY c DESC, val) AS rn FROM cnt ORDER BY c DESC LIMIT %d), " + "non_mcv_flagged AS (SELECT val, c FROM cnt WHERE val NOT IN (SELECT val FROM mcv_ranked)), " + "hist_acc AS (SELECT val, c, SUM(c) OVER (ORDER BY val) AS cum, SUM(c) OVER () AS n FROM non_mcv_flagged), " + "param AS (SELECT CASE WHEN n > 0 THEN CEIL(n * 1.0 / %d) ELSE 1 END AS cap, n FROM hist_acc LIMIT 1), " + "hist_buckets AS (SELECT LEAST(FLOOR((cum - 1) / param.cap), %d - 1) AS bid, val, c, FALSE AS is_mcv FROM hist_acc, param), " + "mcv_buckets AS (SELECT -rn AS bid, val, c, TRUE AS is_mcv FROM mcv_ranked), " + "all_buckets AS (SELECT * FROM hist_buckets UNION ALL SELECT * FROM mcv_buckets) " + "SELECT bid, MAX(val) AS endpoint, SUM(c) AS rows_in_bucket, SUM(SUM(c)) OVER (ORDER BY MAX(val)) AS cumulative, " + "COUNT(*) AS approx_ndv, MAX(is_mcv) AS is_mcv FROM all_buckets GROUP BY bid ORDER BY MAX(val);"; +static const char *HISTOGRAM_WITH_SAMPLING_SCAN_QUERY_TEMPLATE = + "WITH src AS (SELECT /*+ SAMPLING_SCAN */ %s AS val FROM %s WHERE %s IS NOT NULL), " + "cnt AS (SELECT val, COUNT(*) AS c FROM src GROUP BY val), " + "mcv_ranked AS (SELECT val, c, ROW_NUMBER() OVER (ORDER BY c DESC, val) AS rn FROM cnt ORDER BY c DESC LIMIT %d), " + "non_mcv_flagged AS (SELECT val, c FROM cnt WHERE val NOT IN (SELECT val FROM mcv_ranked)), " + "hist_acc AS (SELECT val, c, SUM(c) OVER (ORDER BY val) AS cum, SUM(c) OVER () AS n FROM non_mcv_flagged), " + "param AS (SELECT CASE WHEN n > 0 THEN CEIL(n * 1.0 / %d) ELSE 1 END AS cap, n FROM hist_acc LIMIT 1), " + "hist_buckets AS (SELECT LEAST(FLOOR((cum - 1) / param.cap), %d - 1) AS bid, val, c, FALSE AS is_mcv FROM hist_acc, param), " + "mcv_buckets AS (SELECT -rn AS bid, val, c, TRUE AS is_mcv FROM mcv_ranked), " + "all_buckets AS (SELECT * FROM hist_buckets UNION ALL SELECT * FROM mcv_buckets) " + "SELECT bid, MAX(val) AS endpoint, SUM(c) AS rows_in_bucket, SUM(SUM(c)) OVER (ORDER BY MAX(val)) AS cumulative, " + "COUNT(*) AS approx_ndv, MAX(is_mcv) AS is_mcv FROM all_buckets GROUP BY bid ORDER BY MAX(val);"; + +int analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, + int with_fullscan, MOP classop); +int get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, + int with_fullscan, char **histogram_blob, int *histogram_total_length); +int set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, char *histogram_blob, + int histogram_total_length, MOP classop); From 901fc9e8fd946a3cbe1a8319c4d52a4d728568ec Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 6 Nov 2025 21:01:10 +0900 Subject: [PATCH 036/112] =?UTF-8?q?(fix)=20CBRD-26217:=20histogram=20class?= =?UTF-8?q?=EC=97=90=20mcv=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cs/CMakeLists.txt | 4 +- sa/CMakeLists.txt | 4 +- src/histogram/histogram_cl.h | 48 ------------------- src/object/schema_manager.c | 4 +- src/object/schema_manager.h | 2 +- src/object/schema_system_catalog_install.cpp | 1 - ...hema_system_catalog_install_query_spec.cpp | 1 - src/object/schema_template.c | 11 +---- src/object/schema_template.h | 2 +- src/object/transform.c | 1 - src/query/execute_schema.c | 10 ++-- 11 files changed, 14 insertions(+), 74 deletions(-) delete mode 100644 src/histogram/histogram_cl.h diff --git a/cs/CMakeLists.txt b/cs/CMakeLists.txt index d97589cffa4..0cfe5bb311e 100644 --- a/cs/CMakeLists.txt +++ b/cs/CMakeLists.txt @@ -428,13 +428,13 @@ set(PARALLEL_QUERY_EXECUTE_HEADERS ) set (HISTOGRAM_SOURCES - ${HISTOGRAM_DIR}/histogram_cl.c + ${HISTOGRAM_DIR}/histogram_cl.cpp ${HISTOGRAM_DIR}/histogram_builder.cpp ${HISTOGRAM_DIR}/histogram_reader.cpp ) set (HISTOGRAM_HEADERS - ${HISTOGRAM_DIR}/histogram_cl.h + ${HISTOGRAM_DIR}/histogram_cl.hpp ${HISTOGRAM_DIR}/histogram_builder.hpp ${HISTOGRAM_DIR}/histogram_reader.hpp ) diff --git a/sa/CMakeLists.txt b/sa/CMakeLists.txt index cbef7d0b390..e33dbe75689 100644 --- a/sa/CMakeLists.txt +++ b/sa/CMakeLists.txt @@ -541,12 +541,12 @@ set(XASL_HEADERS ) set(HISTOGRAM_SOURCES - ${HISTOGRAM_DIR}/histogram_cl.c + ${HISTOGRAM_DIR}/histogram_cl.cpp ${HISTOGRAM_DIR}/histogram_reader.cpp ${HISTOGRAM_DIR}/histogram_builder.cpp ) set(HISTOGRAM_HEADERS - ${HISTOGRAM_DIR}/histogram_cl.h + ${HISTOGRAM_DIR}/histogram_cl.hpp ${HISTOGRAM_DIR}/histogram_reader.hpp ${HISTOGRAM_DIR}/histogram_builder.hpp ) diff --git a/src/histogram/histogram_cl.h b/src/histogram/histogram_cl.h deleted file mode 100644 index d7eff558e20..00000000000 --- a/src/histogram/histogram_cl.h +++ /dev/null @@ -1,48 +0,0 @@ -#include "thread_compat.hpp" - -static const char *HISTOGRAM_QUERY_TEMPLATE = - "WITH src AS (\n" - " SELECT /*+ RECOMPILE */\n" - " %s AS val\n" - " FROM %s\n" - " WHERE %s IS NOT NULL\n" - "),\n" - "cnt AS (\n" - " SELECT val, COUNT(*) AS c\n" - " FROM src\n" - " GROUP BY val\n" - "),\n" - "acc AS (\n" - " SELECT\n" - " val, c,\n" - " SUM(c) OVER (ORDER BY val) AS cum,\n" - " SUM(c) OVER () AS n\n" - " FROM cnt\n" - "),\n" - "param AS (\n" - " SELECT\n" - " CASE WHEN n > 0 THEN CEIL(n * 1.0 / %d) ELSE 1 END AS cap,\n" - " n\n" - " FROM acc\n" - " LIMIT 1\n" - "),\n" - "b AS (\n" - " SELECT\n" - " LEAST(FLOOR((acc.cum - 1) / param.cap), %d - 1) AS bid,\n" - " acc.val,\n" - " acc.c AS rows_for_val\n" - " FROM acc, param\n" - ")\n" - "SELECT\n" - " b.bid,\n" - " MAX(b.val) AS endpoint,\n" - " SUM(b.rows_for_val) AS rows_in_bucket,\n" - " SUM(SUM(b.rows_for_val)) OVER (ORDER BY b.bid) AS cumulative,\n" - " COUNT(*) AS approx_ndv\n" "FROM b\n" "GROUP BY b.bid\n" "ORDER BY b.bid\n"; - -int analyze_classes (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, - int with_fullscan, MOP classop); -int get_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, - int with_fullscan, char **histogram_blob, int *histogram_total_length); -int set_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, char *histogram_blob, - int histogram_total_length, MOP classop); diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 75e01a018a2..cca54297a87 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -15530,7 +15530,7 @@ sm_save_constraint_info (SM_CONSTRAINT_INFO ** save_info, const SM_CLASS_CONSTRA int -sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogram_type, int bucket_count) +sm_add_histogram (MOP classop, const char *attr_name, int histogram_type, int bucket_count) { bool set_savepoint = false; int error = NO_ERROR; @@ -15561,7 +15561,7 @@ sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogr goto error_exit; } - error = smt_add_histogram (classop, attr_name, data_type, histogram_type, bucket_count); + error = smt_add_histogram (classop, attr_name, histogram_type, bucket_count); if (error != NO_ERROR) { goto error_exit; diff --git a/src/object/schema_manager.h b/src/object/schema_manager.h index f1661e485c3..82932eb3c09 100644 --- a/src/object/schema_manager.h +++ b/src/object/schema_manager.h @@ -112,7 +112,7 @@ extern int sm_add_constraint (MOP classop, DB_CONSTRAINT_TYPE constraint_type, c const char **att_names, const int *asc_desc, const int *attrs_prefix_length, int class_attributes, SM_PREDICATE_INFO * predicate_info, SM_FUNCTION_INFO * fi_info, const char *comment, SM_INDEX_STATUS index_status); -extern int sm_add_histogram (MOP classop, const char *attr_name, int data_type, int histogram_type, int bucket_count); +extern int sm_add_histogram (MOP classop, const char *attr_name, int histogram_type, int bucket_count); extern int sm_drop_histogram (MOP classop, const char *attr_name); extern int sm_drop_constraint (MOP classop, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, bool class_attributes, bool mysql_index_name); diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index 73d31087a2d..9b6f0ed3e15 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -1285,7 +1285,6 @@ namespace cubschema { {"class_of", "object"}, {"key_attr", format_varchar (255)}, - {"data_type", "integer"}, {"histogram_type","integer"}, {"bucket_count", "integer"}, {"histogram_values", format_varchar (1073741823) } diff --git a/src/object/schema_system_catalog_install_query_spec.cpp b/src/object/schema_system_catalog_install_query_spec.cpp index d670852658a..a599296be32 100644 --- a/src/object/schema_system_catalog_install_query_spec.cpp +++ b/src/object/schema_system_catalog_install_query_spec.cpp @@ -1535,7 +1535,6 @@ sm_define_view_db_histogram_spec (void) "SELECT " "[h].[class_of] AS [class_of], " "[h].[key_attr] AS [key_attr], " - "[h].[data_type] AS [data_type], " "[h].[histogram_type] AS [histogram_type], " // TODO : integer -> varchar(32) "[h].[bucket_count] AS [bucket_count], " "[h].[histogram_values] AS [histogram_values] " diff --git a/src/object/schema_template.c b/src/object/schema_template.c index bc663da2218..6f1c2d863b5 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -2044,7 +2044,7 @@ smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name, bool n } int -smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histogram_type, int bucket_count) +smt_add_histogram (MOP classop, const char *attr_name, int histogram_type, int bucket_count) { int au_save, error = NO_ERROR; DB_OBJECT *ret_obj = NULL, *histogram_class = NULL; @@ -2089,14 +2089,7 @@ smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histog assert (false); goto end; } - /* data_type */ - db_make_int (&value, data_type); - error = dbt_put_internal (obj_tmpl, "data_type", &value); - pr_clear_value (&value); - if (error != NO_ERROR) - { - goto end; - } + /* histogram_type */ db_make_int (&value, histogram_type); error = dbt_put_internal (obj_tmpl, "histogram_type", &value); diff --git a/src/object/schema_template.h b/src/object/schema_template.h index ec12130e099..4d80d2861be 100644 --- a/src/object/schema_template.h +++ b/src/object/schema_template.h @@ -84,7 +84,7 @@ extern int smt_add_constraint (SM_TEMPLATE * template_, DB_CONSTRAINT_TYPE const int class_attribute, SM_FOREIGN_KEY_INFO * fk_info, SM_PREDICATE_INFO * filter_index, SM_FUNCTION_INFO * function_index, const char *comment, SM_INDEX_STATUS index_status); -extern int smt_add_histogram (MOP classop, const char *attr_name, int data_type, int histogram_type, int bucket_count); +extern int smt_add_histogram (MOP classop, const char *attr_name, int histogram_type, int bucket_count); extern int smt_drop_constraint (SM_TEMPLATE * template_, const char **att_names, const char *constraint_name, int class_attribute, SM_ATTRIBUTE_FLAG constraint); diff --git a/src/object/transform.c b/src/object/transform.c index 9bd3fd7cb79..c0be1087ecc 100644 --- a/src/object/transform.c +++ b/src/object/transform.c @@ -419,7 +419,6 @@ static CT_ATTR ct_partition_atts[] = { static CT_ATTR ct_histogram_atts[] = { {"class_of", NULL_ATTRID, DB_TYPE_OBJECT}, {"key_attr", NULL_ATTRID, DB_TYPE_VARCHAR}, - {"data_type", NULL_ATTRID, DB_TYPE_INTEGER}, {"histogram_type", NULL_ATTRID, DB_TYPE_INTEGER}, {"bucket_count", NULL_ATTRID, DB_TYPE_INTEGER} }; diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 241e090d284..ef6a1f8cc8b 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -61,7 +61,7 @@ #include "dbtype.h" #include "jsp_cl.h" #include "msgcat_glossary.hpp" -#include "histogram_cl.h" +#include "histogram_cl.hpp" #if defined (SUPPRESS_STRLEN_WARNING) #define strlen(s1) ((int) strlen(s1)) @@ -3879,7 +3879,7 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, PT_HISTOGRAM_INFO * const histogram_info, DO_HISTOGRAM do_histogram) { int error = NO_ERROR; - int data_type, histogram_type, bucket_count, nnames = 0; + int histogram_type, bucket_count, nnames = 0; char *attname = NULL; PT_NODE *cur_column = NULL; int is_partition = DB_NOT_PARTITIONED_CLASS; @@ -3910,7 +3910,6 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) { attname = (char *) att->header.name; - data_type = 0; /* TODO: data_type */ if (do_histogram == DO_HISTOGRAM_DROP) { error = sm_drop_histogram (obj, attname); @@ -3921,7 +3920,7 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, } else { - error = sm_add_histogram (obj, attname, data_type, histogram_type, bucket_count); + error = sm_add_histogram (obj, attname, histogram_type, bucket_count); if (error != NO_ERROR) { return error; @@ -3933,7 +3932,6 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, for (int i = 0; i < nnames; i++) { attname = (char *) cur_column->info.name.original; - data_type = cur_column->type_enum; if (do_histogram == DO_HISTOGRAM_DROP) { error = sm_drop_histogram (obj, attname); @@ -3944,7 +3942,7 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, } else { - error = sm_add_histogram (obj, attname, data_type, histogram_type, bucket_count); + error = sm_add_histogram (obj, attname, histogram_type, bucket_count); error = analyze_classes (NULL, db_get_class_name (obj), attname, 30, false, obj); if (error != NO_ERROR) { From b397194783923e71b392d131466dbca853709963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=86=8C=ED=9D=AC?= <94791489+sohee-dgist@users.noreply.github.com> Date: Thu, 6 Nov 2025 21:03:29 +0900 Subject: [PATCH 037/112] Delete src/histogram/histogram_query.sql --- src/histogram/histogram_query.sql | 41 ------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 src/histogram/histogram_query.sql diff --git a/src/histogram/histogram_query.sql b/src/histogram/histogram_query.sql deleted file mode 100644 index c013976b051..00000000000 --- a/src/histogram/histogram_query.sql +++ /dev/null @@ -1,41 +0,0 @@ -WITH src AS ( - SELECT /*+ RECOMPILE */ - t.a AS val - FROM t - WHERE t.a IS NOT NULL -), -cnt AS ( - SELECT val, COUNT(*) AS c - FROM src - GROUP BY val -), -acc AS ( - SELECT - val, c, - SUM(c) OVER (ORDER BY val) AS cum, - SUM(c) OVER () AS n - FROM cnt -), -param AS ( - SELECT - CASE WHEN n > 0 THEN CEIL(n * 1.0 / 30) ELSE 1 END AS cap, - n - FROM acc - LIMIT 1 -), -b AS ( - SELECT - LEAST( FLOOR( (acc.cum - 1) / param.cap ), 30 - 1 ) AS bid, - acc.val, - acc.c AS rows_for_val - FROM acc, param -) -SELECT - b.bid, - MAX(b.val) AS endpoint, - SUM(b.rows_for_val) AS rows_in_bucket, - SUM(SUM(b.rows_for_val)) OVER (ORDER BY b.bid) AS cumulative, - COUNT(*) AS approx_ndv -FROM b -GROUP BY b.bid -ORDER BY b.bid; \ No newline at end of file From d81e3c33c757b138fd053352d93cf95962ccb9cc Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 18 Nov 2025 14:00:30 +0900 Subject: [PATCH 038/112] =?UTF-8?q?=ED=95=84=EC=9A=94=EC=97=86=EB=8A=94=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20VARBIT=20?= =?UTF-8?q?TYPE=20=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.c | 229 ------------------- src/object/schema_system_catalog_install.cpp | 7 +- 2 files changed, 3 insertions(+), 233 deletions(-) delete mode 100644 src/histogram/histogram_cl.c diff --git a/src/histogram/histogram_cl.c b/src/histogram/histogram_cl.c deleted file mode 100644 index 7f0fe35a3b8..00000000000 --- a/src/histogram/histogram_cl.c +++ /dev/null @@ -1,229 +0,0 @@ -#include "dbtype_def.h" -#include "histogram_cl.h" -#include "db.h" -#include "histogram_builder.hpp" -#include "thread_compat.hpp" -#include "db_query.h" -#include "locator_cl.h" -#include "schema_manager.h" -#include "schema_system_catalog_constants.h" - -/* - * analyze_all_classes - * - * return: - * with_fullscan(in): true iff WITH FULLSCAN - * - * NOTE: - */ -int -analyze_classes (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, - int with_fullscan, MOP classop) -{ - int error = NO_ERROR; - char *histogram_blob = NULL; - int histogram_total_length = 0; - error = - get_histogram (thread_p, tbl_name, attr_name, max_number_of_buckets, with_fullscan, &histogram_blob, - &histogram_total_length); - if (error != NO_ERROR) - { - return error; - } - error = set_histogram (thread_p, tbl_name, attr_name, histogram_blob, histogram_total_length, classop); - if (error != NO_ERROR) - { - return error; - } - db_private_free (thread_p, histogram_blob); - - return NO_ERROR; -} - -int -get_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, - int with_fullscan, char **histogram_blob, int *histogram_total_length) -{ - int error = NO_ERROR; - DB_QUERY_RESULT *query_result; - DB_QUERY_ERROR query_error; - hist::HistogramBuilder histogram_builder; - DB_TYPE type = DB_TYPE_UNKNOWN; - - char query_buf[1024]; - snprintf (query_buf, sizeof (query_buf), HISTOGRAM_QUERY_TEMPLATE, attr_name, tbl_name, attr_name, - max_number_of_buckets, max_number_of_buckets); - - error = db_compile_and_execute_local (query_buf, &query_result, &query_error); - - if (error < 0) - { - return error; - } - - error = db_query_first_tuple (query_result); - if (error != DB_CURSOR_SUCCESS) - { - if (error == DB_CURSOR_END) - { - error = NO_ERROR; - } - else - { - ASSERT_ERROR (); - } - return error; - } - - - do - { - DB_VALUE value[5]; - error = db_query_get_tuple_value_by_name (query_result, const_cast < char *>("bid"), &value[0]); - error = db_query_get_tuple_value_by_name (query_result, const_cast < char *>("endpoint"), &value[1]); - error = db_query_get_tuple_value_by_name (query_result, const_cast < char *>("rows_in_bucket"), &value[2]); - error = db_query_get_tuple_value_by_name (query_result, const_cast < char *>("cumulative"), &value[3]); - error = db_query_get_tuple_value_by_name (query_result, const_cast < char *>("approx_ndv"), &value[4]); - - if (error != NO_ERROR) - { - return error; - } - - switch (value[1].domain.general_info.type) - { - case DB_TYPE_INTEGER: - { - // int를 std::int64_t로 변환하여 variant 생성 - hist::HistogramTypes hi = static_cast < std::int64_t > (db_get_int (&value[1])); - histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); - } - type = DB_TYPE_INTEGER; - break; - case DB_TYPE_BIGINT: - { - // int64_t를 variant로 생성 - std::int64_t val = db_get_bigint (&value[1]); - hist::HistogramTypes hi - { - val}; - histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); - } - type = DB_TYPE_BIGINT; - break; - case DB_TYPE_DOUBLE: - { - // double을 variant로 생성 - double val = db_get_double (&value[1]); - hist::HistogramTypes hi - { - val}; - histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); - } - type = DB_TYPE_DOUBLE; - break; - case DB_TYPE_STRING: - { - // string을 variant로 생성 (복사 생성으로 안전하게) - const char *str = db_get_string (&value[1]); - if (str == NULL) - { - return ER_FAILED; - } - std::string str_val (str); // 복사 생성 - 안전 - hist::HistogramTypes hi - { - str_val}; - histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); - } - type = DB_TYPE_STRING; - break; - default: - assert (false); - break; - } - } - while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS); - - *histogram_blob = histogram_builder.build (thread_p, type, histogram_total_length); - if (*histogram_blob == NULL) - { - return ER_FAILED; - } - - return NO_ERROR; -} - -int -set_histogram (THREAD_ENTRY * thread_p, const char *tbl_name, const char *attr_name, char *histogram_blob, - int histogram_total_length, MOP classop) -{ - int error = NO_ERROR; - DB_OBJECT *histogram_class, *histogram_obj, *edit_histogram_object = NULL; - DB_OTMPL *obj_tmpl = NULL; - DB_VALUE value[2]; - DB_VALUE *value_ptrs[2] = { &value[0], &value[1] }; - DB_VALUE histogram_value; - const char *search_attrs[2] = { "class_of", "key_attr" }; - - histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); - if (histogram_class == NULL) - { - error = ER_BO_MISSING_OR_INVALID_CATALOG; - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); - goto end; - } - - /* class_of, key_attr */ - db_make_object (&value[0], classop); - db_make_string (&value[1], attr_name); - - histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_READ); - if (histogram_obj == NULL) - { - error = ER_LC_CLASSNAME_EXIST; - char error_histogram[256]; - sprintf (error_histogram, "histogram of %s(%s)", sm_get_ch_name (classop), attr_name); - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, error_histogram); - goto end; - } - - obj_tmpl = dbt_edit_object (histogram_obj); - if (obj_tmpl == NULL) - { - assert (er_errid () != NO_ERROR); - error = er_errid (); - goto end; - } - - db_make_varbit (&histogram_value, 1073741823, histogram_blob, histogram_total_length); - error = dbt_put (obj_tmpl, "histogram_values", &histogram_value); - if (error != NO_ERROR) - { - goto end; - } - - edit_histogram_object = dbt_finish_object (obj_tmpl); - if (edit_histogram_object == NULL) - { - assert (er_errid () != NO_ERROR); - error = er_errid (); - goto end; - } - - assert (edit_histogram_object == histogram_obj); - obj_tmpl = NULL; - - error = locator_flush_instance (edit_histogram_object); - if (error != NO_ERROR) - { - goto end; - } - -end: - db_value_clear (value_ptrs[0]); - db_value_clear (value_ptrs[1]); - db_value_clear (&histogram_value); - assert (error == NO_ERROR); // for debug - return error; -} diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index 9b6f0ed3e15..b8da7b827a9 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -353,7 +353,7 @@ namespace cubschema const inline std::string format_varbit (const int size) { - std::string s ("varbit("); + std::string s ("bit varying("); s += std::to_string (size); s += ")"; return s; @@ -1287,7 +1287,7 @@ namespace cubschema {"key_attr", format_varchar (255)}, {"histogram_type","integer"}, {"bucket_count", "integer"}, - {"histogram_values", format_varchar (1073741823) } + {"histogram_values", format_varbit (1073741823) } }, // constraint { @@ -2080,10 +2080,9 @@ namespace cubschema { {"class_of", "object"}, {"key_attr", format_varchar (255)}, - {"data_type", "integer"}, {"histogram_type","integer"}, {"bucket_count", "integer"}, - {"histogram_values", format_varchar (1024)}, + {"histogram_values", format_varbit (1024)}, {attribute_kind::QUERY_SPEC, sm_define_view_db_histogram_spec ()} }, // constraint From 3330b4d471b82fa7f1ec01aa801080ef76836a65 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 18 Nov 2025 19:45:56 +0900 Subject: [PATCH 039/112] =?UTF-8?q?=ED=9E=88=EC=8A=A4=ED=86=A0=EB=9E=A8=20?= =?UTF-8?q?Read=EC=8B=9C=20=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_builder.cpp | 29 +++--- src/histogram/histogram_builder.hpp | 14 +-- src/histogram/histogram_cl.cpp | 132 ++++++++++++++++++++-------- src/histogram/histogram_cl.hpp | 7 ++ src/histogram/histogram_reader.cpp | 12 +-- src/histogram/histogram_reader.hpp | 2 +- src/optimizer/query_planner.c | 3 + 7 files changed, 136 insertions(+), 63 deletions(-) diff --git a/src/histogram/histogram_builder.cpp b/src/histogram/histogram_builder.cpp index a175b15cd26..b62f76a88f9 100644 --- a/src/histogram/histogram_builder.cpp +++ b/src/histogram/histogram_builder.cpp @@ -59,20 +59,20 @@ namespace hist // ---- header ---- HeaderV1 H{}; std::memcpy (H.magic, "HST1", 4); - H.version = ntohl (1); - H.nbuckets = ntohl (static_cast (buckets_.size())); - H.type = ntohl (static_cast (type)); + H.version = htonl (1); + H.nbuckets = htonl (static_cast (buckets_.size())); + H.type = htonl (static_cast (type)); H.str_size = 0; // Fix Later H.total_size = 0; // Fix Later - char *buffer = static_cast (db_private_alloc (thread_p, sizeof (H) + bucket_area_size)); // records + char *buffer = static_cast (db_private_alloc (thread_p, sizeof (HeaderV1) + bucket_area_size)); // records if (buffer == NULL) { return NULL; } - std::memset (buffer, 0, sizeof (H) + bucket_area_size); // initialize to zero - char *end_buffer = buffer + sizeof (H) + bucket_area_size; - char *buffer_ptr = buffer + sizeof (H); + std::memset (buffer, 0, sizeof (HeaderV1) + bucket_area_size); // initialize to zero + char *end_buffer = buffer + sizeof (HeaderV1) + bucket_area_size; + char *buffer_ptr = buffer + sizeof (HeaderV1); char *str_blob_ptr; // buckets area if (buckets_.empty()) @@ -198,22 +198,23 @@ namespace hist } // write string assert (str_blob_ptr == str_blob_ptr_end); - buffer = static_cast (db_private_realloc (thread_p, buffer, sizeof (H) + bucket_area_size + cur_str_off_)); + buffer = static_cast (db_private_realloc (thread_p, buffer, + sizeof (HeaderV1) + bucket_area_size + cur_str_off_)); if (buffer == NULL) { db_private_free (thread_p, str_blob_ptr); return NULL; } - memcpy (buffer + sizeof (H) + bucket_area_size, str_blob_ptr, cur_str_off_); + memcpy (buffer + sizeof (HeaderV1) + bucket_area_size, str_blob_ptr, cur_str_off_); end_buffer += cur_str_off_; db_private_free (thread_p, str_blob_ptr); } - H.str_size = ntohl (cur_str_off_); - H.total_size = ntohl (sizeof (H) + bucket_area_size + cur_str_off_); - memcpy (buffer, &H, sizeof (H)); - assert (end_buffer - buffer == sizeof (H) + bucket_area_size + cur_str_off_); - *histogram_total_length = sizeof (H) + bucket_area_size + cur_str_off_; + H.str_size = htonl (static_cast (cur_str_off_)); + H.total_size = htonl (static_cast (sizeof (HeaderV1) + bucket_area_size + cur_str_off_)); + memcpy (buffer, &H, sizeof (HeaderV1)); + assert (static_cast (end_buffer - buffer) == sizeof (HeaderV1) + bucket_area_size + cur_str_off_); + *histogram_total_length = sizeof (HeaderV1) + bucket_area_size + cur_str_off_; // write header return buffer; diff --git a/src/histogram/histogram_builder.hpp b/src/histogram/histogram_builder.hpp index acd7efc319b..ae59dd72087 100644 --- a/src/histogram/histogram_builder.hpp +++ b/src/histogram/histogram_builder.hpp @@ -9,6 +9,13 @@ namespace hist { using HistogramTypes = std::variant; + struct Bucket + { + HistogramTypes data_hi; // std::variant: int32_t, int64_t, double, string 중 하나 + std::int64_t cumulative; + std::int64_t approx_ndv; + }; + class HistogramBuilder { public: @@ -17,13 +24,6 @@ namespace hist char *build (THREAD_ENTRY *thread_p, DB_TYPE type, int *histogram_total_length); private: - struct Bucket - { - HistogramTypes data_hi; // std::variant: int32_t, int64_t, double, string 중 하나 - std::int64_t cumulative; - std::int64_t approx_ndv; - }; - HeaderV1 header_; std::vector buckets_; std::int32_t cur_str_off_ = 0; diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 3790a9e5206..d2128151e1e 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -9,6 +9,8 @@ #include "schema_system_catalog_constants.h" #include #include +#include +#include "parser.h" /* * analyze_all_classes @@ -109,27 +111,27 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na // int를 std::int64_t로 변환하여 variant 생성 hist::HistogramTypes hi = static_cast < std::int64_t > (db_get_int (&value[1])); histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + type = DB_TYPE_INTEGER; + break; } - type = DB_TYPE_INTEGER; - break; case DB_TYPE_BIGINT: { // int64_t를 variant로 생성 std::int64_t val = db_get_bigint (&value[1]); hist::HistogramTypes hi {val}; histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + type = DB_TYPE_BIGINT; + break; } - type = DB_TYPE_BIGINT; - break; case DB_TYPE_DOUBLE: { // double을 variant로 생성 double val = db_get_double (&value[1]); hist::HistogramTypes hi {val}; histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + type = DB_TYPE_DOUBLE; + break; } - type = DB_TYPE_DOUBLE; - break; case DB_TYPE_STRING: { // string을 variant로 생성 (복사 생성으로 안전하게) @@ -141,9 +143,9 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na std::string str_val (str); // 복사 생성 - 안전 hist::HistogramTypes hi {str_val}; histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + type = DB_TYPE_STRING; + break; } - type = DB_TYPE_STRING; - break; default: assert (false); break; @@ -165,33 +167,13 @@ set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na int histogram_total_length, MOP classop) { int error = NO_ERROR; - DB_OBJECT *histogram_class, *histogram_obj, *edit_histogram_object = NULL; + DB_OBJECT *histogram_obj, *edit_histogram_object = NULL; DB_OTMPL *obj_tmpl = NULL; - DB_VALUE value[2]; - DB_VALUE *value_ptrs[2] = { &value[0], &value[1] }; DB_VALUE histogram_value; - const char *search_attrs[2] = { "class_of", "key_attr" }; - - histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); - if (histogram_class == NULL) - { - error = ER_BO_MISSING_OR_INVALID_CATALOG; - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); - goto end; - } - - /* class_of, key_attr */ - db_make_object (&value[0], classop); - db_make_string (&value[1], attr_name); - - histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_READ); - if (histogram_obj == NULL) + error = db_get_histogram (classop, attr_name, &histogram_obj); + if (error != NO_ERROR) { - error = ER_LC_CLASSNAME_EXIST; - char error_histogram[256]; - sprintf (error_histogram, "histogram of %s(%s)", sm_get_ch_name (classop), attr_name); - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, error_histogram); - goto end; + return error; } obj_tmpl = dbt_edit_object (histogram_obj); @@ -202,7 +184,7 @@ set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na goto end; } - db_make_varbit (&histogram_value, 1073741823, histogram_blob, histogram_total_length); + db_make_varbit (&histogram_value, 1073741823, histogram_blob, histogram_total_length * 8); error = dbt_put (obj_tmpl, "histogram_values", &histogram_value); if (error != NO_ERROR) { @@ -227,9 +209,89 @@ set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na } end: - db_value_clear (value_ptrs[0]); - db_value_clear (value_ptrs[1]); db_value_clear (&histogram_value); assert (error == NO_ERROR); // for debug return error; } + +void +histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) +{ + *selectivity = 0.0; + int error = NO_ERROR; + /* get object from db histogram class */ + assert (lhs->node_type == PT_NAME); + const char *tbl_name = lhs->info.name.resolved; + const char *attr_name = lhs->info.name.original; + MOP classop = db_find_class (tbl_name); + DB_VALUE histogram_value; + + DB_OBJECT *histogram_obj = NULL; + int histogram_total_length = 0; + error = db_get_histogram (classop, attr_name, &histogram_obj); + if (error != NO_ERROR) + { + return; + } + + if (histogram_obj == NULL) + { + *selectivity = (double) 0.001; + return; + } + + /* get histgoram */ + error = db_get (histogram_obj, "histogram_values", &histogram_value); + if (error != NO_ERROR) + { + *selectivity = (double) 0.001; + return; + } + const char *histogram_blob_ptr = db_get_bit (&histogram_value, &histogram_total_length); + if (histogram_blob_ptr == NULL || histogram_total_length <= 0) + { + *selectivity = (double) 0.001; + return; + } + // string_view로 변환할 때 명시적으로 길이 지정 + std::string_view histogram_blob (histogram_blob_ptr, static_cast (histogram_total_length / 8)); + + hist::HistogramReader histogram_reader; + error = histogram_reader.reset (histogram_blob); + if (error != NO_ERROR) + { + *selectivity = (double) 0.001; + return; + } + return; +} + +int +db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj) +{ + int error = NO_ERROR; + DB_OBJECT *histogram_class; + DB_OTMPL *obj_tmpl = NULL; + DB_VALUE value[2]; + DB_VALUE *value_ptrs[2] = { &value[0], &value[1] }; + DB_VALUE histogram_value; + const char *search_attrs[2] = { "class_of", "key_attr" }; + + histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); + if (histogram_class == NULL) + { + error = ER_BO_MISSING_OR_INVALID_CATALOG; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + return error; + } + + db_make_object (&value[0], classop); + db_make_string (&value[1], attr_name); + + *histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_READ); + + db_value_clear (value_ptrs[0]); + db_value_clear (value_ptrs[1]); + + return NO_ERROR; +} \ No newline at end of file diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index d9cbe02c281..85267616506 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -1,4 +1,9 @@ #include "thread_compat.hpp" + +// Forward declaration for PT_NODE +struct parser_node; +typedef struct parser_node PT_NODE; + static const char *HISTOGRAM_QUERY_TEMPLATE = "WITH src AS (SELECT %s AS val FROM %s WHERE %s IS NOT NULL), " "cnt AS (SELECT val, COUNT(*) AS c FROM src GROUP BY val), " @@ -30,3 +35,5 @@ int get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *att int with_fullscan, char **histogram_blob, int *histogram_total_length); int set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, char *histogram_blob, int histogram_total_length, MOP classop); +void histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); +int db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj); diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index 2f84eeb3cf2..d1829eae9a9 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -59,24 +59,24 @@ namespace hist return error; } - nb_ = get_value (&H->nbuckets); - str_size_ = get_value (&H->str_size); + nb_ = get_value (&H->nbuckets); + str_size_ = get_value (&H->str_size); type_ = static_cast (get_value (&H->type)); - total_size_ = get_value (&H->total_size); + total_size_ = get_value (&H->total_size); assert (total_size_ == blob_.size()); /* read index table for O(1) access to bucket record */ const char *p = blob_.data() + sizeof (HeaderV1); - const char *end = blob_.data() + blob_.size(); + const char *end = blob_.data() + total_size_; bucket_area_begin_ = p; /* find the last record */ - std::uint32_t max_off = BUCKET_RECORD_SIZE*nb_; + std::uint32_t max_off = BUCKET_RECORD_SIZE * nb_; const char *last = bucket_area_begin_ + max_off; - if (last + BUCKET_RECORD_SIZE > end) + if (last > end) { return ER_FAILED; } diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index 7a382273860..95dabdfdd7b 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -37,7 +37,7 @@ namespace hist std::uint32_t version; std::uint32_t nbuckets; std::uint32_t str_size; - std::uint32_t type; // Not Same to DB Type + std::uint32_t type; // DB_TYPE std::uint32_t total_size; // total size of the histogram }; diff --git a/src/optimizer/query_planner.c b/src/optimizer/query_planner.c index 64edc8814b5..1b777ab5f33 100644 --- a/src/optimizer/query_planner.c +++ b/src/optimizer/query_planner.c @@ -51,6 +51,7 @@ #include "network_interface_cl.h" #include "dbtype.h" #include "regu_var.hpp" +#include "histogram_cl.hpp" #define TEST_DUMP_PLAN_SCAN_COST 0 #define TEST_DUMP_PLAN_SORT_COST 0 @@ -9579,6 +9580,8 @@ qo_equal_selectivity (QO_ENV * env, PT_NODE * pt_expr) break; case PC_CONST: + histogram_get_equal_selectivity (lhs, rhs, &selectivity); + break; case PC_HOST_VAR: case PC_SUBQUERY: case PC_SET: From 8aa7230f7908cb0987ef98750a60520ecc906ba7 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 18 Nov 2025 20:28:43 +0900 Subject: [PATCH 040/112] =?UTF-8?q?selectivity=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EC=99=84=EB=A3=8C=20/=20=EB=B2=84?= =?UTF-8?q?=ED=82=B7=20=EC=9C=84=EC=B9=98=20=EC=88=98=EC=A0=95=20=ED=95=84?= =?UTF-8?q?=EC=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 18 ++++++++++++++ src/histogram/histogram_reader.cpp | 10 +++++++- src/histogram/histogram_reader.hpp | 40 +++++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index d2128151e1e..e248eab6f77 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -219,6 +219,7 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity { *selectivity = 0.0; int error = NO_ERROR; + std::uint32_t bucket_index = 0; /* get object from db histogram class */ assert (lhs->node_type == PT_NAME); const char *tbl_name = lhs->info.name.resolved; @@ -263,6 +264,23 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity *selectivity = (double) 0.001; return; } + + switch (rhs->info.value.db_value.domain.general_info.type) + { + case DB_TYPE_INTEGER: + { + std::int32_t val = db_get_int (&rhs->info.value.db_value); + bucket_index = histogram_reader.find_bucket (val); + break; + } + default: + assert (false); //TODO: Not implemented + break; + } + + *selectivity = (static_cast (histogram_reader.bucket_rows (bucket_index - 1)) / static_cast + (histogram_reader.total_rows())) / + static_cast (histogram_reader.bucket_approx_ndv (bucket_index)); return; } diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index d1829eae9a9..47c91a300bb 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -80,7 +80,7 @@ namespace hist { return ER_FAILED; } - buckets_end_ = last + BUCKET_RECORD_SIZE; // data + cumulative + buckets_end_ = last; if (buckets_end_ + str_size_ != end) { return ER_FAILED; @@ -136,6 +136,13 @@ namespace hist return get_value (bucket_hi_value_ptr (i)); } + template<> + std::int32_t HistogramReader::bucket_hi (std::uint32_t i) const + { + // DB_TYPE_INTEGER는 std::int64_t로 저장되지만, std::int32_t로 읽을 수 있음 + return static_cast (get_value (bucket_hi_value_ptr (i))); + } + template<> double HistogramReader::bucket_hi (std::uint32_t i) const { @@ -157,4 +164,5 @@ namespace hist return std::string_view{str_blob_.data() + off32, static_cast (len32)}; } + // ---------- get_equal_selectivity ---------- } // namespace hist diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index 95dabdfdd7b..f3fbe3386aa 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -66,9 +66,47 @@ namespace hist template T bucket_hi (std::uint32_t i) const; - std::int64_t bucket_rows (std::uint32_t i) const; + template + std::uint32_t find_bucket (const T &value) const + { + // nb_ == 0 은 설계상 거의 없겠지만, 방어적으로 처리 + if (nb_ == 0) + { + return 0; + } + + std::uint32_t lo = 0; + std::uint32_t hi = nb_ - 1; + std::uint32_t ans = nb_ - 1; // 기본값: 마지막 버킷 + while (lo <= hi) + { + std::uint32_t mid = lo + (hi - lo) / 2; + T hi_val = bucket_hi (mid); + + if (value <= hi_val) + { + // (low, hi] 에서 hi 부분에 들어감 → 후보 인덱스 + ans = mid; + if (mid == 0) + { + break; // 더 왼쪽은 없음 + } + hi = mid - 1; + } + else + { + // value > HI[mid] → 더 오른쪽 버킷을 봐야 함 + lo = mid + 1; + } + } + + // ans 는 항상 [0, nb_-1] 범위 + // - value > HI[nb_-1] 이면 갱신이 안 돼서 nb_-1 유지 + // - 그 외에는 lower_bound(HI, value) 결과 + return ans; + } private: template T get_value (const void *ptr) const; From 2954ff0df8d392bcc20b8c906c92ae548a0c877e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=86=8C=ED=9D=AC?= <94791489+sohee-dgist@users.noreply.github.com> Date: Wed, 19 Nov 2025 13:18:17 +0900 Subject: [PATCH 041/112] Add histogram review notes --- REVIEW_NOTES.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 REVIEW_NOTES.md diff --git a/REVIEW_NOTES.md b/REVIEW_NOTES.md new file mode 100644 index 00000000000..5187c35e15c --- /dev/null +++ b/REVIEW_NOTES.md @@ -0,0 +1,41 @@ +# Histogram PR 코드 리뷰 메모 (한국어) + +## 주요 이슈 및 개선 제안 + +1. **문자열 인라인 버킷 읽기 오류** + - `HistogramBuilder::write`에서 길이가 4 이하인 경우 길이 값을 기록하고 바로 데이터를 4바이트 슬롯에 복사합니다. 그러나 `HistogramReader::bucket_hi`는 `len32 <= 4`일 때 길이를 `len32 - 4`로 계산하여 잘못된 길이를 반환합니다. 길이가 4 이하인 문자열이 모두 빈 문자열로 잘리거나 큰 음수 길이로 해석될 수 있습니다. 인라인 데이터는 기록된 길이 전체(`len32`)를 그대로 사용하도록 수정하거나, 인라인/오프셋 포맷을 동일하게 역직렬화하는 보완이 필요합니다. + +2. **버킷 인덱스 언더플로우 및 선택도 계산** + - `histogram_get_equal_selectivity`에서 `find_bucket` 결과에 대해 `bucket_index - 1`을 사용해 이전 버킷 누적값을 참조하지만, 첫 번째 버킷(인덱스 0)일 때 언더플로우가 발생합니다. 최소 버킷 시 누적값을 0으로 처리하거나 인덱스를 보정하는 방어 코드가 필요합니다. 또한 NDV가 0인 경우를 고려한 0-division 방지 로직도 추가되면 좋습니다. + +3. **타입 확장 누락 및 TODO 처리** + - `histogram_get_equal_selectivity`는 현재 `DB_TYPE_INTEGER`만 지원하며 나머지 타입에서 `assert(false)`로 종료됩니다. BIGINT/DOUBLE/STRING 등 히스토그램이 지원하는 타입별 비교 경로를 구현하고, 미지원 시 기본 선택도로 graceful degrade 하는 것이 좋습니다. + - `histogram_cl.cpp`의 `number_of_mcv` 등 여러 TODO가 고정값으로 남아 있어 추후 상수 정의 또는 파라미터화가 필요합니다. + +4. **직렬화/역직렬화 구조 검증 부족** + - `HistogramReader::reset`은 `total_size_ == blob_.size()`를 `assert`만으로 검증하며, 더 작은 버퍼나 손상된 입력에 대한 에러 처리가 제한적입니다. `last > end` 외에도 헤더 크기/문자열 영역 경계 등을 명시적으로 검사하여 안전성을 높일 수 있습니다. + - `HistogramBuilder::build`의 헤더 필드(`str_size`, `total_size`)가 최종 버퍼에 반영된 뒤에도 `HeaderV1` 내부 멤버(`header_`)는 사용되지 않으므로 불필요하거나 일관성 검증이 어렵습니다. 헤더를 지역 변수로 두되, 빌드 완료 후 값을 검증하는 유닛 테스트를 추가하면 좋겠습니다. + +5. **수명 관리 및 변형 정밀도** + - `HistogramTypes`에 `std::string_view`를 허용하지만, `histogram_builder.add` 호출 시 원본 버퍼 수명이 보장되지 않으면 빌드 시점에 dangling 참조가 될 수 있습니다. `add`가 항상 소유권을 복사(`std::string`)하도록 정규화하거나, API에서 소유권 요구사항을 명확히 문서화해야 합니다. + - `add`의 기본 `approx_ndv`가 `quiet_NaN()`으로 초기화되어 정수 필드와 타입이 맞지 않습니다. NDV가 없을 때의 센티넬 값을 정수 범위에서 명확히 정의하거나 필드를 `double`로 전환하는 설계 재검토가 필요합니다. + +6. **네임스페이스/주석 일관성** + - `histogram_builder.hpp`의 네임스페이스 닫기 주석이 `// namespace histo`로 오타가 있습니다. 코드 전반의 네임스페이스 명시를 통일해 가독성을 높이세요. + +## 대규모 리팩토링 아이디어 + +- **직렬화 포맷 캡슐화**: 헤더/버킷/문자열 영역 접근을 별도 구조체로 분리하고, 읽기/쓰기 시 공통 헬퍼를 통해 패딩, 정렬, 엔디언 처리를 중앙집중화하면 이식성과 안정성이 개선됩니다. +- **타입별 정책 클래스 도입**: INT/BIGINT/DOUBLE/STRING에 대한 (비)교차 비교, 누적 계산, 문자열 인코딩 로직을 정책 클래스로 분리하면 `switch` 남발을 줄이고 신규 타입 추가가 쉬워집니다. +- **검증 및 Fuzz 테스트 추가**: 랜덤 버킷/데이터로 히스토그램을 생성한 뒤 직렬화→역직렬화→선택도 계산을 반복하는 프로퍼티 테스트를 추가하여 포맷 호환성과 경계 조건(빈 버킷, 단일 버킷, 매우 긴 문자열 등)을 검증하세요. +- **옵티마이저 연동 추상화**: `histogram_get_equal_selectivity`를 옵티마이저 공통 API로 래핑하고, 존재하지 않는 히스토그램일 때의 기본 선택도 정책을 한곳에서 관리하면 중복 로직과 매직 넘버를 줄일 수 있습니다. +- **리소스 관리 개선**: `db_private_alloc`/`db_private_free` 사용 구간을 RAII 래퍼로 감싸 메모리 누수에 안전하게 하고, 실패 시 정리 경로를 명확히 하는 편이 좋습니다. + +## 남아 있는 TODO/구현 공백 정리 + +- `histogram_get_equal_selectivity`의 비-INT 타입 처리 및 안전한 버킷 인덱스/NDV 보정. +- `histogram_builder`/`reader` 간 문자열 인라인 포맷 역직렬화 오류 수정. +- `number_of_mcv` 등 하드코딩된 상수의 설정화/파라미터화. +- 손상된 히스토그램 버퍼에 대한 검증/오류 처리 강화. +- `find_bucket`/`bucket_rows` 경계 조건(빈 버킷, 단일 버킷) 테스트 및 처리. +- 네임스페이스/주석 일관성 정리와 API 수명 규칙 문서화. From cd9495977137ea7d066b108d7c9278e62cb42ed5 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 25 Nov 2025 11:57:44 +0900 Subject: [PATCH 042/112] =?UTF-8?q?(=EB=B0=A9=EC=96=B4=EC=9A=A9=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80)=20=EB=94=94=EB=B2=84?= =?UTF-8?q?=EA=B9=85=EC=9A=A9/=20=ED=98=84=EC=9E=AC=20=EC=9E=98=20?= =?UTF-8?q?=EC=95=88=EB=90=98=EC=84=9C=20=EB=84=A3=EC=96=B4=EB=91=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_builder.cpp | 2 +- src/histogram/histogram_cl.cpp | 4 +-- src/histogram/histogram_reader.hpp | 45 +++++++++++++++++++---------- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/histogram/histogram_builder.cpp b/src/histogram/histogram_builder.cpp index b62f76a88f9..95d9ccd5616 100644 --- a/src/histogram/histogram_builder.cpp +++ b/src/histogram/histogram_builder.cpp @@ -93,7 +93,7 @@ namespace hist { // int64_t 값을 int32_t로 변환하여 저장 (실제로는 32bit 값이므로) std::int64_t val = std::get (b.data_hi); - write (buffer_ptr, static_cast (val)); + write (buffer_ptr, static_cast (val)); } else { diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index e248eab6f77..f990a7fe577 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -14,7 +14,7 @@ /* * analyze_all_classes - * + * * return: * with_fullscan(in): true iff WITH FULLSCAN * @@ -278,7 +278,7 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity break; } - *selectivity = (static_cast (histogram_reader.bucket_rows (bucket_index - 1)) / static_cast + *selectivity = (static_cast (histogram_reader.bucket_rows (bucket_index)) / static_cast (histogram_reader.total_rows())) / static_cast (histogram_reader.bucket_approx_ndv (bucket_index)); return; diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index f3fbe3386aa..f5e983c2545 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -70,42 +70,49 @@ namespace hist template std::uint32_t find_bucket (const T &value) const { - // nb_ == 0 은 설계상 거의 없겠지만, 방어적으로 처리 if (nb_ == 0) { - return 0; + return 0; // 방어용 } + // 오른쪽으로 튀면 마지막 버킷으로 클램프 + T max_val = bucket_hi (nb_ - 1); + if (value > max_val) + { + return nb_ - 1; + } + + // [0, nb_-1] 에서 lower_bound(HI, value) std::uint32_t lo = 0; std::uint32_t hi = nb_ - 1; - std::uint32_t ans = nb_ - 1; // 기본값: 마지막 버킷 - while (lo <= hi) + while (lo < hi) { std::uint32_t mid = lo + (hi - lo) / 2; T hi_val = bucket_hi (mid); + // hi 값은 포함이므로 value <= HI[mid] 면 왼쪽으로 좁힘 if (value <= hi_val) { - // (low, hi] 에서 hi 부분에 들어감 → 후보 인덱스 - ans = mid; - if (mid == 0) - { - break; // 더 왼쪽은 없음 - } - hi = mid - 1; + hi = mid; } else { - // value > HI[mid] → 더 오른쪽 버킷을 봐야 함 lo = mid + 1; } } - // ans 는 항상 [0, nb_-1] 범위 - // - value > HI[nb_-1] 이면 갱신이 안 돼서 nb_-1 유지 - // - 그 외에는 lower_bound(HI, value) 결과 - return ans; + // 여기 오면 lo == hi, 그리고 HI[lo] >= value 가 보장됨 + // 엔드포인트: [1, 2, 3] + // value = 0 → 0 + // value = 1 → 0 + // value = 2 → 1 + // value = 3 → 2 + // value > 3 → 위의 클램프 로직으로 2 + // 여기에서는 템플릿 특수화 (compare val에 대해서 필요할 것 같아 보임. (강조!)) + // 나머지 경우에 대해서는 잘 모르겠네.............. + return lo; + } private: template @@ -123,7 +130,13 @@ namespace hist std::uint32_t nb_ = 0; std::uint32_t str_size_ = 0; std::uint32_t total_size_ = 0; + // 타입은 디비 타입으로 도치시키는게 좋아 보인다. 뉴머릭 타입에 대해서는 double과 int로만 사용 되는 대충 히스토그램 비교성 비교만 해서 히스토그램을 만드는 것이 훨씬 더 이롭다. + // 왜냐하면 굳이 정확할 필요는 없을 거 같다. + + // 그러면 CHARSET에 대한 비교가 필요한데, 왜 CHARSET에 대한 비교는 COLLATION이 필요한 것일까? + std::uint32_t type_ = DB_TYPE_UNKNOWN; + }; From 44d8e1a09fec2b9e24ed24cd1a89d0f10541ff8b Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 27 Nov 2025 16:29:38 +0900 Subject: [PATCH 043/112] =?UTF-8?q?(feature)=20string/numeric/datetime=20t?= =?UTF-8?q?ype=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=9E=88=EC=8A=A4=ED=86=A0?= =?UTF-8?q?=EA=B7=B8=EB=9E=A8=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_builder.cpp | 9 +- src/histogram/histogram_builder.hpp | 2 +- src/histogram/histogram_cl.c | 0 src/histogram/histogram_cl.cpp | 209 ++++++++++++++++++++++++---- src/histogram/histogram_cl.hpp | 2 +- src/histogram/histogram_reader.cpp | 21 +++ src/histogram/histogram_reader.hpp | 6 +- 7 files changed, 212 insertions(+), 37 deletions(-) create mode 100644 src/histogram/histogram_cl.c diff --git a/src/histogram/histogram_builder.cpp b/src/histogram/histogram_builder.cpp index 95d9ccd5616..2019edfe7c3 100644 --- a/src/histogram/histogram_builder.cpp +++ b/src/histogram/histogram_builder.cpp @@ -168,6 +168,7 @@ namespace hist { return NULL; } + char *cur_str_blob_ptr = str_blob_ptr; std::memset (str_blob_ptr, 0, cur_str_off_); // initialize to zero char *str_blob_ptr_end = str_blob_ptr + cur_str_off_; for (const auto &b : buckets_) @@ -191,13 +192,13 @@ namespace hist if (str_val.length() > 4) { - memcpy (str_blob_ptr, str_val.data(), str_val.length()); - str_blob_ptr += str_val.length(); + memcpy (cur_str_blob_ptr, str_val.data(), str_val.length()); + cur_str_blob_ptr += str_val.length(); } } } // write string - assert (str_blob_ptr == str_blob_ptr_end); + assert (cur_str_blob_ptr == str_blob_ptr_end); buffer = static_cast (db_private_realloc (thread_p, buffer, sizeof (HeaderV1) + bucket_area_size + cur_str_off_)); if (buffer == NULL) @@ -206,14 +207,12 @@ namespace hist return NULL; } memcpy (buffer + sizeof (HeaderV1) + bucket_area_size, str_blob_ptr, cur_str_off_); - end_buffer += cur_str_off_; db_private_free (thread_p, str_blob_ptr); } H.str_size = htonl (static_cast (cur_str_off_)); H.total_size = htonl (static_cast (sizeof (HeaderV1) + bucket_area_size + cur_str_off_)); memcpy (buffer, &H, sizeof (HeaderV1)); - assert (static_cast (end_buffer - buffer) == sizeof (HeaderV1) + bucket_area_size + cur_str_off_); *histogram_total_length = sizeof (HeaderV1) + bucket_area_size + cur_str_off_; // write header diff --git a/src/histogram/histogram_builder.hpp b/src/histogram/histogram_builder.hpp index ae59dd72087..74087ed050b 100644 --- a/src/histogram/histogram_builder.hpp +++ b/src/histogram/histogram_builder.hpp @@ -8,7 +8,7 @@ namespace hist { - using HistogramTypes = std::variant; + using HistogramTypes = std::variant; struct Bucket { HistogramTypes data_hi; // std::variant: int32_t, int64_t, double, string 중 하나 diff --git a/src/histogram/histogram_cl.c b/src/histogram/histogram_cl.c new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index f990a7fe577..c579839ce64 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -14,7 +14,7 @@ /* * analyze_all_classes - * + * * return: * with_fullscan(in): true iff WITH FULLSCAN * @@ -53,10 +53,10 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na DB_QUERY_ERROR query_error; hist::HistogramBuilder histogram_builder; DB_TYPE type = DB_TYPE_UNKNOWN; - bool sampling_scan = false; + bool sampling_scan = true; int number_of_mcv = 3; // TODO - char query_buf[1024]; + char query_buf[1024+222+254]; // TODO GET MAX TABLE NAME LENGTH FROM SQL.H if (sampling_scan) { snprintf (query_buf, sizeof (query_buf), HISTOGRAM_WITH_SAMPLING_SCAN_QUERY_TEMPLATE, attr_name, tbl_name, @@ -93,63 +93,122 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na do { DB_VALUE value[5]; + hist::HistogramTypes hi{}; error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("bid"), &value[0]); error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("endpoint"), &value[1]); error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("rows_in_bucket"), &value[2]); error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("cumulative"), &value[3]); error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("approx_ndv"), &value[4]); - if (error != NO_ERROR) { return error; } - switch (value[1].domain.general_info.type) { case DB_TYPE_INTEGER: { - // int를 std::int64_t로 변환하여 variant 생성 - hist::HistogramTypes hi = static_cast < std::int64_t > (db_get_int (&value[1])); - histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); - type = DB_TYPE_INTEGER; + hi = static_cast < std::int64_t > (db_get_int (&value[1])); + break; + } + case DB_TYPE_SHORT: + { + hi = static_cast < std::int64_t > (db_get_short (&value[1])); break; } - case DB_TYPE_BIGINT: + case DB_TYPE_FLOAT: { - // int64_t를 variant로 생성 - std::int64_t val = db_get_bigint (&value[1]); - hist::HistogramTypes hi {val}; - histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); - type = DB_TYPE_BIGINT; + double val = db_get_float (&value[1]); + hi = val; break; } case DB_TYPE_DOUBLE: { - // double을 variant로 생성 double val = db_get_double (&value[1]); - hist::HistogramTypes hi {val}; - histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); - type = DB_TYPE_DOUBLE; + hi = val; + break; + } + case DB_TYPE_NUMERIC: + { + /* Actually, the numeric type is a 16-byte value with very high precision, + * but for approximate statistical calculations it's probably better not to + * rely on the full 16-byte precision. */ + double val; + numeric_coerce_num_to_double (db_get_numeric (&value[1]), db_value_scale (&value[1]), &val); + hi = val; + break; + } + case DB_TYPE_BIT: + case DB_TYPE_VARBIT: + { + /* deal as char type */ + int length = 0; + const char *str = db_get_bit (&value[1], &length); + if (str == NULL) + { + return ER_FAILED; + } + std::string str_val (str, length); + hi = str_val; break; } + case DB_TYPE_CHAR: /* later consider for null trailing exists */ case DB_TYPE_STRING: { - // string을 variant로 생성 (복사 생성으로 안전하게) const char *str = db_get_string (&value[1]); if (str == NULL) { return ER_FAILED; } - std::string str_val (str); // 복사 생성 - 안전 - hist::HistogramTypes hi {str_val}; - histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); - type = DB_TYPE_STRING; + std::string str_val (str); + hi = str_val; + break; + } + case DB_TYPE_TIME: + { + DB_TIME *time = db_get_time (&value[1]); + hi = static_cast (*time); + break; + } + case DB_TYPE_TIMESTAMP: + case DB_TYPE_TIMESTAMPLTZ: + { + DB_TIMESTAMP *timestamp = db_get_timestamp (&value[1]); + hi = static_cast (*timestamp); + break; + } + case DB_TYPE_DATE: + { + DB_DATE *date = db_get_date (&value[1]); + hi = static_cast (*date); + break; + } + case DB_TYPE_MONETARY: + { + /* Its use is deprecated, but it has been kept for backporting purposes. */ + DB_MONETARY *monetary = db_get_monetary (&value[1]); + hi = static_cast (monetary->amount); + break; + } + case DB_TYPE_TIMESTAMPTZ: + { + DB_TIMESTAMPTZ *timestamptz = db_get_timestamptz (&value[1]); + hi = static_cast (timestamptz->timestamp); + break; + } + case DB_TYPE_DATETIMETZ: + case DB_TYPE_DATETIMELTZ: + { + /* in comparison, the order is maintained by date and time */ + DB_DATETIMETZ *datetimetz = db_get_datetimetz (&value[1]); + hi = static_cast (datetimetz->datetime.date) << 32 | datetimetz->datetime.time; break; } default: - assert (false); + assert (false); /* impossible to reach here - blocked at parser layer first */ break; } + histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + type = static_cast (value[1].domain.general_info.type); } while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS); @@ -254,7 +313,8 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity *selectivity = (double) 0.001; return; } - // string_view로 변환할 때 명시적으로 길이 지정 + + /* need length of histogram_blob_ptr */ std::string_view histogram_blob (histogram_blob_ptr, static_cast (histogram_total_length / 8)); hist::HistogramReader histogram_reader; @@ -273,11 +333,106 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity bucket_index = histogram_reader.find_bucket (val); break; } + case DB_TYPE_SHORT: + { + std::int32_t val = static_cast (db_get_short (&rhs->info.value.db_value)); + bucket_index = histogram_reader.find_bucket (val); + break; + } + case DB_TYPE_FLOAT: + { + double val = db_get_float (&rhs->info.value.db_value); + bucket_index = histogram_reader.find_bucket (val); + break; + } + case DB_TYPE_DOUBLE: + { + double val = db_get_double (&rhs->info.value.db_value); + bucket_index = histogram_reader.find_bucket (val); + break; + } + case DB_TYPE_NUMERIC: + { + double val; + numeric_coerce_num_to_double (db_get_numeric (&rhs->info.value.db_value), db_value_scale (&rhs->info.value.db_value), + &val); + bucket_index = histogram_reader.find_bucket (val); + break; + } + case DB_TYPE_BIT: + case DB_TYPE_VARBIT: + { + int length = 0; + const char *str = db_get_bit (&rhs->info.value.db_value, &length); + if (str == NULL) + { + *selectivity = (double) 0.001; + return; + } + std::string str_val (str, length); + bucket_index = histogram_reader.find_bucket (str_val); + break; + } + case DB_TYPE_CHAR: /* later consider for null trailing exists */ + case DB_TYPE_STRING: + { + const char *str = db_get_string (&rhs->info.value.db_value); + if (str == NULL) + { + *selectivity = (double) 0.001; + return; + } + std::string str_val (str); + bucket_index = histogram_reader.find_bucket (str_val); + break; + } + case DB_TYPE_TIME: + { + + DB_TIME *time = db_get_time (&rhs->info.value.db_value); + bucket_index = histogram_reader.find_bucket (static_cast (*time)); + break; + } + case DB_TYPE_TIMESTAMP: + case DB_TYPE_TIMESTAMPLTZ: + { + + DB_TIMESTAMP *timestamp = db_get_timestamp (&rhs->info.value.db_value); + bucket_index = histogram_reader.find_bucket (static_cast (*timestamp)); + break; + } + case DB_TYPE_DATE: + { + DB_DATE *date = db_get_date (&rhs->info.value.db_value); + bucket_index = histogram_reader.find_bucket (static_cast (*date)); + break; + } + case DB_TYPE_MONETARY: + { + DB_MONETARY *monetary = db_get_monetary (&rhs->info.value.db_value); + bucket_index = histogram_reader.find_bucket (static_cast (monetary->amount)); + break; + } + case DB_TYPE_TIMESTAMPTZ: + { + DB_TIMESTAMPTZ *timestamptz = db_get_timestamptz (&rhs->info.value.db_value); + bucket_index = histogram_reader.find_bucket (static_cast (timestamptz->timestamp)); + break; + } + case DB_TYPE_DATETIMETZ: + case DB_TYPE_DATETIMELTZ: + { + DB_DATETIMETZ *datetimetz = db_get_datetimetz (&rhs->info.value.db_value); + bucket_index = histogram_reader.find_bucket (static_cast + (datetimetz->datetime.date) << 32 | datetimetz->datetime.time); + break; + } default: - assert (false); //TODO: Not implemented + assert (false); /* impossible to reach here - blocked at parser layer first */ break; } + *selectivity = (static_cast (histogram_reader.bucket_rows (bucket_index)) / static_cast (histogram_reader.total_rows())) / static_cast (histogram_reader.bucket_approx_ndv (bucket_index)); diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index 85267616506..c2715e02d92 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -36,4 +36,4 @@ int get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *att int set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, char *histogram_blob, int histogram_total_length, MOP classop); void histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); -int db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj); +int db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj); \ No newline at end of file diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index 47c91a300bb..d7954338d7d 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -164,5 +164,26 @@ namespace hist return std::string_view{str_blob_.data() + off32, static_cast (len32)}; } + template<> + std::string HistogramReader::bucket_hi (std::uint32_t i) const + { + const char *p = bucket_hi_value_ptr (i); + std::uint32_t len32 = get_value (p); + std::uint32_t off32 = get_value (p + 4); + + if (len32 <= 4) // inline data + { + return std::string{ p+4, static_cast (len32) }; + } + assert (off32 + len32 <= str_size_); + return std::string{str_blob_.data() + off32, static_cast (len32)}; + } + + template<> + unsigned long HistogramReader::bucket_hi (std::uint32_t i) const + { + return static_cast (get_value (bucket_hi_value_ptr (i))); + } + // ---------- get_equal_selectivity ---------- } // namespace hist diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index f5e983c2545..b8cda8eb1aa 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -109,8 +109,8 @@ namespace hist // value = 2 → 1 // value = 3 → 2 // value > 3 → 위의 클램프 로직으로 2 - // 여기에서는 템플릿 특수화 (compare val에 대해서 필요할 것 같아 보임. (강조!)) - // 나머지 경우에 대해서는 잘 모르겠네.............. + // 여기에서는 템플릿 특수화 (compare val에 대해서 필요할 것 같아 보임. (강조!)) + // 나머지 경우에 대해서는 잘 모르겠네.............. return lo; } @@ -134,7 +134,7 @@ namespace hist // 왜냐하면 굳이 정확할 필요는 없을 거 같다. // 그러면 CHARSET에 대한 비교가 필요한데, 왜 CHARSET에 대한 비교는 COLLATION이 필요한 것일까? - + std::uint32_t type_ = DB_TYPE_UNKNOWN; }; From d402b095b70eda5b2b209c01a8997a0116b9edd0 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 27 Nov 2025 17:18:03 +0900 Subject: [PATCH 044/112] =?UTF-8?q?(feature)=20MCV=EB=A5=BC=20CMP=EC=8B=9C?= =?UTF-8?q?=20=ED=99=95=EC=9D=B8=20=ED=95=A0=20=EC=88=98=20=EC=9E=88?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD=ED=95=98=EA=B8=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CMP 로직에 해당 사항 추가함. - MCV bucket이라면 뒤로 후퇴할 것 --- src/histogram/histogram_cl.cpp | 7 +++++- src/histogram/histogram_reader.cpp | 7 ++++-- src/histogram/histogram_reader.hpp | 37 +++++++++++++----------------- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index c579839ce64..4a81d4f951b 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -278,7 +278,7 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity { *selectivity = 0.0; int error = NO_ERROR; - std::uint32_t bucket_index = 0; + int bucket_index = 0; /* get object from db histogram class */ assert (lhs->node_type == PT_NAME); const char *tbl_name = lhs->info.name.resolved; @@ -431,7 +431,12 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity assert (false); /* impossible to reach here - blocked at parser layer first */ break; } + if (bucket_index == -1) /* not found */ + { + *selectivity = 0.0; + return; + } *selectivity = (static_cast (histogram_reader.bucket_rows (bucket_index)) / static_cast (histogram_reader.total_rows())) / diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index d7954338d7d..762ad79b936 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -118,12 +118,15 @@ namespace hist assert (i < nb_); const char *rec = bucket_rec (i); const char *p = rec + 16; - return get_value (p); + std::int64_t result; + result = get_value (p); + assert (result > 0); + return result; } std::int64_t HistogramReader::bucket_rows (std::uint32_t i) const { - assert (i < nb_); + assert (i < 0 || i < nb_); const std::int64_t cur = bucket_cumulative (i); const std::int64_t prev = (i == 0) ? 0 : bucket_cumulative (i - 1); return cur - prev; diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index b8cda8eb1aa..f5c1568a654 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -68,30 +68,27 @@ namespace hist T bucket_hi (std::uint32_t i) const; std::int64_t bucket_rows (std::uint32_t i) const; template - std::uint32_t find_bucket (const T &value) const + int find_bucket (const T &value) const { if (nb_ == 0) { - return 0; // 방어용 + return -1; } - // 오른쪽으로 튀면 마지막 버킷으로 클램프 T max_val = bucket_hi (nb_ - 1); if (value > max_val) { return nb_ - 1; } - // [0, nb_-1] 에서 lower_bound(HI, value) - std::uint32_t lo = 0; - std::uint32_t hi = nb_ - 1; + int lo = 0; + int hi = nb_ - 1; while (lo < hi) { - std::uint32_t mid = lo + (hi - lo) / 2; + int mid = lo + (hi - lo) / 2; T hi_val = bucket_hi (mid); - // hi 값은 포함이므로 value <= HI[mid] 면 왼쪽으로 좁힘 if (value <= hi_val) { hi = mid; @@ -102,15 +99,17 @@ namespace hist } } - // 여기 오면 lo == hi, 그리고 HI[lo] >= value 가 보장됨 - // 엔드포인트: [1, 2, 3] - // value = 0 → 0 - // value = 1 → 0 - // value = 2 → 1 - // value = 3 → 2 - // value > 3 → 위의 클램프 로직으로 2 - // 여기에서는 템플릿 특수화 (compare val에 대해서 필요할 것 같아 보임. (강조!)) - // 나머지 경우에 대해서는 잘 모르겠네.............. + if (bucket_approx_ndv (lo) == 1) + { + T mcv_val = bucket_hi (lo); + + if (! (value == mcv_val)) + { + /* this is not MCV value */ + return -1; + } + } + return lo; } @@ -130,10 +129,6 @@ namespace hist std::uint32_t nb_ = 0; std::uint32_t str_size_ = 0; std::uint32_t total_size_ = 0; - // 타입은 디비 타입으로 도치시키는게 좋아 보인다. 뉴머릭 타입에 대해서는 double과 int로만 사용 되는 대충 히스토그램 비교성 비교만 해서 히스토그램을 만드는 것이 훨씬 더 이롭다. - // 왜냐하면 굳이 정확할 필요는 없을 거 같다. - - // 그러면 CHARSET에 대한 비교가 필요한데, 왜 CHARSET에 대한 비교는 COLLATION이 필요한 것일까? std::uint32_t type_ = DB_TYPE_UNKNOWN; From 2c467292c308b78ffb36a0238c4a2f88d126b2c3 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 27 Nov 2025 17:32:12 +0900 Subject: [PATCH 045/112] =?UTF-8?q?(bugfix)=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EC=82=AC=ED=95=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_reader.hpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index f5c1568a654..8dccd3898c9 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -99,14 +99,28 @@ namespace hist } } - if (bucket_approx_ndv (lo) == 1) + /* mcv check */ + while (lo >= 0 && lo < nb_ && bucket_approx_ndv (lo) == 1) { T mcv_val = bucket_hi (lo); - if (! (value == mcv_val)) + if (value == mcv_val) { - /* this is not MCV value */ - return -1; + return lo; + } + + if (value < mcv_val) + { + --lo; + } + else + { + assert (false); /* impossible */ + } + + if (lo < 0 || lo >= nb_) + { + break; } } From 7084aeab814551c0f10187234a1c0a5d809a4662 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 27 Nov 2025 17:40:29 +0900 Subject: [PATCH 046/112] =?UTF-8?q?(indent/refactor)=20license=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_builder.cpp | 24 ++++++++++++++++++++++-- src/histogram/histogram_builder.hpp | 27 +++++++++++++++++++++++++++ src/histogram/histogram_cl.cpp | 23 +++++++++++++++++++++++ src/histogram/histogram_cl.hpp | 29 ++++++++++++++++++++++++++++- src/histogram/histogram_reader.cpp | 22 ++++++++++++++++++++++ src/histogram/histogram_reader.hpp | 28 +++++++++++++++++++++++++++- 6 files changed, 149 insertions(+), 4 deletions(-) diff --git a/src/histogram/histogram_builder.cpp b/src/histogram/histogram_builder.cpp index 2019edfe7c3..5830de3c79c 100644 --- a/src/histogram/histogram_builder.cpp +++ b/src/histogram/histogram_builder.cpp @@ -1,3 +1,25 @@ +/* + * Copyright 2008 Search Solution Corporation + * Copyright 2016 CUBRID Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* + * histogram_builder.cpp - Histogram builder implementation + */ + #include "histogram_builder.hpp" #include "histogram_reader.hpp" #include @@ -130,14 +152,12 @@ namespace hist break; case DB_TYPE_STRING: { - // variant에 string_view나 string이 있을 수 있음 if (std::holds_alternative (b.data_hi)) { write (buffer_ptr, std::get (b.data_hi)); } else if (std::holds_alternative (b.data_hi)) { - // string_view를 string으로 변환 std::string_view sv = std::get (b.data_hi); write (buffer_ptr, std::string (sv)); } diff --git a/src/histogram/histogram_builder.hpp b/src/histogram/histogram_builder.hpp index 74087ed050b..7c8d6389743 100644 --- a/src/histogram/histogram_builder.hpp +++ b/src/histogram/histogram_builder.hpp @@ -1,3 +1,28 @@ +/* + * Copyright 2008 Search Solution Corporation + * Copyright 2016 CUBRID Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* + * histogram_builder.hpp - Histogram builder declaration + */ + +#ifndef _HISTOGRAM_BUILDER_HPP_ +#define _HISTOGRAM_BUILDER_HPP_ + #include #include #include @@ -34,3 +59,5 @@ namespace hist }; } // namespace histo + +#endif // _HISTOGRAM_BUILDER_HPP_ \ No newline at end of file diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 4a81d4f951b..e76ce878966 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -1,3 +1,26 @@ +/* + * Copyright 2008 Search Solution Corporation + * Copyright 2016 CUBRID Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* + * histogram_cl.cpp - Histogram Client implementation + */ + + #include "dbtype_def.h" #include "histogram_cl.hpp" #include "db.h" diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index c2715e02d92..7a1ebab421c 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -1,3 +1,28 @@ +/* + * Copyright 2008 Search Solution Corporation + * Copyright 2016 CUBRID Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* +* histogram_cl.hpp - Histogram class declaration +*/ + +#ifndef _HISTOGRAM_CL_HPP_ +#define _HISTOGRAM_CL_HPP_ + #include "thread_compat.hpp" // Forward declaration for PT_NODE @@ -36,4 +61,6 @@ int get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *att int set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, char *histogram_blob, int histogram_total_length, MOP classop); void histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); -int db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj); \ No newline at end of file +int db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj); + +#endif // _HISTOGRAM_CL_HPP_ \ No newline at end of file diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index 762ad79b936..2d2d382ba5e 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -1,3 +1,25 @@ +/* + * Copyright 2008 Search Solution Corporation + * Copyright 2016 CUBRID Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* +* histogram_reader.cpp - Histogram reader implementation +*/ + #include "histogram_reader.hpp" #include #include diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index 8dccd3898c9..29041509e16 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -1,4 +1,28 @@ -#pragma once +/* + * Copyright 2008 Search Solution Corporation + * Copyright 2016 CUBRID Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* +* histogram_reader.hpp - Histogram reader declaration +*/ + +#ifndef _HISTOGRAM_READER_HPP_ +#define _HISTOGRAM_READER_HPP_ + #include #include #include @@ -150,3 +174,5 @@ namespace hist } // namespace hist + +#endif // _HISTOGRAM_READER_HPP_ \ No newline at end of file From 1abc4dfbe39a50c4ceb597edcb73a8c77e8c3044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=86=8C=ED=9D=AC?= <94791489+sohee-dgist@users.noreply.github.com> Date: Thu, 27 Nov 2025 20:10:58 +0900 Subject: [PATCH 047/112] Delete src/histogram/histogram_cl.c --- src/histogram/histogram_cl.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/histogram/histogram_cl.c diff --git a/src/histogram/histogram_cl.c b/src/histogram/histogram_cl.c deleted file mode 100644 index e69de29bb2d..00000000000 From 070b1d81e3e74b8b3143fecb33edba903fe7e368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=86=8C=ED=9D=AC?= <94791489+sohee-dgist@users.noreply.github.com> Date: Thu, 27 Nov 2025 20:11:32 +0900 Subject: [PATCH 048/112] Delete REVIEW_NOTES.md --- REVIEW_NOTES.md | 41 ----------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 REVIEW_NOTES.md diff --git a/REVIEW_NOTES.md b/REVIEW_NOTES.md deleted file mode 100644 index 5187c35e15c..00000000000 --- a/REVIEW_NOTES.md +++ /dev/null @@ -1,41 +0,0 @@ -# Histogram PR 코드 리뷰 메모 (한국어) - -## 주요 이슈 및 개선 제안 - -1. **문자열 인라인 버킷 읽기 오류** - - `HistogramBuilder::write`에서 길이가 4 이하인 경우 길이 값을 기록하고 바로 데이터를 4바이트 슬롯에 복사합니다. 그러나 `HistogramReader::bucket_hi`는 `len32 <= 4`일 때 길이를 `len32 - 4`로 계산하여 잘못된 길이를 반환합니다. 길이가 4 이하인 문자열이 모두 빈 문자열로 잘리거나 큰 음수 길이로 해석될 수 있습니다. 인라인 데이터는 기록된 길이 전체(`len32`)를 그대로 사용하도록 수정하거나, 인라인/오프셋 포맷을 동일하게 역직렬화하는 보완이 필요합니다. - -2. **버킷 인덱스 언더플로우 및 선택도 계산** - - `histogram_get_equal_selectivity`에서 `find_bucket` 결과에 대해 `bucket_index - 1`을 사용해 이전 버킷 누적값을 참조하지만, 첫 번째 버킷(인덱스 0)일 때 언더플로우가 발생합니다. 최소 버킷 시 누적값을 0으로 처리하거나 인덱스를 보정하는 방어 코드가 필요합니다. 또한 NDV가 0인 경우를 고려한 0-division 방지 로직도 추가되면 좋습니다. - -3. **타입 확장 누락 및 TODO 처리** - - `histogram_get_equal_selectivity`는 현재 `DB_TYPE_INTEGER`만 지원하며 나머지 타입에서 `assert(false)`로 종료됩니다. BIGINT/DOUBLE/STRING 등 히스토그램이 지원하는 타입별 비교 경로를 구현하고, 미지원 시 기본 선택도로 graceful degrade 하는 것이 좋습니다. - - `histogram_cl.cpp`의 `number_of_mcv` 등 여러 TODO가 고정값으로 남아 있어 추후 상수 정의 또는 파라미터화가 필요합니다. - -4. **직렬화/역직렬화 구조 검증 부족** - - `HistogramReader::reset`은 `total_size_ == blob_.size()`를 `assert`만으로 검증하며, 더 작은 버퍼나 손상된 입력에 대한 에러 처리가 제한적입니다. `last > end` 외에도 헤더 크기/문자열 영역 경계 등을 명시적으로 검사하여 안전성을 높일 수 있습니다. - - `HistogramBuilder::build`의 헤더 필드(`str_size`, `total_size`)가 최종 버퍼에 반영된 뒤에도 `HeaderV1` 내부 멤버(`header_`)는 사용되지 않으므로 불필요하거나 일관성 검증이 어렵습니다. 헤더를 지역 변수로 두되, 빌드 완료 후 값을 검증하는 유닛 테스트를 추가하면 좋겠습니다. - -5. **수명 관리 및 변형 정밀도** - - `HistogramTypes`에 `std::string_view`를 허용하지만, `histogram_builder.add` 호출 시 원본 버퍼 수명이 보장되지 않으면 빌드 시점에 dangling 참조가 될 수 있습니다. `add`가 항상 소유권을 복사(`std::string`)하도록 정규화하거나, API에서 소유권 요구사항을 명확히 문서화해야 합니다. - - `add`의 기본 `approx_ndv`가 `quiet_NaN()`으로 초기화되어 정수 필드와 타입이 맞지 않습니다. NDV가 없을 때의 센티넬 값을 정수 범위에서 명확히 정의하거나 필드를 `double`로 전환하는 설계 재검토가 필요합니다. - -6. **네임스페이스/주석 일관성** - - `histogram_builder.hpp`의 네임스페이스 닫기 주석이 `// namespace histo`로 오타가 있습니다. 코드 전반의 네임스페이스 명시를 통일해 가독성을 높이세요. - -## 대규모 리팩토링 아이디어 - -- **직렬화 포맷 캡슐화**: 헤더/버킷/문자열 영역 접근을 별도 구조체로 분리하고, 읽기/쓰기 시 공통 헬퍼를 통해 패딩, 정렬, 엔디언 처리를 중앙집중화하면 이식성과 안정성이 개선됩니다. -- **타입별 정책 클래스 도입**: INT/BIGINT/DOUBLE/STRING에 대한 (비)교차 비교, 누적 계산, 문자열 인코딩 로직을 정책 클래스로 분리하면 `switch` 남발을 줄이고 신규 타입 추가가 쉬워집니다. -- **검증 및 Fuzz 테스트 추가**: 랜덤 버킷/데이터로 히스토그램을 생성한 뒤 직렬화→역직렬화→선택도 계산을 반복하는 프로퍼티 테스트를 추가하여 포맷 호환성과 경계 조건(빈 버킷, 단일 버킷, 매우 긴 문자열 등)을 검증하세요. -- **옵티마이저 연동 추상화**: `histogram_get_equal_selectivity`를 옵티마이저 공통 API로 래핑하고, 존재하지 않는 히스토그램일 때의 기본 선택도 정책을 한곳에서 관리하면 중복 로직과 매직 넘버를 줄일 수 있습니다. -- **리소스 관리 개선**: `db_private_alloc`/`db_private_free` 사용 구간을 RAII 래퍼로 감싸 메모리 누수에 안전하게 하고, 실패 시 정리 경로를 명확히 하는 편이 좋습니다. - -## 남아 있는 TODO/구현 공백 정리 - -- `histogram_get_equal_selectivity`의 비-INT 타입 처리 및 안전한 버킷 인덱스/NDV 보정. -- `histogram_builder`/`reader` 간 문자열 인라인 포맷 역직렬화 오류 수정. -- `number_of_mcv` 등 하드코딩된 상수의 설정화/파라미터화. -- 손상된 히스토그램 버퍼에 대한 검증/오류 처리 강화. -- `find_bucket`/`bucket_rows` 경계 조건(빈 버킷, 단일 버킷) 테스트 및 처리. -- 네임스페이스/주석 일관성 정리와 API 수명 규칙 문서화. From f411ba68a419ef21ac8715631a6f0b271e64c12b Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 28 Nov 2025 16:51:44 +0900 Subject: [PATCH 049/112] =?UTF-8?q?(feature)=20ANALYZE=20HISTOGRAM=20?= =?UTF-8?q?=EB=AC=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cubridmanager | 2 +- src/histogram/histogram_reader.cpp | 2 +- src/histogram/histogram_reader.hpp | 4 +- src/object/schema_manager.c | 4 +- src/object/schema_manager.h | 2 +- src/object/schema_system_catalog_install.cpp | 4 +- ...hema_system_catalog_install_query_spec.cpp | 2 +- src/object/schema_template.c | 10 +-- src/object/schema_template.h | 2 +- src/object/transform.c | 2 +- src/parser/csql_grammar.y | 80 +++++++++++++++++++ src/parser/csql_lexer.l | 1 + src/parser/parse_tree.h | 2 +- src/parser/parse_tree_cl.c | 4 +- src/query/execute_schema.c | 7 +- 15 files changed, 100 insertions(+), 28 deletions(-) diff --git a/cubridmanager b/cubridmanager index aee66659e11..7cbb7001ac3 160000 --- a/cubridmanager +++ b/cubridmanager @@ -1 +1 @@ -Subproject commit aee66659e11bec1b426ec11f872d36a9345425f8 +Subproject commit 7cbb7001ac3ab5c68c234b5d8d5214727e65833f diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index 2d2d382ba5e..98ec58a8f7d 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -148,7 +148,7 @@ namespace hist std::int64_t HistogramReader::bucket_rows (std::uint32_t i) const { - assert (i < 0 || i < nb_); + assert (i < nb_); const std::int64_t cur = bucket_cumulative (i); const std::int64_t prev = (i == 0) ? 0 : bucket_cumulative (i - 1); return cur - prev; diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index 29041509e16..a1cb343c1ca 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -124,7 +124,7 @@ namespace hist } /* mcv check */ - while (lo >= 0 && lo < nb_ && bucket_approx_ndv (lo) == 1) + while (lo >= 0 && lo < static_cast (nb_) && bucket_approx_ndv (lo) == 1) { T mcv_val = bucket_hi (lo); @@ -142,7 +142,7 @@ namespace hist assert (false); /* impossible */ } - if (lo < 0 || lo >= nb_) + if (lo < 0 || lo >= static_cast (nb_)) { break; } diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index cca54297a87..33e030686cc 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -15530,7 +15530,7 @@ sm_save_constraint_info (SM_CONSTRAINT_INFO ** save_info, const SM_CLASS_CONSTRA int -sm_add_histogram (MOP classop, const char *attr_name, int histogram_type, int bucket_count) +sm_add_histogram (MOP classop, const char *attr_name, int bucket_count, bool with_fullscan) { bool set_savepoint = false; int error = NO_ERROR; @@ -15561,7 +15561,7 @@ sm_add_histogram (MOP classop, const char *attr_name, int histogram_type, int bu goto error_exit; } - error = smt_add_histogram (classop, attr_name, histogram_type, bucket_count); + error = smt_add_histogram (classop, attr_name, bucket_count, with_fullscan); if (error != NO_ERROR) { goto error_exit; diff --git a/src/object/schema_manager.h b/src/object/schema_manager.h index 82932eb3c09..044f1f444d5 100644 --- a/src/object/schema_manager.h +++ b/src/object/schema_manager.h @@ -112,7 +112,7 @@ extern int sm_add_constraint (MOP classop, DB_CONSTRAINT_TYPE constraint_type, c const char **att_names, const int *asc_desc, const int *attrs_prefix_length, int class_attributes, SM_PREDICATE_INFO * predicate_info, SM_FUNCTION_INFO * fi_info, const char *comment, SM_INDEX_STATUS index_status); -extern int sm_add_histogram (MOP classop, const char *attr_name, int histogram_type, int bucket_count); +extern int sm_add_histogram (MOP classop, const char *attr_name, int bucket_count, bool with_fullscan); extern int sm_drop_histogram (MOP classop, const char *attr_name); extern int sm_drop_constraint (MOP classop, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name, const char **att_names, bool class_attributes, bool mysql_index_name); diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index b8da7b827a9..9715ccf1fc6 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -1285,7 +1285,7 @@ namespace cubschema { {"class_of", "object"}, {"key_attr", format_varchar (255)}, - {"histogram_type","integer"}, + {"with_fullscan","integer"}, {"bucket_count", "integer"}, {"histogram_values", format_varbit (1073741823) } }, @@ -2080,7 +2080,7 @@ namespace cubschema { {"class_of", "object"}, {"key_attr", format_varchar (255)}, - {"histogram_type","integer"}, + {"with_fullscan","integer"}, {"bucket_count", "integer"}, {"histogram_values", format_varbit (1024)}, {attribute_kind::QUERY_SPEC, sm_define_view_db_histogram_spec ()} diff --git a/src/object/schema_system_catalog_install_query_spec.cpp b/src/object/schema_system_catalog_install_query_spec.cpp index a599296be32..a74247b7baa 100644 --- a/src/object/schema_system_catalog_install_query_spec.cpp +++ b/src/object/schema_system_catalog_install_query_spec.cpp @@ -1535,7 +1535,7 @@ sm_define_view_db_histogram_spec (void) "SELECT " "[h].[class_of] AS [class_of], " "[h].[key_attr] AS [key_attr], " - "[h].[histogram_type] AS [histogram_type], " // TODO : integer -> varchar(32) + "[h].[with_fullscan] AS [with_fullscan], " // TODO : integer -> varchar(32) "[h].[bucket_count] AS [bucket_count], " "[h].[histogram_values] AS [histogram_values] " "FROM " diff --git a/src/object/schema_template.c b/src/object/schema_template.c index 6f1c2d863b5..a8c90b26fd8 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -2044,7 +2044,7 @@ smt_check_histogram_exist_and_delete (MOP classop, const char *attr_name, bool n } int -smt_add_histogram (MOP classop, const char *attr_name, int histogram_type, int bucket_count) +smt_add_histogram (MOP classop, const char *attr_name, int bucket_count, bool with_fullscan) { int au_save, error = NO_ERROR; DB_OBJECT *ret_obj = NULL, *histogram_class = NULL; @@ -2090,14 +2090,6 @@ smt_add_histogram (MOP classop, const char *attr_name, int histogram_type, int b goto end; } - /* histogram_type */ - db_make_int (&value, histogram_type); - error = dbt_put_internal (obj_tmpl, "histogram_type", &value); - pr_clear_value (&value); - if (error != NO_ERROR) - { - goto end; - } /* bucket_count */ db_make_int (&value, bucket_count); error = dbt_put_internal (obj_tmpl, "bucket_count", &value); diff --git a/src/object/schema_template.h b/src/object/schema_template.h index 4d80d2861be..4b8d800b741 100644 --- a/src/object/schema_template.h +++ b/src/object/schema_template.h @@ -84,7 +84,7 @@ extern int smt_add_constraint (SM_TEMPLATE * template_, DB_CONSTRAINT_TYPE const int class_attribute, SM_FOREIGN_KEY_INFO * fk_info, SM_PREDICATE_INFO * filter_index, SM_FUNCTION_INFO * function_index, const char *comment, SM_INDEX_STATUS index_status); -extern int smt_add_histogram (MOP classop, const char *attr_name, int histogram_type, int bucket_count); +extern int smt_add_histogram (MOP classop, const char *attr_name, int bucket_count, bool with_fullscan); extern int smt_drop_constraint (SM_TEMPLATE * template_, const char **att_names, const char *constraint_name, int class_attribute, SM_ATTRIBUTE_FLAG constraint); diff --git a/src/object/transform.c b/src/object/transform.c index c0be1087ecc..041241f60a0 100644 --- a/src/object/transform.c +++ b/src/object/transform.c @@ -419,7 +419,7 @@ static CT_ATTR ct_partition_atts[] = { static CT_ATTR ct_histogram_atts[] = { {"class_of", NULL_ATTRID, DB_TYPE_OBJECT}, {"key_attr", NULL_ATTRID, DB_TYPE_VARCHAR}, - {"histogram_type", NULL_ATTRID, DB_TYPE_INTEGER}, + {"with_fullscan", NULL_ATTRID, DB_TYPE_INTEGER}, {"bucket_count", NULL_ATTRID, DB_TYPE_INTEGER} }; diff --git a/src/parser/csql_grammar.y b/src/parser/csql_grammar.y index 47d301f2a5a..912ab607d04 100644 --- a/src/parser/csql_grammar.y +++ b/src/parser/csql_grammar.y @@ -707,11 +707,13 @@ BEGIN_SUPPRESS_WARNING_BISON_FLEX %type rename_class_list %type rename_class_pair %type drop_stmt +%type drop_histogram_stmt %type opt_index_column_name_list %type index_column_name_list %type histogram_column_list %type histogram_column %type update_statistics_stmt +%type update_histogram_stmt %type only_class_name_list %type opt_level_spec %type char_string_literal_list @@ -1174,6 +1176,7 @@ BEGIN_SUPPRESS_WARNING_BISON_FLEX %token BOOLEAN_ %token BOTH_ %token BREADTH +%token BUCKETS %token BY %token CALL %token CASCADE @@ -1988,6 +1991,12 @@ stmt_ | update_statistics_stmt { DBG_TRACE_GRAMMAR(stmt_, | update_statstics_stmt); $$ = $1; } + | update_histogram_stmt + { DBG_TRACE_GRAMMAR(stmt_, | update_histogram_stmt); + $$ = $1; } + | drop_histogram_stmt + { DBG_TRACE_GRAMMAR(stmt_, | drop_histogram_stmt); + $$ = $1; } | drop_stmt { DBG_TRACE_GRAMMAR(stmt_, | drop_stmt); $$ = $1; } @@ -5180,6 +5189,77 @@ update_statistics_stmt DBG_PRINT}} ; +update_histogram_stmt + : ANALYZE TABLE only_class_name UPDATE HISTOGRAM ON_ histogram_column_list WITH unsigned_integer BUCKETS opt_with_fullscan + {{ DBG_TRACE_GRAMMAR(update_histogram_stmt, | ANALYZE TABLE only_class_name UPDATE HISTOGRAM ON histogram_column_list WITH unsigned_integer BUCKETS opt_with_fullscan ); + PT_NODE *uhs = parser_new_node (this_parser, PT_CREATE_HISTOGRAM); + PT_NODE *target_t = parser_new_node (this_parser, PT_SPEC); + if (uhs && target_t) + { + target_t->info.spec.entity_name = $3; + PARSER_SAVE_ERR_CONTEXT (target_t, @3.buffer_pos) + target_t->info.spec.meta_class = PT_CLASS; + uhs->info.histogram.target_table_spec = target_t; + + uhs->info.histogram.target_columns = $7; + uhs->info.histogram.bucket_count = $9->info.value.data_value.i; + uhs->info.histogram.with_fullscan = $11; + } + + $$ = uhs; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT }} + | ANALYZE TABLE only_class_name UPDATE HISTOGRAM WITH unsigned_integer BUCKETS opt_with_fullscan + {{ DBG_TRACE_GRAMMAR(update_histogram_stmt, | ANALYZE TABLE only_class_name UPDATE HISTOGRAM WITH unsigned_integer BUCKETS opt_with_fullscan ); + PT_NODE *uhs = parser_new_node (this_parser, PT_CREATE_HISTOGRAM); + PT_NODE *target_t = parser_new_node (this_parser, PT_SPEC); + if (uhs && target_t) + { + target_t->info.spec.entity_name = $3; + PARSER_SAVE_ERR_CONTEXT (target_t, @3.buffer_pos) + target_t->info.spec.meta_class = PT_CLASS; + uhs->info.histogram.target_table_spec = target_t; + uhs->info.histogram.target_columns = NULL; + uhs->info.histogram.bucket_count = $7->info.value.data_value.i; + uhs->info.histogram.with_fullscan = $9; + } + + $$ = uhs; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT }} + ; +drop_histogram_stmt + : ANALYZE TABLE only_class_name DROP HISTOGRAM ON_ histogram_column_list + {{ DBG_TRACE_GRAMMAR(drop_histogram_stmt, | ANALYZE TABLE only_class_name DROP HISTOGRAM ON histogram_column_list); + PT_NODE *dhs = parser_new_node (this_parser, PT_DROP_HISTOGRAM); + PT_NODE *target_t = parser_new_node (this_parser, PT_SPEC); + if (dhs && target_t) + { + target_t->info.spec.entity_name = $3; + PARSER_SAVE_ERR_CONTEXT (target_t, @3.buffer_pos) + target_t->info.spec.meta_class = PT_CLASS; + dhs->info.histogram.target_table_spec = target_t; + dhs->info.histogram.target_columns = $7; + } + $$ = dhs; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT }} + | ANALYZE TABLE only_class_name DROP HISTOGRAM + {{ DBG_TRACE_GRAMMAR(drop_histogram_stmt, | ANALYZE TABLE only_class_name DROP HISTOGRAM ON histogram_column_list); + PT_NODE *dhs = parser_new_node (this_parser, PT_DROP_HISTOGRAM); + PT_NODE *target_t = parser_new_node (this_parser, PT_SPEC); + if (dhs && target_t) + { + target_t->info.spec.entity_name = $3; + PARSER_SAVE_ERR_CONTEXT (target_t, @3.buffer_pos) + target_t->info.spec.meta_class = PT_CLASS; + dhs->info.histogram.target_table_spec = target_t; + } + $$ = dhs; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT }} + ; + only_class_name_list : only_class_name_list ',' only_class_name {{ DBG_TRACE_GRAMMAR(only_class_name_list, : only_class_name_list ',' only_class_name); diff --git a/src/parser/csql_lexer.l b/src/parser/csql_lexer.l index e8a3fb09386..a39b546493d 100644 --- a/src/parser/csql_lexer.l +++ b/src/parser/csql_lexer.l @@ -201,6 +201,7 @@ IDL [a-zA-Z0-9_] [bB][oO][oO][lL][eE][aA][nN] { begin_token(yytext); return BOOLEAN_; } [bB][oO][tT][hH] { begin_token(yytext); return BOTH_; } [bB][rR][eE][aA][dD][tT][hH] { begin_token(yytext); return BREADTH; } +[bB][uU][cC][kK][eE][tT][sS] { begin_token(yytext); return BUCKETS; } [bB][yY] { begin_token(yytext); return BY; } [bB][uU][fF][fF][eE][rR] { begin_token(yytext); csql_yylval.cptr = pt_makename(yytext); diff --git a/src/parser/parse_tree.h b/src/parser/parse_tree.h index 3eda7042e0d..554c09b681b 100644 --- a/src/parser/parse_tree.h +++ b/src/parser/parse_tree.h @@ -1987,8 +1987,8 @@ struct pt_histogram_info { PT_NODE *target_table_spec; /* PT_SPEC */ PT_NODE *target_columns; /* PT_COLUMN_LIST (PT_NAME) */ - int histogram_type; /* histogram type */ int bucket_count; /* bucket count */ + int with_fullscan; /* with fullscan */ }; /* CREATE/DROP INDEX INFO */ diff --git a/src/parser/parse_tree_cl.c b/src/parser/parse_tree_cl.c index f023f7cc118..b7db560a727 100644 --- a/src/parser/parse_tree_cl.c +++ b/src/parser/parse_tree_cl.c @@ -7336,8 +7336,8 @@ pt_print_create_entity (PARSER_CONTEXT * parser, PT_NODE * p) static PT_NODE * pt_init_create_histogram (PT_NODE * p) { - p->info.histogram.histogram_type = 0; p->info.histogram.bucket_count = 256; + p->info.histogram.with_fullscan = 0; return p; } @@ -7350,7 +7350,7 @@ pt_init_create_histogram (PT_NODE * p) static PT_NODE * pt_init_drop_histogram (PT_NODE * p) { - p->info.histogram.histogram_type = 0; + p->info.histogram.with_fullscan = 0; p->info.histogram.bucket_count = 0; return p; } diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index ef6a1f8cc8b..3f8e1e2d420 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3879,7 +3879,7 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, PT_HISTOGRAM_INFO * const histogram_info, DO_HISTOGRAM do_histogram) { int error = NO_ERROR; - int histogram_type, bucket_count, nnames = 0; + int bucket_count, nnames = 0; char *attname = NULL; PT_NODE *cur_column = NULL; int is_partition = DB_NOT_PARTITIONED_CLASS; @@ -3898,7 +3898,6 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, /* fill infos for catlaog table TODO: data_type, duplication check */ nnames = pt_length_of_list (histogram_info->target_columns); - histogram_type = histogram_info->histogram_type; bucket_count = histogram_info->bucket_count; cur_column = histogram_info->target_columns; @@ -3920,7 +3919,7 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, } else { - error = sm_add_histogram (obj, attname, histogram_type, bucket_count); + error = sm_add_histogram (obj, attname, bucket_count, true); if (error != NO_ERROR) { return error; @@ -3942,7 +3941,7 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, } else { - error = sm_add_histogram (obj, attname, histogram_type, bucket_count); + error = sm_add_histogram (obj, attname, bucket_count, true); error = analyze_classes (NULL, db_get_class_name (obj), attname, 30, false, obj); if (error != NO_ERROR) { From 26d1a64d4c57de243cbea440813fca12852c54d8 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 28 Nov 2025 17:47:03 +0900 Subject: [PATCH 050/112] =?UTF-8?q?(feature)=20pt=5Fcreate=5Fhistogram=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=EB=AA=85=20update=EB=A1=9C=20=EC=A0=84?= =?UTF-8?q?=EC=9B=90=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/ddl_log.c | 2 +- src/compat/dbi_compat.h | 2 +- src/compat/dbtype_def.h | 2 +- src/executables/csql_result.c | 2 +- src/parser/csql_grammar.y | 142 +--------------------------------- src/parser/name_resolution.c | 17 +--- src/parser/parse_tree.h | 2 +- src/parser/parse_tree_cl.c | 40 +++++----- src/parser/parser_message.h | 2 +- src/parser/parser_support.c | 2 +- src/parser/semantic_check.c | 12 +-- src/query/execute_schema.c | 6 +- src/query/execute_statement.c | 16 ++-- src/query/execute_statement.h | 2 +- src/transaction/log_applier.c | 2 +- 15 files changed, 50 insertions(+), 201 deletions(-) diff --git a/src/base/ddl_log.c b/src/base/ddl_log.c index 76be812a808..0f7f928dd03 100644 --- a/src/base/ddl_log.c +++ b/src/base/ddl_log.c @@ -1433,7 +1433,7 @@ logddl_is_ddl_type (int node_type, PT_NODE * node) case PT_CREATE_ENTITY: case PT_CREATE_INDEX: case PT_CREATE_SERIAL: - case PT_CREATE_HISTOGRAM: + case PT_UPDATE_HISTOGRAM: case PT_DROP_HISTOGRAM: case PT_CREATE_STORED_PROCEDURE: case PT_CREATE_SYNONYM: diff --git a/src/compat/dbi_compat.h b/src/compat/dbi_compat.h index 8b8521d11a4..64c9eb67951 100644 --- a/src/compat/dbi_compat.h +++ b/src/compat/dbi_compat.h @@ -63,7 +63,7 @@ extern "C" #define SQLX_CMD_REGISTER_DATABASE CUBRID_STMT_REGISTER_DATABASE #define SQLX_CMD_CREATE_CLASS CUBRID_STMT_CREATE_CLASS #define SQLX_CMD_CREATE_INDEX CUBRID_STMT_CREATE_INDEX -#define SQLX_CMD_CREATE_HISTOGRAM CUBRID_STMT_CREATE_HISTOGRAM +#define SQLX_CMD_UPDATE_HISTOGRAM CUBRID_STMT_UPDATE_HISTOGRAM #define SQLX_CMD_DROP_HISTOGRAM CUBRID_STMT_DROP_HISTOGRAM #define SQLX_CMD_CREATE_TRIGGER CUBRID_STMT_CREATE_TRIGGER #define SQLX_CMD_CREATE_SERIAL CUBRID_STMT_CREATE_SERIAL diff --git a/src/compat/dbtype_def.h b/src/compat/dbtype_def.h index 6b586dfa777..b826e6a4ec9 100644 --- a/src/compat/dbtype_def.h +++ b/src/compat/dbtype_def.h @@ -119,7 +119,7 @@ extern "C" CUBRID_STMT_ALTER_USER, CUBRID_STMT_SET_SYS_PARAMS, CUBRID_STMT_ALTER_INDEX, - CUBRID_STMT_CREATE_HISTOGRAM, + CUBRID_STMT_UPDATE_HISTOGRAM, CUBRID_STMT_DROP_HISTOGRAM, CUBRID_STMT_CREATE_STORED_PROCEDURE, CUBRID_STMT_DROP_STORED_PROCEDURE, diff --git a/src/executables/csql_result.c b/src/executables/csql_result.c index db16312589d..cf5c01484a6 100644 --- a/src/executables/csql_result.c +++ b/src/executables/csql_result.c @@ -108,7 +108,7 @@ static CSQL_CMD_STRING_TABLE csql_Cmd_string_table[] = { {CUBRID_STMT_ROLLBACK_WORK, "ROLLBACK"}, {CUBRID_STMT_GRANT, "GRANT"}, {CUBRID_STMT_REVOKE, "REVOKE"}, - {CUBRID_STMT_CREATE_HISTOGRAM, "CREATE HISTOGRAM"}, + {CUBRID_STMT_UPDATE_HISTOGRAM, "CREATE HISTOGRAM"}, {CUBRID_STMT_DROP_HISTOGRAM, "DROP HISTOGRAM"}, {CUBRID_STMT_CREATE_USER, "CREATE USER"}, {CUBRID_STMT_DROP_USER, "DROP USER"}, diff --git a/src/parser/csql_grammar.y b/src/parser/csql_grammar.y index 912ab607d04..092ba19855c 100644 --- a/src/parser/csql_grammar.y +++ b/src/parser/csql_grammar.y @@ -3162,75 +3162,6 @@ create_stmt $$ = node; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - DBG_PRINT}} - | CREATE /* 1 */ - { /* 2 */ - DBG_TRACE_GRAMMAR(create_stmt, | CREATE); - PT_NODE* node = parser_new_node (this_parser, PT_CREATE_HISTOGRAM); - parser_push_hint_node (node); - push_msg (MSGCAT_SYNTAX_INVALID_CREATE_HISTOGRAM); - } - HISTOGRAM /* 3 */ - { pop_msg(); } /* 4 */ - ON_ /* 5 */ - only_class_name /* 6 */ - '(' histogram_column_list ')' /* 8 */ - opt_comment_spec /* 9 */ - {{ DBG_TRACE_GRAMMAR (create_stmt, | CREATE HISTOGRAM ON_ ~); - - PT_NODE *node = parser_pop_hint_node (); - PARSER_SAVE_ERR_CONTEXT (node, @$.buffer_pos) - PT_NODE *ocs = parser_new_node(this_parser, PT_SPEC); - - if (node && ocs) - { - PT_NODE *col; - int arg_count = 0, prefix_col_count = 0; - ocs->info.spec.entity_name = $6; - PARSER_SAVE_ERR_CONTEXT (ocs, @6.buffer_pos) - ocs->info.spec.meta_class = PT_CLASS; - node->info.histogram.target_table_spec = ocs; - col = $8; - - prefix_col_count = parser_count_prefix_columns (col, &arg_count); - node->info.histogram.target_columns = col; - } - - $$ = node; - PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - - DBG_PRINT}} - | CREATE /* 1 */ - { /* 2 */ - DBG_TRACE_GRAMMAR(create_stmt, | CREATE); - PT_NODE* node = parser_new_node (this_parser, PT_CREATE_HISTOGRAM); - parser_push_hint_node (node); - push_msg (MSGCAT_SYNTAX_INVALID_CREATE_HISTOGRAM); - } - HISTOGRAM /* 3 */ - { pop_msg(); } /* 4 */ - ON_ /* 5 */ - only_class_name /* 6 */ - opt_comment_spec /* 9 */ - {{ DBG_TRACE_GRAMMAR (create_stmt, | CREATE HISTOGRAM ON_ ~); - - PT_NODE *node = parser_pop_hint_node (); - PARSER_SAVE_ERR_CONTEXT (node, @$.buffer_pos) - PT_NODE *ocs = parser_new_node(this_parser, PT_SPEC); - - if (node && ocs) - { - int arg_count = 0, prefix_col_count = 0; - ocs->info.spec.entity_name = $6; - PARSER_SAVE_ERR_CONTEXT (ocs, @6.buffer_pos) - ocs->info.spec.meta_class = PT_CLASS; - node->info.histogram.target_table_spec = ocs; - node->info.histogram.target_columns = NULL; - } - - $$ = node; - PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - DBG_PRINT}} | CREATE /* 1 */ opt_or_replace /* 2 */ @@ -4882,75 +4813,6 @@ drop_stmt $$ = node; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - DBG_PRINT}} - | DROP /* 1 */ - { /* 2 */ - DBG_TRACE_GRAMMAR(create_stmt, | CREATE); - PT_NODE* node = parser_new_node (this_parser, PT_DROP_HISTOGRAM); - parser_push_hint_node (node); - push_msg (MSGCAT_SYNTAX_INVALID_DROP_HISTOGRAM); - } - HISTOGRAM /* 3 */ - { pop_msg(); } /* 4 */ - ON_ /* 5 */ - only_class_name /* 6 */ - '(' histogram_column_list ')' /* 8 */ - opt_comment_spec /* 9 */ - {{ DBG_TRACE_GRAMMAR (create_stmt, | DROP HISTOGRAM ON_ ~); - - PT_NODE *node = parser_pop_hint_node (); - PARSER_SAVE_ERR_CONTEXT (node, @$.buffer_pos) - PT_NODE *ocs = parser_new_node(this_parser, PT_SPEC); - - if (node && ocs) - { - PT_NODE *col, *temp; - int arg_count = 0, prefix_col_count = 0; - ocs->info.spec.entity_name = $6; - PARSER_SAVE_ERR_CONTEXT (ocs, @6.buffer_pos) - ocs->info.spec.meta_class = PT_CLASS; - node->info.histogram.target_table_spec = ocs; - col = $8; - - prefix_col_count = parser_count_prefix_columns (col, &arg_count); - node->info.histogram.target_columns = col; - } - - $$ = node; - PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - - DBG_PRINT}} - | DROP /* 1 */ - { /* 2 */ - DBG_TRACE_GRAMMAR(create_stmt, | CREATE); - PT_NODE* node = parser_new_node (this_parser, PT_DROP_HISTOGRAM); - parser_push_hint_node (node); - push_msg (MSGCAT_SYNTAX_INVALID_DROP_HISTOGRAM); - } - HISTOGRAM /* 3 */ - { pop_msg(); } /* 4 */ - ON_ /* 5 */ - only_class_name /* 6 */ - opt_comment_spec /* 9 */ - {{ DBG_TRACE_GRAMMAR (create_stmt, | DROP HISTOGRAM ON_ ~); - - PT_NODE *node = parser_pop_hint_node (); - PARSER_SAVE_ERR_CONTEXT (node, @$.buffer_pos) - PT_NODE *ocs = parser_new_node(this_parser, PT_SPEC); - - if (node && ocs) - { - int arg_count = 0, prefix_col_count = 0; - ocs->info.spec.entity_name = $6; - PARSER_SAVE_ERR_CONTEXT (ocs, @6.buffer_pos) - ocs->info.spec.meta_class = PT_CLASS; - node->info.histogram.target_table_spec = ocs; - node->info.histogram.target_columns = NULL; - } - - $$ = node; - PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - DBG_PRINT}} | DROP FUNCTION procedure_or_function_name_list {{ DBG_TRACE_GRAMMAR(drop_stmt, | DROP FUNCTION procedure_or_function_name_list); @@ -5192,7 +5054,7 @@ update_statistics_stmt update_histogram_stmt : ANALYZE TABLE only_class_name UPDATE HISTOGRAM ON_ histogram_column_list WITH unsigned_integer BUCKETS opt_with_fullscan {{ DBG_TRACE_GRAMMAR(update_histogram_stmt, | ANALYZE TABLE only_class_name UPDATE HISTOGRAM ON histogram_column_list WITH unsigned_integer BUCKETS opt_with_fullscan ); - PT_NODE *uhs = parser_new_node (this_parser, PT_CREATE_HISTOGRAM); + PT_NODE *uhs = parser_new_node (this_parser, PT_UPDATE_HISTOGRAM); PT_NODE *target_t = parser_new_node (this_parser, PT_SPEC); if (uhs && target_t) { @@ -5211,7 +5073,7 @@ update_histogram_stmt DBG_PRINT }} | ANALYZE TABLE only_class_name UPDATE HISTOGRAM WITH unsigned_integer BUCKETS opt_with_fullscan {{ DBG_TRACE_GRAMMAR(update_histogram_stmt, | ANALYZE TABLE only_class_name UPDATE HISTOGRAM WITH unsigned_integer BUCKETS opt_with_fullscan ); - PT_NODE *uhs = parser_new_node (this_parser, PT_CREATE_HISTOGRAM); + PT_NODE *uhs = parser_new_node (this_parser, PT_UPDATE_HISTOGRAM); PT_NODE *target_t = parser_new_node (this_parser, PT_SPEC); if (uhs && target_t) { diff --git a/src/parser/name_resolution.c b/src/parser/name_resolution.c index 0d49caf10df..733de1e3d62 100644 --- a/src/parser/name_resolution.c +++ b/src/parser/name_resolution.c @@ -3294,22 +3294,7 @@ pt_bind_names (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue *continue_walk = PT_LIST_WALK; break; - case PT_CREATE_HISTOGRAM: - scopestack.specs = node->info.histogram.target_table_spec; - bind_arg->scopes = &scopestack; - spec_frame.next = bind_arg->spec_frames; - spec_frame.extra_specs = NULL; - bind_arg->spec_frames = &spec_frame; - pt_bind_scope (parser, bind_arg); - - parser_walk_leaves (parser, node, pt_bind_names, bind_arg, pt_bind_names_post, bind_arg); - - bind_arg->spec_frames = bind_arg->spec_frames->next; - bind_arg->scopes = bind_arg->scopes->next; - - *continue_walk = PT_LIST_WALK; - break; - + case PT_UPDATE_HISTOGRAM: case PT_DROP_HISTOGRAM: scopestack.specs = node->info.histogram.target_table_spec; bind_arg->scopes = &scopestack; diff --git a/src/parser/parse_tree.h b/src/parser/parse_tree.h index 554c09b681b..011a9babd1d 100644 --- a/src/parser/parse_tree.h +++ b/src/parser/parse_tree.h @@ -986,7 +986,7 @@ enum pt_node_type PT_REVOKE = CUBRID_STMT_REVOKE, PT_UPDATE_STATS = CUBRID_STMT_UPDATE_STATS, PT_GET_STATS = CUBRID_STMT_GET_STATS, - PT_CREATE_HISTOGRAM = CUBRID_STMT_CREATE_HISTOGRAM, + PT_UPDATE_HISTOGRAM = CUBRID_STMT_UPDATE_HISTOGRAM, PT_DROP_HISTOGRAM = CUBRID_STMT_DROP_HISTOGRAM, PT_INSERT = CUBRID_STMT_INSERT, PT_SELECT = CUBRID_STMT_SELECT, diff --git a/src/parser/parse_tree_cl.c b/src/parser/parse_tree_cl.c index b7db560a727..c2080a64294 100644 --- a/src/parser/parse_tree_cl.c +++ b/src/parser/parse_tree_cl.c @@ -212,7 +212,7 @@ static PT_NODE *pt_apply_commit_work (PARSER_CONTEXT * parser, PT_NODE * p, void static PT_NODE *pt_apply_constraint (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); static PT_NODE *pt_apply_create_entity (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); static PT_NODE *pt_apply_create_index (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); -static PT_NODE *pt_apply_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); +static PT_NODE *pt_apply_update_histogram (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); static PT_NODE *pt_apply_create_user (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); static PT_NODE *pt_apply_data_default (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); static PT_NODE *pt_apply_datatype (PARSER_CONTEXT * parser, PT_NODE * p, void *arg); @@ -293,7 +293,7 @@ static PT_NODE *pt_init_auth_cmd (PT_NODE * p); static PT_NODE *pt_init_constraint (PT_NODE * node); static PT_NODE *pt_init_create_entity (PT_NODE * p); static PT_NODE *pt_init_create_index (PT_NODE * p); -static PT_NODE *pt_init_create_histogram (PT_NODE * p); +static PT_NODE *pt_init_update_histogram (PT_NODE * p); static PT_NODE *pt_init_drop_histogram (PT_NODE * p); static PT_NODE *pt_init_data_default (PT_NODE * p); static PT_NODE *pt_init_datatype (PT_NODE * p); @@ -343,7 +343,7 @@ static PARSER_VARCHAR *pt_print_constraint (PARSER_CONTEXT * parser, PT_NODE * p static PARSER_VARCHAR *pt_print_col_def_constraint (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_entity (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_index (PARSER_CONTEXT * parser, PT_NODE * p); -static PARSER_VARCHAR *pt_print_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p); +static PARSER_VARCHAR *pt_print_update_histogram (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_drop_histogram (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_serial (PARSER_CONTEXT * parser, PT_NODE * p); static PARSER_VARCHAR *pt_print_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * p); @@ -3075,8 +3075,8 @@ pt_show_node_type (PT_NODE * node) return "CREATE_ENTITY"; case PT_CREATE_INDEX: return "CREATE_INDEX"; - case PT_CREATE_HISTOGRAM: - return "CREATE_HISTOGRAM"; + case PT_UPDATE_HISTOGRAM: + return "update_histogram"; case PT_DROP_HISTOGRAM: return "DROP_HISTOGRAM"; case PT_CREATE_USER: @@ -5032,8 +5032,8 @@ pt_init_apply_f (void) pt_apply_func_array[PT_COMMIT_WORK] = pt_apply_commit_work; pt_apply_func_array[PT_CREATE_ENTITY] = pt_apply_create_entity; pt_apply_func_array[PT_CREATE_INDEX] = pt_apply_create_index; - pt_apply_func_array[PT_CREATE_HISTOGRAM] = pt_apply_create_histogram; //TODO - pt_apply_func_array[PT_DROP_HISTOGRAM] = pt_apply_create_histogram; + pt_apply_func_array[PT_UPDATE_HISTOGRAM] = pt_apply_update_histogram; + pt_apply_func_array[PT_DROP_HISTOGRAM] = pt_apply_update_histogram; pt_apply_func_array[PT_CREATE_USER] = pt_apply_create_user; pt_apply_func_array[PT_CREATE_TRIGGER] = pt_apply_create_trigger; pt_apply_func_array[PT_CREATE_SERIAL] = pt_apply_create_serial; @@ -5168,7 +5168,7 @@ pt_init_init_f (void) pt_init_func_array[PT_COMMIT_WORK] = pt_init_func_null_function; pt_init_func_array[PT_CREATE_ENTITY] = pt_init_create_entity; pt_init_func_array[PT_CREATE_INDEX] = pt_init_create_index; - pt_init_func_array[PT_CREATE_HISTOGRAM] = pt_init_create_histogram; + pt_init_func_array[PT_UPDATE_HISTOGRAM] = pt_init_update_histogram; pt_init_func_array[PT_DROP_HISTOGRAM] = pt_init_drop_histogram; pt_init_func_array[PT_CREATE_USER] = pt_init_func_null_function; pt_init_func_array[PT_CREATE_TRIGGER] = pt_init_func_null_function; @@ -5300,7 +5300,7 @@ pt_init_print_f (void) pt_print_func_array[PT_COMMIT_WORK] = pt_print_commit_work; pt_print_func_array[PT_CREATE_ENTITY] = pt_print_create_entity; pt_print_func_array[PT_CREATE_INDEX] = pt_print_create_index; - pt_print_func_array[PT_CREATE_HISTOGRAM] = pt_print_create_histogram; + pt_print_func_array[PT_UPDATE_HISTOGRAM] = pt_print_update_histogram; pt_print_func_array[PT_DROP_HISTOGRAM] = pt_print_drop_histogram; pt_print_func_array[PT_CREATE_USER] = pt_print_create_user; pt_print_func_array[PT_CREATE_TRIGGER] = pt_print_create_trigger; @@ -7327,21 +7327,21 @@ pt_print_create_entity (PARSER_CONTEXT * parser, PT_NODE * p) return q; } -/* CREATE_HISTOGRAM */ +/* update_histogram */ /* - * pt_init_create_histogram () - + * pt_init_update_histogram () - * return: * p(in): */ static PT_NODE * -pt_init_create_histogram (PT_NODE * p) +pt_init_update_histogram (PT_NODE * p) { p->info.histogram.bucket_count = 256; p->info.histogram.with_fullscan = 0; return p; } -/* CREATE_HISTOGRAM */ +/* update_histogram */ /* * pt_init_drop_histogram () - * return: @@ -7356,7 +7356,7 @@ pt_init_drop_histogram (PT_NODE * p) } /* - * pt_apply_create_histogram () - + * pt_apply_update_histogram () - * return: * parser(in): * p(in): @@ -7364,15 +7364,17 @@ pt_init_drop_histogram (PT_NODE * p) * arg(in): */ static PT_NODE * -pt_apply_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) +pt_apply_update_histogram (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) { PT_APPLY_WALK (parser, p->info.histogram.target_table_spec, arg); PT_APPLY_WALK (parser, p->info.histogram.target_columns, arg); + PT_APPLY_WALK (parser, p->info.histogram.bucket_count, arg); + PT_APPLY_WALK (parser, p->info.histogram.with_fullscan, arg); return p; } /* - * pt_apply_create_histogram () - + * pt_apply_update_histogram () - * return: * parser(in): * p(in): @@ -7380,7 +7382,7 @@ pt_apply_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) * arg(in): */ static PARSER_VARCHAR * -pt_print_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p) +pt_print_update_histogram (PARSER_CONTEXT * parser, PT_NODE * p) { PARSER_VARCHAR *b = 0, *tbl = 0, *cl = 0; unsigned int saved_cp = parser->custom_print; @@ -7390,7 +7392,7 @@ pt_print_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p) if (!(parser->custom_print & PT_SUPPRESS_INDEX)) { - b = pt_append_nulstring (parser, b, "create"); + b = pt_append_nulstring (parser, b, "update"); } b = pt_append_nulstring (parser, b, " histogram"); @@ -7423,7 +7425,7 @@ pt_print_create_histogram (PARSER_CONTEXT * parser, PT_NODE * p) } /* - * pt_apply_create_histogram () - + * pt_apply_update_histogram () - * return: * parser(in): * p(in): diff --git a/src/parser/parser_message.h b/src/parser/parser_message.h index 45329dcdd68..071e65ea870 100644 --- a/src/parser/parser_message.h +++ b/src/parser/parser_message.h @@ -174,7 +174,7 @@ #define MSGCAT_SYNTAX_MAX_SERVER_USER_LEN MSGCAT_SYNTAX_NO(137) #define MSGCAT_SYNTAX_INVALID_LEVEL MSGCAT_SYNTAX_NO(138) #define MSGCAT_SYNTAX_NO_PRECISION_IN_SP_FUNCTION MSGCAT_SYNTAX_NO(139) -#define MSGCAT_SYNTAX_INVALID_CREATE_HISTOGRAM MSGCAT_SYNTAX_NO(140) +#define MSGCAT_SYNTAX_INVALID_update_histogram MSGCAT_SYNTAX_NO(140) #define MSGCAT_SYNTAX_INVALID_DROP_HISTOGRAM MSGCAT_SYNTAX_NO(141) diff --git a/src/parser/parser_support.c b/src/parser/parser_support.c index f8e9f5099b5..78494d2e594 100644 --- a/src/parser/parser_support.c +++ b/src/parser/parser_support.c @@ -1515,7 +1515,7 @@ pt_is_ddl_statement (const PT_NODE * node) case PT_REMOVE_TRIGGER: case PT_RENAME_TRIGGER: case PT_UPDATE_STATS: - case PT_CREATE_HISTOGRAM: + case PT_UPDATE_HISTOGRAM: case PT_DROP_HISTOGRAM: /* TODO: check it */ case PT_CREATE_SERVER: diff --git a/src/parser/semantic_check.c b/src/parser/semantic_check.c index 61d25c3fde2..691f8cdf791 100644 --- a/src/parser/semantic_check.c +++ b/src/parser/semantic_check.c @@ -9076,7 +9076,7 @@ pt_check_create_index (PARSER_CONTEXT * parser, PT_NODE * node) } static void -pt_check_create_histogram (PARSER_CONTEXT * parser, PT_NODE * node) +pt_check_update_histogram (PARSER_CONTEXT * parser, PT_NODE * node) { PT_NODE *name; DB_OBJECT *db_obj; @@ -12364,7 +12364,7 @@ pt_check_with_info (PARSER_CONTEXT * parser, PT_NODE * node, SEMANTIC_CHK_INFO * } break; - case PT_CREATE_HISTOGRAM: + case PT_UPDATE_HISTOGRAM: if (parser->host_var_count) { PT_ERRORm (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_HOSTVAR_IN_DDL); @@ -12373,9 +12373,9 @@ pt_check_with_info (PARSER_CONTEXT * parser, PT_NODE * node, SEMANTIC_CHK_INFO * { sc_info_ptr->system_class = false; node = pt_resolve_names (parser, node, sc_info_ptr); - if (!pt_has_error (parser) && node->node_type == PT_CREATE_HISTOGRAM) + if (!pt_has_error (parser) && node->node_type == PT_UPDATE_HISTOGRAM) { - pt_check_create_histogram (parser, node); + pt_check_update_histogram (parser, node); } if (!pt_has_error (parser)) @@ -12398,9 +12398,9 @@ pt_check_with_info (PARSER_CONTEXT * parser, PT_NODE * node, SEMANTIC_CHK_INFO * { sc_info_ptr->system_class = false; node = pt_resolve_names (parser, node, sc_info_ptr); - if (!pt_has_error (parser) && node->node_type == PT_CREATE_HISTOGRAM) + if (!pt_has_error (parser) && node->node_type == PT_UPDATE_HISTOGRAM) { - pt_check_create_histogram (parser, node); + pt_check_update_histogram (parser, node); } if (!pt_has_error (parser)) diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 3f8e1e2d420..a07ec11caf2 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3961,13 +3961,13 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, /** - * do_create_histogram() - Creates a histogram on a class. + * do_update_histogram() - Creates a histogram on a class. * return: Error code if it fails * parser(in): Parser context * statement(in): Parse tree of a create histogram statement */ int -do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) +do_update_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) { PT_NODE *cls; DB_OBJECT *obj; @@ -4002,7 +4002,7 @@ do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) /** - * do_create_histogram() - Creates a histogram on a class. + * do_update_histogram() - Creates a histogram on a class. * return: Error code if it fails * parser(in): Parser context * statement(in): Parse tree of a create histogram statement diff --git a/src/query/execute_statement.c b/src/query/execute_statement.c index 886ff12f70c..d18cd9b7dca 100644 --- a/src/query/execute_statement.c +++ b/src/query/execute_statement.c @@ -3159,7 +3159,7 @@ do_statement (PARSER_CONTEXT * parser, PT_NODE * statement) case PT_CREATE_SERIAL: case PT_CREATE_TRIGGER: case PT_CREATE_USER: - case PT_CREATE_HISTOGRAM: + case PT_UPDATE_HISTOGRAM: case PT_DROP_HISTOGRAM: case PT_ALTER: case PT_ALTER_INDEX: @@ -3238,8 +3238,8 @@ do_statement (PARSER_CONTEXT * parser, PT_NODE * statement) error = do_create_index (parser, statement); break; - case PT_CREATE_HISTOGRAM: - error = do_create_histogram (parser, statement); + case PT_UPDATE_HISTOGRAM: + error = do_update_histogram (parser, statement); break; case PT_DROP_HISTOGRAM: @@ -3865,7 +3865,7 @@ do_execute_statement (PARSER_CONTEXT * parser, PT_NODE * statement) case PT_CREATE_SERIAL: case PT_CREATE_TRIGGER: case PT_CREATE_USER: - case PT_CREATE_HISTOGRAM: + case PT_UPDATE_HISTOGRAM: case PT_DROP_HISTOGRAM: case PT_ALTER: case PT_ALTER_INDEX: @@ -3940,8 +3940,8 @@ do_execute_statement (PARSER_CONTEXT * parser, PT_NODE * statement) case PT_CREATE_USER: err = do_create_user (parser, statement); break; - case PT_CREATE_HISTOGRAM: - err = do_create_histogram (parser, statement); + case PT_UPDATE_HISTOGRAM: + err = do_update_histogram (parser, statement); break; case PT_DROP_HISTOGRAM: err = do_drop_histogram (parser, statement); @@ -16173,8 +16173,8 @@ do_replicate_statement (PARSER_CONTEXT * parser, PT_NODE * statement) repl_stmt.statement_type = CUBRID_STMT_DROP_INDEX; break; - case PT_CREATE_HISTOGRAM: - repl_stmt.statement_type = CUBRID_STMT_CREATE_HISTOGRAM; + case PT_UPDATE_HISTOGRAM: + repl_stmt.statement_type = CUBRID_STMT_UPDATE_HISTOGRAM; break; case PT_DROP_HISTOGRAM: diff --git a/src/query/execute_statement.h b/src/query/execute_statement.h index de7e032f687..45d472c6d6d 100644 --- a/src/query/execute_statement.h +++ b/src/query/execute_statement.h @@ -119,7 +119,7 @@ extern int do_delete (PARSER_CONTEXT * parser, PT_NODE * statement); extern int do_prepare_delete (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * parent); extern int do_execute_delete (PARSER_CONTEXT * parser, PT_NODE * statement); -extern int do_create_histogram (PARSER_CONTEXT * parser, PT_NODE * statement); +extern int do_update_histogram (PARSER_CONTEXT * parser, PT_NODE * statement); extern int do_drop_histogram (PARSER_CONTEXT * parser, PT_NODE * statement); extern int do_drop (PARSER_CONTEXT * parser, PT_NODE * statement); diff --git a/src/transaction/log_applier.c b/src/transaction/log_applier.c index 01c26f3cc5f..d8748bc20a7 100644 --- a/src/transaction/log_applier.c +++ b/src/transaction/log_applier.c @@ -5526,7 +5526,7 @@ la_apply_statement_log (LA_ITEM * item) case CUBRID_STMT_ALTER_SERIAL: case CUBRID_STMT_DROP_SERIAL: - case CUBRID_STMT_CREATE_HISTOGRAM: + case CUBRID_STMT_UPDATE_HISTOGRAM: case CUBRID_STMT_DROP_HISTOGRAM: case CUBRID_STMT_DROP_DATABASE: From c127b22e0183979346502606349e6210fd16c088 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 2 Dec 2025 19:09:43 +0900 Subject: [PATCH 051/112] =?UTF-8?q?(feature)=20query=5Fdump=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20=EA=B8=B0=ED=83=80=20=EA=B5=AC=ED=97=8C?= =?UTF-8?q?=20-=20semantic=5Fcheck=EC=8B=9C=20invalid=20type=EC=9D=84=20?= =?UTF-8?q?=ED=8F=AC=ED=95=A8=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95=20-=20query=5Fdump=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20=EC=9D=BC=EB=B6=80=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=EC=97=90=20=EB=8C=80=ED=95=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80=20(=ED=95=B4=EB=8B=B9=EB=90=98?= =?UTF-8?q?=EB=8A=94=20=EC=BB=AC=EB=9F=BC=EC=97=90=20=EB=8C=80=ED=95=B4=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=20=EC=9E=88=EC=96=B4=EB=8F=84=20=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 130 ++++++++++++++++++++++++++++++++- src/histogram/histogram_cl.hpp | 8 +- src/object/schema_manager.c | 1 + src/parser/parse_tree_cl.c | 4 - src/parser/semantic_check.c | 5 +- src/query/execute_schema.c | 87 +++++++++++++++++++--- 6 files changed, 213 insertions(+), 22 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index e76ce878966..038c08a1894 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -45,7 +45,7 @@ */ int analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, - int with_fullscan, MOP classop) + bool with_fullscan, MOP classop) { int error = NO_ERROR; char *histogram_blob = NULL; @@ -69,18 +69,17 @@ analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_ int get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, - int with_fullscan, char **histogram_blob, int *histogram_total_length) + bool with_fullscan, char **histogram_blob, int *histogram_total_length) { int error = NO_ERROR; DB_QUERY_RESULT *query_result; DB_QUERY_ERROR query_error; hist::HistogramBuilder histogram_builder; DB_TYPE type = DB_TYPE_UNKNOWN; - bool sampling_scan = true; int number_of_mcv = 3; // TODO char query_buf[1024+222+254]; // TODO GET MAX TABLE NAME LENGTH FROM SQL.H - if (sampling_scan) + if (with_fullscan) { snprintf (query_buf, sizeof (query_buf), HISTOGRAM_WITH_SAMPLING_SCAN_QUERY_TEMPLATE, attr_name, tbl_name, attr_name, number_of_mcv, max_number_of_buckets, max_number_of_buckets); @@ -494,5 +493,128 @@ db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj) db_value_clear (value_ptrs[0]); db_value_clear (value_ptrs[1]); + return NO_ERROR; +} + +bool +is_histogrammable_type (DB_TYPE type) +{ + switch (type) + { + /* numeric */ + case DB_TYPE_INTEGER: + case DB_TYPE_SHORT: + case DB_TYPE_FLOAT: + case DB_TYPE_DOUBLE: + case DB_TYPE_NUMERIC: + case DB_TYPE_MONETARY: + return true; + + /* bit string */ + case DB_TYPE_BIT: + case DB_TYPE_VARBIT: + return true; + + /* character string */ + case DB_TYPE_CHAR: + case DB_TYPE_STRING: + return true; + + /* date / time */ + case DB_TYPE_TIME: + case DB_TYPE_DATE: + case DB_TYPE_TIMESTAMP: + case DB_TYPE_TIMESTAMPLTZ: + case DB_TYPE_TIMESTAMPTZ: + case DB_TYPE_DATETIMELTZ: + case DB_TYPE_DATETIMETZ: + return true; + + default: + return false; + } +} + +/*===========================================================================*/ +/* dump_histogram */ + +/* ++------------------ HISTOGRAM ------------------+ +| column : age (int) | +| rows : 100000 sample : 10000 (10.0%) | +| pages : 120 / 500 | +| buckets: 16 nulls : 123 | ++------------------------------------------------+ +#00 [-inf, 10] rows= 1234(0.012) ndv=10 cum=0.012 + +*/ + +/*===========================================================================*/ +#define HIST_DUMP_WIDTH 47 /* inner width of the histogram */ + +int +dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with_fullscan, int error, FILE *f) +{ + char line[HIST_DUMP_WIDTH + 1]; + SM_CLASS *class_ = NULL; + const char *col_name = attr_name; + const char *type_name = db_get_type_name (attr_type); + int rows_scanned = 0; + int bucket_count = 0; + double null_frequency = 0.0; + if (error != NO_ERROR) + { + snprintf (line, sizeof (line), "ERROR: Failed to dump histogram column: %s", attr_name); + fprintf (f, "| %-47s|\n", line); + fprintf (f, "+------------------------------------------------+\n"); + return NO_ERROR; + } + + class_ = sm_get_class_with_statistics (classop); + if (class_ == NULL) + { + return ER_FAILED; + } + + /* top border */ + fputs ("+------------------ HISTOGRAM ------------------+\n", f); + + /* column line */ + snprintf (line, sizeof (line), " column : %s (%s)", col_name, type_name); + fprintf (f, "| %-47s|\n", line); + + /* rows + sample line */ + if (with_fullscan) + { + snprintf (line, sizeof (line), + " rows : %d sample : %d (%.1f%%)", + class_->stats->heap_num_objects, rows_scanned, (double) rows_scanned / class_->stats->heap_num_objects * 100.0); + } + else + { + snprintf (line, sizeof (line), + " rows : %d ", + class_->stats->heap_num_objects); + } + fprintf (f, "| %-47s|\n", line); + + /* pages line */ + snprintf (line, sizeof (line), + " pages : %d / %d", + std::min (class_->stats->heap_num_pages, class_->stats->heap_num_objects), class_->stats->heap_num_pages); + fprintf (f, "| %-47s|\n", line); + + /* buckets + nulls line */ + snprintf (line, sizeof (line), + " buckets: %d nulls : %.0f", + bucket_count, null_frequency); + fprintf (f, "| %-47s|\n", line); + + /* bottom border */ + fputs ("+------------------------------------------------+\n", f); + + /* bucket line */ + //TODO: add bucket line + //fprintf (f, "#%02d [...] ...\n", ...); return NO_ERROR; } \ No newline at end of file diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index 7a1ebab421c..8dab2bb1370 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -23,6 +23,7 @@ #ifndef _HISTOGRAM_CL_HPP_ #define _HISTOGRAM_CL_HPP_ +#include #include "thread_compat.hpp" // Forward declaration for PT_NODE @@ -55,12 +56,13 @@ static const char *HISTOGRAM_WITH_SAMPLING_SCAN_QUERY_TEMPLATE = "COUNT(*) AS approx_ndv, MAX(is_mcv) AS is_mcv FROM all_buckets GROUP BY bid ORDER BY MAX(val);"; int analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, - int with_fullscan, MOP classop); + bool with_fullscan, MOP classop); int get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, - int with_fullscan, char **histogram_blob, int *histogram_total_length); + bool with_fullscan, char **histogram_blob, int *histogram_total_length); int set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, char *histogram_blob, int histogram_total_length, MOP classop); void histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); int db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj); - +bool is_histogrammable_type (DB_TYPE type); +int dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with_fullscan, int error, FILE *f); #endif // _HISTOGRAM_CL_HPP_ \ No newline at end of file diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 33e030686cc..35602aad62b 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -15535,6 +15535,7 @@ sm_add_histogram (MOP classop, const char *attr_name, int bucket_count, bool wit bool set_savepoint = false; int error = NO_ERROR; SM_CLASS *class_ = NULL; + DB_OBJECT *obj = NULL; if (attr_name == NULL) { diff --git a/src/parser/parse_tree_cl.c b/src/parser/parse_tree_cl.c index c2080a64294..3e747a9f2e7 100644 --- a/src/parser/parse_tree_cl.c +++ b/src/parser/parse_tree_cl.c @@ -7336,8 +7336,6 @@ pt_print_create_entity (PARSER_CONTEXT * parser, PT_NODE * p) static PT_NODE * pt_init_update_histogram (PT_NODE * p) { - p->info.histogram.bucket_count = 256; - p->info.histogram.with_fullscan = 0; return p; } @@ -7368,8 +7366,6 @@ pt_apply_update_histogram (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) { PT_APPLY_WALK (parser, p->info.histogram.target_table_spec, arg); PT_APPLY_WALK (parser, p->info.histogram.target_columns, arg); - PT_APPLY_WALK (parser, p->info.histogram.bucket_count, arg); - PT_APPLY_WALK (parser, p->info.histogram.with_fullscan, arg); return p; } diff --git a/src/parser/semantic_check.c b/src/parser/semantic_check.c index 691f8cdf791..84dc067a582 100644 --- a/src/parser/semantic_check.c +++ b/src/parser/semantic_check.c @@ -9119,7 +9119,8 @@ pt_check_update_histogram (PARSER_CONTEXT * parser, PT_NODE * node) PT_ERRORm (parser, name, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_NO_INDEX_ON_VCLASS); return; } - /* check if this is a partition class (TODO: to be implemented) */ + + /* check if this is a partition class (TODO: not implemented) */ if (sm_partitioned_class_type (db_obj, &is_partition, NULL, NULL) != NO_ERROR) { PT_ERROR (parser, node, er_msg ()); @@ -9134,7 +9135,7 @@ pt_check_update_histogram (PARSER_CONTEXT * parser, PT_NODE * node) name->info.name.db_object = db_obj; - + /* auth check */ pt_check_user_owns_class (parser, name); if (pt_has_error (parser)) { diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index a07ec11caf2..45bf9fa4114 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3868,21 +3868,23 @@ do_alter_index (PARSER_CONTEXT * parser, const PT_NODE * statement) /* - * create_or_drop_histogram_helper() - Creates or drops a histogram on a class. + * update_or_drop_histogram_helper() - Creates or drops a histogram on a class. * return: Error code * parser(in): Parser context * obj(in): Class object * histogram_info(in): Histogram information */ static int -create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, +update_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, PT_HISTOGRAM_INFO * const histogram_info, DO_HISTOGRAM do_histogram) { int error = NO_ERROR; int bucket_count, nnames = 0; + bool with_fullscan = false; char *attname = NULL; PT_NODE *cur_column = NULL; int is_partition = DB_NOT_PARTITIONED_CLASS; + DB_TYPE attr_type = DB_TYPE_NULL; /* check histogram is allowed on this class */ error = sm_partitioned_class_type (obj, &is_partition, NULL, NULL); @@ -3896,10 +3898,18 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, return ER_NOT_ALLOWED_ACCESS_TO_PARTITION; } - /* fill infos for catlaog table TODO: data_type, duplication check */ + /* fill infos for catlaog table */ nnames = pt_length_of_list (histogram_info->target_columns); bucket_count = histogram_info->bucket_count; cur_column = histogram_info->target_columns; + with_fullscan = histogram_info->with_fullscan ? true : false; + + /* update statistics for class first */ + error = sm_update_statistics (obj, with_fullscan); + if (error != NO_ERROR) + { + return error; + } if (nnames == 0) { @@ -3919,9 +3929,37 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, } else { - error = sm_add_histogram (obj, attname, bucket_count, true); + /* type check for the attribute */ + attr_type = TP_DOMAIN_TYPE (att->domain); + if (!is_histogrammable_type (attr_type)) + { + error = ER_OBJ_INVALID_ARGUMENTS; + dump_histogram (obj, attname, attr_type, with_fullscan, error, stdout); + continue; + } + + /* create histogram catalog entry */ + error = sm_add_histogram (obj, attname, bucket_count, with_fullscan); + if (error != NO_ERROR) + { + if (error != ER_LC_CLASSNAME_EXIST) + { + dump_histogram (obj, attname, attr_type, with_fullscan, error, stdout); + return error; + } + } + /* update the histogram */ + error = analyze_classes (NULL, db_get_class_name (obj), attname, bucket_count, with_fullscan, obj); + if (error != NO_ERROR) + { + dump_histogram (obj, attname, attr_type, with_fullscan, error, stdout); + return error; + } + /* TODO: dump the histogram */ + error = dump_histogram (obj, attname, attr_type, with_fullscan, error, stdout); if (error != NO_ERROR) { + assert (false); return error; } } @@ -3941,12 +3979,43 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, } else { - error = sm_add_histogram (obj, attname, bucket_count, true); - error = analyze_classes (NULL, db_get_class_name (obj), attname, 30, false, obj); + /* type check for the attribute */ + DB_ATTRIBUTE *attribute; + DB_DOMAIN *attr_domain; + + attribute = db_get_attribute (obj, attname); + attr_domain = db_attribute_domain (attribute); + attr_type = TP_DOMAIN_TYPE (attr_domain); + + if (!is_histogrammable_type (attr_type)) + { + error = ER_OBJ_INVALID_ARGUMENTS; + dump_histogram (obj, attname, attr_type, with_fullscan, error, stdout); + continue; + } + /* create histogram catalog entry */ + error = sm_add_histogram (obj, attname, bucket_count, with_fullscan); + if (error != NO_ERROR) + { + if (error != ER_LC_CLASSNAME_EXIST) + { + dump_histogram (obj, attname, attr_type, with_fullscan, error, stdout); + return error; + } + } + /* update the histogram */ + error = analyze_classes (NULL, db_get_class_name (obj), attname, bucket_count, with_fullscan, obj); if (error != NO_ERROR) { return error; } + /* TODO: dump the histogram */ + error = dump_histogram (obj, attname, attr_type, with_fullscan, error, stdout); + if (error != NO_ERROR) + { + assert (false); + return error; + } } cur_column = cur_column->next; } @@ -3961,7 +4030,7 @@ create_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, /** - * do_update_histogram() - Creates a histogram on a class. + * do_update_histogram() - Create or Update a histogram on a class. * return: Error code if it fails * parser(in): Parser context * statement(in): Parse tree of a create histogram statement @@ -3987,7 +4056,7 @@ do_update_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) return er_errid (); } - error = create_or_drop_histogram_helper (parser, obj, &statement->info.histogram, DO_HISTOGRAM_CREATE); + error = update_or_drop_histogram_helper (parser, obj, &statement->info.histogram, DO_HISTOGRAM_CREATE); if (error != NO_ERROR) { @@ -4028,7 +4097,7 @@ do_drop_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) return er_errid (); } - error = create_or_drop_histogram_helper (parser, obj, &statement->info.histogram, DO_HISTOGRAM_DROP); + error = update_or_drop_histogram_helper (parser, obj, &statement->info.histogram, DO_HISTOGRAM_DROP); if (error != NO_ERROR) { From ebb7cd23f13bb4b0b2a7873eea5fa2f1d0381185 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 3 Dec 2025 15:13:23 +0900 Subject: [PATCH 052/112] =?UTF-8?q?(feature)=20histo=5Fdump=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80/=20statistics=EC=97=90=20=ED=8F=AC=EC=95=84=EC=86=A1?= =?UTF-8?q?=20=EB=B6=84=ED=8F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 123 +++++++++++++++++++++++++---- src/histogram/histogram_reader.cpp | 86 ++++++++++++++++++++ src/histogram/histogram_reader.hpp | 3 + src/storage/heap_file.c | 20 ++++- 4 files changed, 214 insertions(+), 18 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 038c08a1894..ad18cfd36c3 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -79,7 +79,7 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na int number_of_mcv = 3; // TODO char query_buf[1024+222+254]; // TODO GET MAX TABLE NAME LENGTH FROM SQL.H - if (with_fullscan) + if (!with_fullscan) { snprintf (query_buf, sizeof (query_buf), HISTOGRAM_WITH_SAMPLING_SCAN_QUERY_TEMPLATE, attr_name, tbl_name, attr_name, number_of_mcv, max_number_of_buckets, max_number_of_buckets); @@ -561,6 +561,10 @@ dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with const char *type_name = db_get_type_name (attr_type); int rows_scanned = 0; int bucket_count = 0; + DB_VALUE histogram_value; + DB_OBJECT *histogram_obj = NULL; + int histogram_total_length = 0; + double null_frequency = 0.0; if (error != NO_ERROR) { @@ -576,15 +580,59 @@ dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with return ER_FAILED; } + error = db_get_histogram (classop, attr_name, &histogram_obj); + if (error != NO_ERROR) + { + return ER_FAILED; + } + + if (histogram_obj == NULL) + { + return ER_FAILED; + } + + /* get histgoram */ + error = db_get (histogram_obj, "histogram_values", &histogram_value); + if (error != NO_ERROR) + { + return ER_FAILED; + } + + const char *histogram_blob_ptr = db_get_bit (&histogram_value, &histogram_total_length); + if (histogram_blob_ptr == NULL || histogram_total_length <= 0) + { + return ER_FAILED; + } + + /* need length of histogram_blob_ptr */ + std::string_view histogram_blob (histogram_blob_ptr, static_cast (histogram_total_length / 8)); + + hist::HistogramReader histogram_reader; + error = histogram_reader.reset (histogram_blob); + if (error != NO_ERROR) + { + return ER_FAILED; + } + /* top border */ - fputs ("+------------------ HISTOGRAM ------------------+\n", f); + fputs ("+------------------ HISTOGRAM -------------------+\n", f); /* column line */ snprintf (line, sizeof (line), " column : %s (%s)", col_name, type_name); fprintf (f, "| %-47s|\n", line); /* rows + sample line */ - if (with_fullscan) + rows_scanned = static_cast (histogram_reader.total_rows()); + + if (class_->stats->heap_num_objects <= 0 || class_->stats->heap_num_pages <= 0) + { + snprintf (line, sizeof (line), "Empty histogram for column: %s", attr_name); + fprintf (f, "| %-47s|\n", line); + fprintf (f, "+------------------------------------------------+\n"); + return NO_ERROR; + } + + if (!with_fullscan) { snprintf (line, sizeof (line), " rows : %d sample : %d (%.1f%%)", @@ -593,28 +641,69 @@ dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with else { snprintf (line, sizeof (line), - " rows : %d ", - class_->stats->heap_num_objects); + " rows : %d ", static_cast (histogram_reader.total_rows())); } fprintf (f, "| %-47s|\n", line); - /* pages line */ + /* buckets + null frec line : TODO add null frequency */ snprintf (line, sizeof (line), - " pages : %d / %d", - std::min (class_->stats->heap_num_pages, class_->stats->heap_num_objects), class_->stats->heap_num_pages); - fprintf (f, "| %-47s|\n", line); - - /* buckets + nulls line */ - snprintf (line, sizeof (line), - " buckets: %d nulls : %.0f", - bucket_count, null_frequency); + " buckets + mcv: %d", + static_cast (histogram_reader.bucket_count())); fprintf (f, "| %-47s|\n", line); /* bottom border */ fputs ("+------------------------------------------------+\n", f); - /* bucket line */ - //TODO: add bucket line - //fprintf (f, "#%02d [...] ...\n", ...); + const double total_rows = static_cast (histogram_reader.total_rows ()); + const int bucket_cnt = static_cast (histogram_reader.bucket_count ()); + + for (int i = 0; i < bucket_cnt; i++) + { + const int rows = static_cast (histogram_reader.bucket_rows (i)); + const double sel = + (total_rows > 0.0 + ? static_cast (rows) / total_rows + : 0.0); + + const std::int32_t ndv = + static_cast (histogram_reader.bucket_approx_ndv (i)); + const bool is_mcv = (ndv == 1); + const double cum_sel = + (total_rows > 0.0 + ? static_cast (histogram_reader.bucket_cumulative (i)) / total_rows + : 0.0); + + const char *mcv_suffix = is_mcv ? " (MCV)" : ""; + + if (i == 0) + { + std::string hi = histogram_reader.bucket_hi_dump_with_type (i, attr_type); + std::fprintf (f, + "#%02d (-inf, %s] rows=%d(%.3f) ndv=%d%s cum=%.3f\n", + i, + hi.c_str (), + rows, + sel, + ndv, + mcv_suffix, + cum_sel); + } + else + { + std::string lo = histogram_reader.bucket_hi_dump_with_type (i - 1, attr_type); + std::string hi = histogram_reader.bucket_hi_dump_with_type (i, attr_type); + std::fprintf (f, + "#%02d (%s, %s] rows=%d(%.3f) ndv=%d%s cum=%.3f\n", + i, + lo.c_str (), + hi.c_str (), + rows, + sel, + ndv, + mcv_suffix, + cum_sel); + } + } + return NO_ERROR; } \ No newline at end of file diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index 98ec58a8f7d..061c6cc26a9 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -210,5 +210,91 @@ namespace hist return static_cast (get_value (bucket_hi_value_ptr (i))); } + // ---------- bucket_hi dump template specialization ---------- + template<> + std::string HistogramReader::bucket_hi_dump (std::uint32_t i) const + { + return std::to_string (get_value (bucket_hi_value_ptr (i))); + } + + template<> + std::string HistogramReader::bucket_hi_dump (std::uint32_t i) const + { + return std::to_string (static_cast (get_value (bucket_hi_value_ptr (i)))); + } + + template<> + std::string HistogramReader::bucket_hi_dump (std::uint32_t i) const + { + return std::to_string (get_value (bucket_hi_value_ptr (i))); + } + + template<> + std::string HistogramReader::bucket_hi_dump (std::uint32_t i) const + { + const char *p = bucket_hi_value_ptr (i); + std::uint32_t len32 = get_value (p); + std::uint32_t off32 = get_value (p + 4); + + if (len32 <= 4) // inline data + { + return std::string{ p+4, static_cast (len32-4) }; + } + assert (off32 + len32 <= str_size_); + return std::string{str_blob_.data() + off32, static_cast (std::min (len32, static_cast (8)))}; + } + + template<> + std::string HistogramReader::bucket_hi_dump (std::uint32_t i) const + { + const char *p = bucket_hi_value_ptr (i); + std::uint32_t len32 = get_value (p); + std::uint32_t off32 = get_value (p + 4); + + if (len32 <= 4) // inline data + { + return std::string{ p+4, static_cast (len32) }; + } + assert (off32 + len32 <= str_size_); + return std::string{str_blob_.data() + off32, static_cast (std::min (len32, static_cast (8)))}; + } + + template<> + std::string HistogramReader::bucket_hi_dump (std::uint32_t i) const + { + return std::to_string (static_cast (get_value (bucket_hi_value_ptr (i)))); + } + + std::string HistogramReader::bucket_hi_dump_with_type (std::uint32_t i, DB_TYPE attr_type) const + { + switch (attr_type) + { + case DB_TYPE_INTEGER: + case DB_TYPE_SHORT: + return bucket_hi_dump (i); + case DB_TYPE_FLOAT: + case DB_TYPE_DOUBLE: + case DB_TYPE_NUMERIC: + return bucket_hi_dump (i); + case DB_TYPE_BIT: + case DB_TYPE_VARBIT: + case DB_TYPE_CHAR: /* later consider for null trailing exists */ + case DB_TYPE_STRING: + return bucket_hi_dump (i); + case DB_TYPE_TIME: + return bucket_hi_dump (i); + case DB_TYPE_TIMESTAMP: + case DB_TYPE_TIMESTAMPLTZ: + case DB_TYPE_DATE: + case DB_TYPE_MONETARY: + case DB_TYPE_TIMESTAMPTZ: + case DB_TYPE_DATETIMETZ: + case DB_TYPE_DATETIMELTZ: + return bucket_hi_dump (i); + default: + assert (false); + return ""; + } + } // ---------- get_equal_selectivity ---------- } // namespace hist diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index a1cb343c1ca..b2a968d5449 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -90,6 +90,9 @@ namespace hist template T bucket_hi (std::uint32_t i) const; + template + std::string bucket_hi_dump (std::uint32_t i) const; + std::string bucket_hi_dump_with_type (std::uint32_t i, DB_TYPE attr_type) const; std::int64_t bucket_rows (std::uint32_t i) const; template int find_bucket (const T &value) const diff --git a/src/storage/heap_file.c b/src/storage/heap_file.c index db51575402d..18d1d06b356 100644 --- a/src/storage/heap_file.c +++ b/src/storage/heap_file.c @@ -39,6 +39,7 @@ #include "porting.h" #include "porting_inline.hpp" #include "record_descriptor.hpp" +#include #include "slotted_page.h" #include "overflow_file.h" #include "boot_sr.h" @@ -7889,6 +7890,22 @@ heap_get_record_data_when_all_ready (THREAD_ENTRY * thread_p, HEAP_GET_CONTEXT * return S_ERROR; } +static int +random_poisson_weight (int weight) +{ +// *INDENT-OFF* + static thread_local std::mt19937 rng { std::random_device{} () }; +// *INDENT-ON* + if (weight <= 0) + { + return 0; + } + + std::poisson_distribution < int >dist (weight); + return dist (rng); +} + + /* * heap_next_internal () - Retrieve of peek next object. * @@ -8114,8 +8131,9 @@ heap_next_internal (THREAD_ENTRY * thread_p, const HFID * hfid, OID * class_oid, if (sampling) { /* skip pages */ + int skip_count = random_poisson_weight (sampling->weight); if (heap_vpid_skip_next (thread_p, hfid, &scan_cache->page_watcher, &old_page_watcher, - sampling->weight, &vpid, scan_cache) == S_ERROR) + skip_count, &vpid, scan_cache) == S_ERROR) { return S_ERROR; } From 92569c032402576eaee0aa831f955beed713ec7f Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 11 Dec 2025 15:53:38 +0900 Subject: [PATCH 053/112] =?UTF-8?q?(feature)=20sm=5Fclass=20=ED=95=98?= =?UTF-8?q?=EC=9C=84=EC=97=90=20histogram=20=EC=A0=95=EB=B3=B4=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=20=ED=95=B4=EB=8B=B9=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20?= =?UTF-8?q?seg=EB=A5=BC=20add=ED=95=A0=EB=95=8C=20=ED=95=A8=EA=BB=98=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=ED=95=98=EB=8F=84=EB=A1=9D=20=ED=95=98?= =?UTF-8?q?=EA=B3=A0,=20term=EC=97=90=20=EB=8C=80=ED=95=9C=20seg=EB=A5=BC?= =?UTF-8?q?=20=EA=B2=80=EC=82=AC=ED=95=A0=EB=95=8C=20=ED=95=B4=EB=8B=B9=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=EB=A5=BC=20=EC=98=AE=EA=B2=A8=EC=A4=84=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TODO: Cache 사용 --- src/histogram/histogram_cl.cpp | 105 +++++++++++++++++++++++------ src/histogram/histogram_cl.hpp | 3 + src/histogram/histogram_reader.hpp | 2 +- src/object/class_object.c | 7 ++ src/object/class_object.h | 1 + src/object/schema_manager.c | 30 +++++++++ src/optimizer/query_graph.c | 11 ++- src/optimizer/query_graph.h | 3 +- src/parser/name_resolution.c | 2 +- src/parser/parse_tree.h | 1 + src/storage/statistics.h | 7 ++ 11 files changed, 148 insertions(+), 24 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index ad18cfd36c3..54bba0baa5c 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -34,6 +34,9 @@ #include #include #include "parser.h" +#include "class_object.h" +#include "object_accessor.h" +#include "authenticate.h" /* * analyze_all_classes @@ -298,38 +301,23 @@ set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na void histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) { - *selectivity = 0.0; int error = NO_ERROR; int bucket_index = 0; - /* get object from db histogram class */ - assert (lhs->node_type == PT_NAME); - const char *tbl_name = lhs->info.name.resolved; - const char *attr_name = lhs->info.name.original; - MOP classop = db_find_class (tbl_name); - DB_VALUE histogram_value; - - DB_OBJECT *histogram_obj = NULL; int histogram_total_length = 0; - error = db_get_histogram (classop, attr_name, &histogram_obj); - if (error != NO_ERROR) - { - return; - } - - if (histogram_obj == NULL) + /* get object from db histogram class */ + if (lhs->node_type != PT_NAME) { *selectivity = (double) 0.001; return; } - /* get histgoram */ - error = db_get (histogram_obj, "histogram_values", &histogram_value); - if (error != NO_ERROR) + DB_VALUE *histogram_value = lhs->info.name.histogram; + if (histogram_value == NULL) { *selectivity = (double) 0.001; return; } - const char *histogram_blob_ptr = db_get_bit (&histogram_value, &histogram_total_length); + const char *histogram_blob_ptr = db_get_bit (histogram_value, &histogram_total_length); if (histogram_blob_ptr == NULL || histogram_total_length <= 0) { *selectivity = (double) 0.001; @@ -496,6 +484,83 @@ db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj) return NO_ERROR; } +int +stats_get_histogram (MOP classop, HIST_STATS **histogram) +{ + int error = NO_ERROR; + DB_OBJECT *histogram_obj = NULL; + SM_ATTRIBUTE *att; + SM_CLASS *class_ = NULL; + error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT); + if (error != NO_ERROR) + { + return error; + } + + *histogram = (HIST_STATS *) db_ws_alloc (sizeof (HIST_STATS)); + if (*histogram == NULL) + { + return ER_OUT_OF_VIRTUAL_MEMORY; + } + (*histogram)->n_attrs = class_->att_count; + (*histogram)->histogram = (DB_VALUE **) db_ws_alloc (sizeof (DB_VALUE *) * class_->att_count); + if ((*histogram)->histogram == NULL) + { + return ER_OUT_OF_VIRTUAL_MEMORY; + } + + int i = 0; + for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) + { + const char *attname = (char *) att->header.name; + DB_VALUE *histogram_value = NULL; + error = db_get_histogram (classop, attname, &histogram_obj); + if (error != NO_ERROR) + { + return error; + } + + if (histogram_obj == NULL) + { + (*histogram)->histogram[i] = nullptr; + i++; + continue; + } + + histogram_value = (DB_VALUE *) db_ws_alloc (sizeof (DB_VALUE)); + error = db_get (histogram_obj, "histogram_values", histogram_value); + if (error != NO_ERROR) + { + return error; + } + + (*histogram)->histogram[i] = histogram_value; // should clear histogram_value + i++; + } + return NO_ERROR; +} + +int stats_free_histogram_and_init (HIST_STATS *histogram) +{ + if (histogram == NULL) + { + return NO_ERROR; + } + for (int i = 0; i < histogram->n_attrs; i++) + { + if (histogram->histogram[i] == nullptr) + { + continue; + } + db_value_clear (histogram->histogram[i]); + db_ws_free (histogram->histogram[i]); + histogram->histogram[i] = nullptr; + } + db_ws_free (histogram->histogram); + db_ws_free (histogram); + return NO_ERROR; +} + bool is_histogrammable_type (DB_TYPE type) { diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index 8dab2bb1370..648e1e9e2dd 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -29,6 +29,7 @@ // Forward declaration for PT_NODE struct parser_node; typedef struct parser_node PT_NODE; +typedef struct hist_stats HIST_STATS; static const char *HISTOGRAM_QUERY_TEMPLATE = "WITH src AS (SELECT %s AS val FROM %s WHERE %s IS NOT NULL), " @@ -64,5 +65,7 @@ int set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *att void histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); int db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj); bool is_histogrammable_type (DB_TYPE type); +int stats_get_histogram (MOP classop, HIST_STATS **histogram); +int stats_free_histogram_and_init (HIST_STATS *histogram); int dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with_fullscan, int error, FILE *f); #endif // _HISTOGRAM_CL_HPP_ \ No newline at end of file diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index b2a968d5449..a1598c9d78b 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -142,7 +142,7 @@ namespace hist } else { - assert (false); /* impossible */ + return lo - 1; } if (lo < 0 || lo >= static_cast (nb_)) diff --git a/src/object/class_object.c b/src/object/class_object.c index ef6febf56d0..b16d822088d 100644 --- a/src/object/class_object.c +++ b/src/object/class_object.c @@ -43,6 +43,7 @@ #include "parser.h" #include "trigger_manager.h" #include "schema_manager.h" +#include "histogram_cl.hpp" #include "dbi.h" #if defined(WINDOWS) #include "misc_string.h" @@ -6843,6 +6844,7 @@ classobj_make_class (const char *name) class_->new_ = NULL; class_->stats = NULL; + class_->histogram = NULL; class_->owner = NULL; class_->collation_id = LANG_SYS_COLLATION; class_->auth_cache = NULL; @@ -6917,6 +6919,11 @@ classobj_free_class (SM_CLASS * class_) stats_free_statistics_and_init (class_->stats); } + if (class_->histogram != NULL) + { + stats_free_histogram_and_init (class_->histogram); + } + if (class_->properties != NULL) { classobj_free_prop_and_init (class_->properties); diff --git a/src/object/class_object.h b/src/object/class_object.h index 9743f9d3098..229ff728fb0 100644 --- a/src/object/class_object.h +++ b/src/object/class_object.h @@ -760,6 +760,7 @@ struct sm_class SM_QUERY_SPEC *query_spec; /* virtual class query_spec information */ SM_TEMPLATE *new_; /* temporary structure */ CLASS_STATS *stats; /* server statistics, loaded on demand */ + HIST_STATS *histogram; /* column histogram, loaded on demand */ MOP owner; /* authorization object */ int collation_id; /* class collation */ diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 35602aad62b..449a087e574 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -73,6 +73,7 @@ #include "release_string.h" #include "execute_statement.h" #include "crypt_opfunc.h" +#include "histogram_cl.hpp" #include "db.h" #include "object_accessor.h" @@ -4128,6 +4129,7 @@ sm_get_class_with_statistics (MOP classop) return NULL; } + /* get the statistics of the class */ if (class_->stats == NULL) { /* it's first time to get the statistics of this class */ @@ -4165,6 +4167,27 @@ sm_get_class_with_statistics (MOP classop) } } + /* get the histogram of the class */ + if (class_->histogram == NULL) + { + /* we don't need to flush the class here */ + int err = stats_get_histogram (classop, &class_->histogram); + if (err != NO_ERROR) + { + return NULL; + } + } + else + { + /* to do : implement timestamp check and update */ + stats_free_histogram_and_init (class_->histogram); + int err = stats_get_histogram (classop, &class_->histogram); + if (err != NO_ERROR) + { + return NULL; + } + } + return class_; } @@ -12489,6 +12512,13 @@ install_new_representation (MOP classop, SM_CLASS * class_, SM_TEMPLATE * flat) class_->stats = NULL; } + /* TODO: HISTOGRAM */ + if (newrep && class_->histogram != NULL) + { + stats_free_histogram_and_init (class_->histogram); + class_->histogram = NULL; + } + /* formerly had classop->no_objects = 1 here, why ? */ /* now that we don't always load methods immediately after editing, must make sure that the methods_loaded flag is diff --git a/src/optimizer/query_graph.c b/src/optimizer/query_graph.c index 3ef92002b30..b1b880053cc 100644 --- a/src/optimizer/query_graph.c +++ b/src/optimizer/query_graph.c @@ -2903,6 +2903,7 @@ set_seg_node (PT_NODE * attr, QO_ENV * env, BITSET * bitset) QO_SEGMENT *seg; PT_NODE *entity; + assert (attr->node_type == PT_NAME); node = lookup_node (attr, env, &entity); /* node will be null if this attr resolves to an enclosing scope */ @@ -2913,6 +2914,7 @@ set_seg_node (PT_NODE * attr, QO_ENV * env, BITSET * bitset) * for shared variables, and it doesn't really hurt anyone just * to ignore failures here. */ + attr->info.name.histogram = seg->pt_node->info.name.histogram; bitset_add (bitset, QO_SEG_IDX (seg)); } @@ -5179,6 +5181,7 @@ qo_get_attr_info (QO_ENV * env, QO_SEGMENT * seg) int attr_id; QO_ATTR_CUM_STATS *cum_statsp; ATTR_STATS *attr_statsp; + DB_VALUE *attr_hist_statsp; BTREE_STATS *bt_statsp; int n_attrs; const char *name; @@ -5187,6 +5190,7 @@ qo_get_attr_info (QO_ENV * env, QO_SEGMENT * seg) int n_unavail_indexes; SM_CLASS_CONSTRAINT *consp; CLASS_STATS *stats; + HIST_STATS *hist_stats; bool is_reserved_name = false; if ((QO_SEG_PT_NODE (seg))->info.name.meta_class == PT_RESERVED) @@ -5255,6 +5259,7 @@ qo_get_attr_info (QO_ENV * env, QO_SEGMENT * seg) /* pointer to ATTR_STATS of CLASS_STATS of QO_CLASS_INFO_ENTRY */ stats = QO_GET_CLASS_STATS (class_info_entryp); + hist_stats = QO_GET_HIST_STATS (class_info_entryp); QO_ASSERT (env, stats != NULL); if (stats->attr_stats == NULL) { @@ -5276,8 +5281,9 @@ qo_get_attr_info (QO_ENV * env, QO_SEGMENT * seg) /* search the attribute from the class information */ attr_statsp = stats->attr_stats; + attr_hist_statsp = hist_stats->histogram[0]; n_attrs = stats->n_attrs; - for (j = 0; j < n_attrs; j++, attr_statsp++) + for (j = 0; j < n_attrs; j++, attr_statsp++, attr_hist_statsp++) { if (attr_statsp->id == attr_id) { @@ -5294,6 +5300,9 @@ qo_get_attr_info (QO_ENV * env, QO_SEGMENT * seg) /* set Number of Distinct Values */ attr_infop->ndv += attr_statsp->ndv; + /* set histogram */ + QO_SEG_PT_NODE (seg)->info.name.histogram = attr_hist_statsp; + if (cum_statsp->valid_limits == false) { /* first time */ diff --git a/src/optimizer/query_graph.h b/src/optimizer/query_graph.h index 0afb2614bfe..920fe65048b 100644 --- a/src/optimizer/query_graph.h +++ b/src/optimizer/query_graph.h @@ -200,7 +200,8 @@ struct qo_index */ #define QO_GET_CLASS_STATS(entryp) \ ((entryp)->self_allocated ? (entryp)->stats : (entryp)->smclass->stats) - +#define QO_GET_HIST_STATS(entryp) \ + ((entryp)->self_allocated ? NULL : ((entryp)->smclass->histogram)) /* * This structure is the head of a list of QO_INDEX_ENTRY index structures. * The purpose for this node is to have a place to store cumulative diff --git a/src/parser/name_resolution.c b/src/parser/name_resolution.c index 733de1e3d62..8c0a04684ca 100644 --- a/src/parser/name_resolution.c +++ b/src/parser/name_resolution.c @@ -6919,7 +6919,7 @@ pt_make_subclass_list (PARSER_CONTEXT * parser, DB_OBJECT * db, int line_num, in result->info.name.spec_id = id; result->info.name.meta_class = meta_class; result->info.name.partition = NULL; - + result->info.name.histogram = NULL; if ((au_fetch_class_force (db, &smclass, AU_FETCH_READ) == NO_ERROR)) { if (smclass->partition != NULL && smclass->partition->pname == NULL) diff --git a/src/parser/parse_tree.h b/src/parser/parse_tree.h index 011a9babd1d..ae55ef5eebb 100644 --- a/src/parser/parse_tree.h +++ b/src/parser/parse_tree.h @@ -2677,6 +2677,7 @@ struct pt_name_info int coll_modifier; /* collation modifier = collation + 1 */ PT_RESERVED_NAME_ID reserved_id; /* used to identify reserved name */ size_t json_table_column_index; /* will be used only for json_table to gather attributes in the correct order */ + DB_VALUE *histogram; /* histogram value */ }; /* diff --git a/src/storage/statistics.h b/src/storage/statistics.h index 67991e7ddc5..1bb1855952d 100644 --- a/src/storage/statistics.h +++ b/src/storage/statistics.h @@ -99,6 +99,13 @@ struct class_stats ATTR_STATS *attr_stats; /* pointer to the array of attribute statistics */ }; +typedef struct hist_stats HIST_STATS; +struct hist_stats +{ + int n_attrs; /* number of attributes; size of the histogram[] */ + DB_VALUE **histogram; /* column histogram , null if not exists */ +}; + /* Statistical Information about the attribute NDV */ typedef struct attr_ndv ATTR_NDV; struct attr_ndv From a93f35d36654a68eb8a3521433adca868d31bb33 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 11 Dec 2025 17:07:51 +0900 Subject: [PATCH 054/112] =?UTF-8?q?(refactor)=20histogram=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EB=8B=A8=EC=9C=84=ED=99=94=20=EB=B0=8F=20TODO=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 257 +++++++++++++++++++---------- src/histogram/histogram_cl.hpp | 31 ++++ src/histogram/histogram_reader.hpp | 56 ++++--- src/optimizer/query_planner.c | 98 +++++++++-- src/optimizer/query_planner.h | 10 ++ 5 files changed, 332 insertions(+), 120 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 54bba0baa5c..5a19915449a 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -37,6 +37,7 @@ #include "class_object.h" #include "object_accessor.h" #include "authenticate.h" +#include "query_planner.h" /* * analyze_all_classes @@ -298,159 +299,245 @@ set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na return error; } -void -histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) +static bool +histogram_init_reader_from_lhs (PT_NODE *lhs, hist::HistogramReader &reader) { - int error = NO_ERROR; - int bucket_index = 0; - int histogram_total_length = 0; - /* get object from db histogram class */ - if (lhs->node_type != PT_NAME) + if (lhs == NULL || lhs->node_type != PT_NAME) { - *selectivity = (double) 0.001; - return; + return false; } DB_VALUE *histogram_value = lhs->info.name.histogram; if (histogram_value == NULL) { - *selectivity = (double) 0.001; - return; + return false; } + + int histogram_total_length = 0; const char *histogram_blob_ptr = db_get_bit (histogram_value, &histogram_total_length); if (histogram_blob_ptr == NULL || histogram_total_length <= 0) { - *selectivity = (double) 0.001; - return; + return false; } - /* need length of histogram_blob_ptr */ - std::string_view histogram_blob (histogram_blob_ptr, static_cast (histogram_total_length / 8)); + std::string_view histogram_blob (histogram_blob_ptr, + static_cast (histogram_total_length / 8)); - hist::HistogramReader histogram_reader; - error = histogram_reader.reset (histogram_blob); + int error = reader.reset (histogram_blob); if (error != NO_ERROR) { - *selectivity = (double) 0.001; - return; + return false; } - switch (rhs->info.value.db_value.domain.general_info.type) + return true; +} + +static bool +histogram_extract_key (const DB_VALUE *db_val, histogram_key &key) +{ + const DB_TYPE type = static_cast (db_val->domain.general_info.type); + + switch (type) { case DB_TYPE_INTEGER: - { - std::int32_t val = db_get_int (&rhs->info.value.db_value); - bucket_index = histogram_reader.find_bucket (val); - break; - } + key.kind = histogram_key_kind::i32; + key.i32 = db_get_int (db_val); + return true; + case DB_TYPE_SHORT: - { - std::int32_t val = static_cast (db_get_short (&rhs->info.value.db_value)); - bucket_index = histogram_reader.find_bucket (val); - break; - } + key.kind = histogram_key_kind::i32; + key.i32 = static_cast (db_get_short (db_val)); + return true; + case DB_TYPE_FLOAT: - { - double val = db_get_float (&rhs->info.value.db_value); - bucket_index = histogram_reader.find_bucket (val); - break; - } + key.kind = histogram_key_kind::dbl; + key.dbl = static_cast (db_get_float (db_val)); + return true; + case DB_TYPE_DOUBLE: - { - double val = db_get_double (&rhs->info.value.db_value); - bucket_index = histogram_reader.find_bucket (val); - break; - } + key.kind = histogram_key_kind::dbl; + key.dbl = db_get_double (db_val); + return true; + case DB_TYPE_NUMERIC: - { - double val; - numeric_coerce_num_to_double (db_get_numeric (&rhs->info.value.db_value), db_value_scale (&rhs->info.value.db_value), - &val); - bucket_index = histogram_reader.find_bucket (val); - break; - } + key.kind = histogram_key_kind::dbl; + numeric_coerce_num_to_double (db_get_numeric (db_val), db_value_scale (db_val), &key.dbl); + return true; + case DB_TYPE_BIT: case DB_TYPE_VARBIT: { int length = 0; - const char *str = db_get_bit (&rhs->info.value.db_value, &length); + const char *str = db_get_bit (db_val, &length); if (str == NULL) { - *selectivity = (double) 0.001; - return; + return false; } - std::string str_val (str, length); - bucket_index = histogram_reader.find_bucket (str_val); - break; + key.kind = histogram_key_kind::str; + key.str.assign (str, length); + return true; } - case DB_TYPE_CHAR: /* later consider for null trailing exists */ + + case DB_TYPE_CHAR: /* later consider for null trailing exists */ case DB_TYPE_STRING: { - const char *str = db_get_string (&rhs->info.value.db_value); + const char *str = db_get_string (db_val); if (str == NULL) { - *selectivity = (double) 0.001; - return; + return false; } - std::string str_val (str); - bucket_index = histogram_reader.find_bucket (str_val); - break; + key.kind = histogram_key_kind::str; + key.str.assign (str); + return true; } + case DB_TYPE_TIME: { - - DB_TIME *time = db_get_time (&rhs->info.value.db_value); - bucket_index = histogram_reader.find_bucket (static_cast (*time)); - break; + DB_TIME *timep = db_get_time (db_val); + key.kind = histogram_key_kind::u64; + key.u64 = static_cast (*timep); + return true; } + case DB_TYPE_TIMESTAMP: case DB_TYPE_TIMESTAMPLTZ: { - - DB_TIMESTAMP *timestamp = db_get_timestamp (&rhs->info.value.db_value); - bucket_index = histogram_reader.find_bucket (static_cast (*timestamp)); - break; + DB_TIMESTAMP *tsp = db_get_timestamp (db_val); + key.kind = histogram_key_kind::u64; + key.u64 = static_cast (*tsp); + return true; } + case DB_TYPE_DATE: { - DB_DATE *date = db_get_date (&rhs->info.value.db_value); - bucket_index = histogram_reader.find_bucket (static_cast (*date)); - break; + DB_DATE *datep = db_get_date (db_val); + key.kind = histogram_key_kind::u64; + key.u64 = static_cast (*datep); + return true; } + case DB_TYPE_MONETARY: { - DB_MONETARY *monetary = db_get_monetary (&rhs->info.value.db_value); - bucket_index = histogram_reader.find_bucket (static_cast (monetary->amount)); - break; + DB_MONETARY *monetary = db_get_monetary (db_val); + key.kind = histogram_key_kind::u64; + key.u64 = static_cast (monetary->amount); + return true; } + case DB_TYPE_TIMESTAMPTZ: { - DB_TIMESTAMPTZ *timestamptz = db_get_timestamptz (&rhs->info.value.db_value); - bucket_index = histogram_reader.find_bucket (static_cast (timestamptz->timestamp)); - break; + DB_TIMESTAMPTZ *timestamptz = db_get_timestamptz (db_val); + key.kind = histogram_key_kind::u64; + key.u64 = static_cast (timestamptz->timestamp); + return true; } + case DB_TYPE_DATETIMETZ: case DB_TYPE_DATETIMELTZ: { - DB_DATETIMETZ *datetimetz = db_get_datetimetz (&rhs->info.value.db_value); - bucket_index = histogram_reader.find_bucket (static_cast - (datetimetz->datetime.date) << 32 | datetimetz->datetime.time); - break; + DB_DATETIMETZ *datetimetz = db_get_datetimetz (db_val); + key.kind = histogram_key_kind::u64; + key.u64 = (static_cast (datetimetz->datetime.date) << 32) + | static_cast (datetimetz->datetime.time); + return true; } + default: assert (false); /* impossible to reach here - blocked at parser layer first */ + return false; + } +} + +void +histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) +{ + + assert (selectivity != NULL); + + hist::HistogramReader histogram_reader; + if (!histogram_init_reader_from_lhs (lhs, histogram_reader)) + { + *selectivity = DEFAULT_EQUAL_SELECTIVITY; + return; + } + + histogram_key key; + if (!histogram_extract_key (&rhs->info.value.db_value, key)) + { + *selectivity = DEFAULT_EQUAL_SELECTIVITY; + return; + } + + int bucket_index = -1; + bool found = false; + + switch (key.kind) + { + case histogram_key_kind::i32: + found = histogram_reader.find_bucket_and_check (key.i32, bucket_index); + break; + + case histogram_key_kind::dbl: + found = histogram_reader.find_bucket_and_check (key.dbl, bucket_index); + break; + + case histogram_key_kind::str: + found = histogram_reader.find_bucket_and_check (key.str, bucket_index); + break; + + case histogram_key_kind::u64: + found = histogram_reader.find_bucket_and_check (key.u64, bucket_index); + break; + + case histogram_key_kind::invalid: + default: + assert (false); break; } - if (bucket_index == -1) /* not found */ + if (!found || bucket_index < 0) { + /* not found in histogram */ *selectivity = 0.0; return; } - *selectivity = (static_cast (histogram_reader.bucket_rows (bucket_index)) / static_cast - (histogram_reader.total_rows())) / - static_cast (histogram_reader.bucket_approx_ndv (bucket_index)); + const double bucket_rows = static_cast (histogram_reader.bucket_rows (bucket_index)); + const double total_rows = static_cast (histogram_reader.total_rows ()); + const double approx_ndv = static_cast (histogram_reader.bucket_approx_ndv (bucket_index)); + + if (total_rows <= 0.0 || approx_ndv <= 0.0) + { + /* safe default */ + *selectivity = DEFAULT_EQUAL_SELECTIVITY; + return; + } + + *selectivity = (bucket_rows / total_rows) / approx_ndv; + return; +} + +void +histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) +{ + return; +} + +void +histogram_get_between_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) +{ + return; +} + +void +histogram_get_range_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) +{ + return; +} + +void +histogram_get_all_some_in_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) +{ return; } diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index 648e1e9e2dd..d19d4c6c13a 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -24,6 +24,8 @@ #define _HISTOGRAM_CL_HPP_ #include +#include +#include #include "thread_compat.hpp" // Forward declaration for PT_NODE @@ -56,16 +58,45 @@ static const char *HISTOGRAM_WITH_SAMPLING_SCAN_QUERY_TEMPLATE = "SELECT bid, MAX(val) AS endpoint, SUM(c) AS rows_in_bucket, SUM(SUM(c)) OVER (ORDER BY MAX(val)) AS cumulative, " "COUNT(*) AS approx_ndv, MAX(is_mcv) AS is_mcv FROM all_buckets GROUP BY bid ORDER BY MAX(val);"; +/* histogram key kind */ +enum class histogram_key_kind +{ + invalid, + i32, + dbl, + str, + u64 +}; + +struct histogram_key +{ + histogram_key_kind kind = histogram_key_kind::invalid; + std::int32_t i32 = 0; + double dbl = 0.0; + std::string str; + std::uint64_t u64 = 0; +}; + +/* histogram analysis functions */ int analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, bool with_fullscan, MOP classop); int get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, bool with_fullscan, char **histogram_blob, int *histogram_total_length); int set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, char *histogram_blob, int histogram_total_length, MOP classop); + +/* histogram selectivity evaluation functions */ void histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); +void histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); +void histogram_get_between_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); +void histogram_get_range_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); +void histogram_get_all_some_in_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); + +/* histogram utility functions */ int db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj); bool is_histogrammable_type (DB_TYPE type); int stats_get_histogram (MOP classop, HIST_STATS **histogram); int stats_free_histogram_and_init (HIST_STATS *histogram); int dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with_fullscan, int error, FILE *f); + #endif // _HISTOGRAM_CL_HPP_ \ No newline at end of file diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index a1598c9d78b..84600e749f6 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -126,34 +126,44 @@ namespace hist } } - /* mcv check */ - while (lo >= 0 && lo < static_cast (nb_) && bucket_approx_ndv (lo) == 1) - { - T mcv_val = bucket_hi (lo); - - if (value == mcv_val) - { - return lo; - } - - if (value < mcv_val) - { - --lo; - } - else - { - return lo - 1; - } + return lo; - if (lo < 0 || lo >= static_cast (nb_)) - { - break; - } + } + template + bool check_value_included (std::uint32_t i, const T &value) const + { + /* not mcv */ + if (bucket_approx_ndv (i) != 1) + { + return true; + } + /* mcv */ + T mcv_val = bucket_hi (i); + if (value == mcv_val) + { + return true; + } + return false; + } + template + bool + find_bucket_and_check (const T &value, int &bucket_index) + { + bucket_index = this->find_bucket (value); + if (bucket_index == -1) + { + return false; } - return lo; + if (!this->check_value_included (bucket_index, value)) + { + bucket_index = -1; + return false; + } + return true; } + private: template T get_value (const void *ptr) const; diff --git a/src/optimizer/query_planner.c b/src/optimizer/query_planner.c index 1b777ab5f33..3bdb98bdc8a 100644 --- a/src/optimizer/query_planner.c +++ b/src/optimizer/query_planner.c @@ -409,16 +409,6 @@ QO_PLAN_VTBL *all_vtbls[] = { &qo_worst_plan_vtbl }; -#define DEFAULT_NULL_SELECTIVITY (double) 0.01 -#define DEFAULT_EXISTS_SELECTIVITY (double) 0.1 -#define DEFAULT_SELECTIVITY (double) 0.1 -#define DEFAULT_EQUAL_SELECTIVITY (double) 0.001 -#define DEFAULT_EQUIJOIN_SELECTIVITY (double) 0.001 -#define DEFAULT_COMP_SELECTIVITY (double) 0.1 -#define DEFAULT_BETWEEN_SELECTIVITY (double) 0.01 -#define DEFAULT_IN_SELECTIVITY (double) 0.01 -#define DEFAULT_RANGE_SELECTIVITY (double) 0.1 - /* Structural equivalence classes for expressions */ typedef enum PRED_CLASS @@ -9577,11 +9567,17 @@ qo_equal_selectivity (QO_ENV * env, PT_NODE * pt_expr) selectivity = DEFAULT_EQUIJOIN_SELECTIVITY; } + /* TODO: add histogram selectivity */ break; case PC_CONST: histogram_get_equal_selectivity (lhs, rhs, &selectivity); - break; + if (selectivity != DEFAULT_EQUAL_SELECTIVITY) + { + break; + } + [[fallthrough]]; + case PC_HOST_VAR: case PC_SUBQUERY: case PC_SET: @@ -9610,6 +9606,21 @@ qo_equal_selectivity (QO_ENV * env, PT_NODE * pt_expr) break; case PC_CONST: + switch (pc_rhs) + { + case PC_ATTR: + histogram_get_equal_selectivity (rhs, lhs, &selectivity); + break; + + default: + break; + } + if (selectivity != DEFAULT_EQUAL_SELECTIVITY) + { + break; + } + [[fallthrough]]; + case PC_HOST_VAR: case PC_SUBQUERY: case PC_SET: @@ -9800,7 +9811,70 @@ qo_equal_selectivity (QO_ENV * env, PT_NODE * pt_expr) static double qo_comp_selectivity (QO_ENV * env, PT_NODE * pt_expr) { - return DEFAULT_COMP_SELECTIVITY; + PT_NODE *lhs, *rhs, *multi_attr; + PRED_CLASS pc_lhs, pc_rhs; + int lhs_icard, rhs_icard, icard; + double selectivity; + + lhs = pt_expr->info.expr.arg1; + rhs = pt_expr->info.expr.arg2; + + /* the class of lhs and rhs */ + pc_lhs = qo_classify (lhs); + pc_rhs = qo_classify (rhs); + + selectivity = DEFAULT_COMP_SELECTIVITY; + + switch (pc_lhs) + { + case PC_ATTR: + + switch (pc_rhs) + { + case PC_ATTR: + /* TODO: add histogram selectivity */ + break; + + case PC_CONST: + histogram_get_comp_selectivity (lhs, rhs, &selectivity); + break; + + default: + break; + } + + break; + + case PC_CONST: + switch (pc_rhs) + { + case PC_ATTR: + histogram_get_comp_selectivity (rhs, lhs, &selectivity); + break; + + default: + break; + } + break; + + case PC_MULTI_ATTR: + switch (pc_rhs) + { + case PC_MULTI_ATTR: + /* (attr,attr) = (attr,attr) */ + /* TODO: add histogram selectivity */ + break; + + default: + break; + } + + break; + default: + break; + } + + return selectivity; } /* diff --git a/src/optimizer/query_planner.h b/src/optimizer/query_planner.h index 09369ab52bb..2ccc1b14e30 100644 --- a/src/optimizer/query_planner.h +++ b/src/optimizer/query_planner.h @@ -110,6 +110,16 @@ typedef enum QO_PLAN_SKIP_ORDERBY_CAN_USE = -2, } QO_PLAN_SKIP_ORDERBY_OPT; +#define DEFAULT_NULL_SELECTIVITY (double) 0.01 +#define DEFAULT_EXISTS_SELECTIVITY (double) 0.1 +#define DEFAULT_SELECTIVITY (double) 0.1 +#define DEFAULT_EQUAL_SELECTIVITY (double) 0.001 +#define DEFAULT_EQUIJOIN_SELECTIVITY (double) 0.001 +#define DEFAULT_COMP_SELECTIVITY (double) 0.1 +#define DEFAULT_BETWEEN_SELECTIVITY (double) 0.01 +#define DEFAULT_IN_SELECTIVITY (double) 0.01 +#define DEFAULT_RANGE_SELECTIVITY (double) 0.1 + struct qo_plan { QO_INFO *info; From bec9aa7c6128f0d74b4a45856934aa4f5f47c2d6 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 11 Dec 2025 17:43:49 +0900 Subject: [PATCH 055/112] =?UTF-8?q?(=EC=84=9C=EB=B8=8C=EB=AA=A8=EB=93=88?= =?UTF-8?q?=20=EC=9D=B4=EC=83=81=ED=95=B4=EC=A7=84=EA=B1=B0=20=EB=90=98?= =?UTF-8?q?=EB=8F=8C=EB=A6=AC=EA=B8=B0=20=EC=8B=9C=EB=8F=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cubridmanager | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cubridmanager b/cubridmanager index 7cbb7001ac3..15d1ad9e35f 160000 --- a/cubridmanager +++ b/cubridmanager @@ -1 +1 @@ -Subproject commit 7cbb7001ac3ab5c68c234b5d8d5214727e65833f +Subproject commit 15d1ad9e35f2eb610bf7d8b28a01db3af9b4bf6e From 9860f8e85e855f521587f294baf9ce7bf24989aa Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 11 Dec 2025 17:47:41 +0900 Subject: [PATCH 056/112] =?UTF-8?q?(=EC=84=9C=EB=B8=8C=EB=AA=A8=EB=93=88?= =?UTF-8?q?=20=ED=8F=AC=EC=9D=B8=ED=84=B0=20=EB=90=98=EB=8F=8C=EB=A6=AC?= =?UTF-8?q?=EA=B8=B0=202=EC=B0=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cubridmanager | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cubridmanager b/cubridmanager index 15d1ad9e35f..aee66659e11 160000 --- a/cubridmanager +++ b/cubridmanager @@ -1 +1 @@ -Subproject commit 15d1ad9e35f2eb610bf7d8b28a01db3af9b4bf6e +Subproject commit aee66659e11bec1b426ec11f872d36a9345425f8 From c3660c16ed38086f5a8fc0679e9b2611ed8a9ddb Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 11 Dec 2025 20:37:32 +0900 Subject: [PATCH 057/112] =?UTF-8?q?(feature)=20range=20selectivity=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 295 ++++++++++++++++++++++++++++- src/histogram/histogram_cl.hpp | 2 +- src/histogram/histogram_reader.cpp | 44 ++++- src/histogram/histogram_reader.hpp | 4 +- src/optimizer/query_planner.c | 88 +++++++-- src/optimizer/query_planner.h | 13 ++ 6 files changed, 411 insertions(+), 35 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 5a19915449a..1b4a4939063 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -448,10 +448,103 @@ histogram_extract_key (const DB_VALUE *db_val, histogram_key &key) } } +static double +numeric_domain_frac_i32_lt (std::int32_t lo, std::int32_t hi, std::int32_t v) +{ + if (v <= lo) + { + return 0.0; + } + if (v >= hi) + { + return 1.0; + } + return (v - lo) / (hi - lo); +} + +double numeric_domain_frac_u64_lt (std::uint64_t lo, std::uint64_t hi, std::uint64_t v) +{ + if (v >= hi) + { + return 1.0; + } + const long double dlo = static_cast (lo); + const long double dhi = static_cast (hi); + const long double dv = static_cast (v); + const long double den = dhi - dlo; + + long double t = (dv - dlo) / den; + return static_cast (t); +} + +double numeric_domain_frac_dbl_lt (double lo, double hi, double v) +{ + if (v >= hi) + { + return 1.0; + } + const long double dlo = static_cast (lo); + const long double dhi = static_cast (hi); + const long double dv = static_cast (v); + const long double den = dhi - dlo; + + long double t = (dv - dlo) / den; + return static_cast (t); +} + +static double +clamp01 (double x) +{ + if (x < 0.0) + { + return 0.0; + } + if (x > 1.0) + { + return 1.0; + } + return x; +} + +static double +string_pos (const unsigned char *s, std::size_t len, std::size_t max_len = 16) +{ + const long double base = 257.0L; + + long double acc = 0.0L; + long double factor = 1.0L; + + const std::size_t use_len = (len < max_len) ? len : max_len; + + for (std::size_t i = 0; i < use_len; ++i) + { + factor /= base; + const unsigned char ch = s[i]; + acc += static_cast (ch) * factor; + } + + return static_cast (acc); +} +static double +string_domain_frac_lt (const std::string &lo, const std::string &hi, const std::string &v) +{ + auto to_bytes = [] (const std::string &s) -> const unsigned char * + { + return reinterpret_cast (s.data ()); + }; + + const double plo = string_pos (to_bytes (lo), lo.size ()); + const double phi = string_pos (to_bytes (hi), hi.size ()); + const double pv = string_pos (to_bytes (v), v.size ()); + + const double den = phi - plo; + double t = (pv - plo) / den; + return clamp01 (t); +} + void histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) { - assert (selectivity != NULL); hist::HistogramReader histogram_reader; @@ -518,8 +611,206 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity } void -histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) +histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool include_equal, double *selectivity) { + assert (selectivity != NULL); + + PRED_CLASS pc_rhs = qo_classify (rhs); + if (pc_rhs != PC_CONST) + { + *selectivity = DEFAULT_COMP_SELECTIVITY; + return; + } + + hist::HistogramReader histogram_reader; + + if (!histogram_init_reader_from_lhs (lhs, histogram_reader)) + { + *selectivity = DEFAULT_COMP_SELECTIVITY; + return; + } + + histogram_key key; + if (!histogram_extract_key (&rhs->info.value.db_value, key)) + { + *selectivity = DEFAULT_COMP_SELECTIVITY; + return; + } + + int bucket_index = -1; + const double total_rows = histogram_reader.total_rows (); + double bucket_rows = 0.0; + + /* caculate bucket_rows for column <= rhs or column < rhs */ + switch (key.kind) + { + case histogram_key_kind::i32: + bucket_index = histogram_reader.find_bucket (key.i32); + + if (bucket_index < 0) + { + *selectivity = 0.0; + return; + } + + if (histogram_reader.bucket_approx_ndv (bucket_index) == 1) + { + if (histogram_reader.check_value_included (bucket_index, key.i32)) + { + if (!is_ge && include_equal) + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index); + } + else + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + } + } + else + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + } + } + else + { + /* linear interpolation */ + const double frac = numeric_domain_frac_i32_lt (histogram_reader.bucket_hi (bucket_index - 1), + histogram_reader.bucket_hi (bucket_index), key.i32); + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1) + histogram_reader.bucket_rows ( + bucket_index) * frac; + } + break; + + case histogram_key_kind::dbl: + bucket_index = histogram_reader.find_bucket (key.dbl); + + if (bucket_index < 0) + { + *selectivity = 0.0; + return; + } + + if (histogram_reader.bucket_approx_ndv (bucket_index) == 1) + { + if (histogram_reader.check_value_included (bucket_index, key.dbl)) + { + if (!is_ge && include_equal) + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index); + } + else + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + } + } + else + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + } + } + else + { + /* linear interpolation */ + const double frac = numeric_domain_frac_dbl_lt (histogram_reader.bucket_hi (bucket_index - 1), + histogram_reader.bucket_hi (bucket_index), key.dbl); + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1) + histogram_reader.bucket_rows ( + bucket_index) * frac; + } + break; + + case histogram_key_kind::str: + bucket_index = histogram_reader.find_bucket (key.str); + if (bucket_index < 0) + { + *selectivity = 0.0; + return; + } + + if (histogram_reader.bucket_approx_ndv (bucket_index) == 1) + { + if (histogram_reader.check_value_included (bucket_index, key.str)) + { + if (!is_ge && include_equal) + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index); + } + else + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + } + } + else + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + } + } + else + { + /* linear interpolation */ + const double frac = string_domain_frac_lt (histogram_reader.bucket_hi (bucket_index - 1), + histogram_reader.bucket_hi (bucket_index), key.str); + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1) + histogram_reader.bucket_rows ( + bucket_index) * frac; + } + break; + + case histogram_key_kind::u64: + bucket_index = histogram_reader.find_bucket (key.u64); + + if (bucket_index < 0) + { + *selectivity = 0.0; + return; + } + + if (histogram_reader.bucket_approx_ndv (bucket_index) == 1) + { + if (histogram_reader.check_value_included (bucket_index, key.u64)) + { + if (!is_ge && include_equal) + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index); + } + else + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + } + } + else + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + } + } + else + { + /* linear interpolation */ + const double frac = numeric_domain_frac_u64_lt (histogram_reader.bucket_hi (bucket_index - 1), + histogram_reader.bucket_hi (bucket_index), key.u64); + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1) + histogram_reader.bucket_rows ( + bucket_index) * frac; + } + break; + + case histogram_key_kind::invalid: + default: + assert (false); + break; + } + + if (bucket_index < 0) + { + /* not found in histogram */ + *selectivity = 0.0; + return; + } + + /* selectivity = bucket_rows / total_rows */ + *selectivity = bucket_rows / total_rows; + + if (is_ge) + { + *selectivity = 1.0 - *selectivity; + } return; } diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index d19d4c6c13a..7b53bc714f3 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -87,7 +87,7 @@ int set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *att /* histogram selectivity evaluation functions */ void histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); -void histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); +void histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool include_equal, double *selectivity); void histogram_get_between_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); void histogram_get_range_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); void histogram_get_all_some_in_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index 061c6cc26a9..ff3163fd9cf 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -129,8 +129,13 @@ namespace hist } // ---------- access ---------- - std::int64_t HistogramReader::bucket_cumulative (std::uint32_t i) const + std::int64_t HistogramReader::bucket_cumulative (std::int32_t i) const { + if (i < 0) + { + return 0; + } + const char *p = bucket_rec (i) + 8; return get_value (p); } @@ -156,27 +161,46 @@ namespace hist // ---------- bucket_hi template specialization ---------- template<> - std::int64_t HistogramReader::bucket_hi (std::uint32_t i) const + std::int64_t HistogramReader::bucket_hi (std::int32_t i) const { + if (i < 0) + { + return std::numeric_limits::min(); + } + return get_value (bucket_hi_value_ptr (i)); } template<> - std::int32_t HistogramReader::bucket_hi (std::uint32_t i) const + std::int32_t HistogramReader::bucket_hi (std::int32_t i) const { - // DB_TYPE_INTEGER는 std::int64_t로 저장되지만, std::int32_t로 읽을 수 있음 + if (i < 0) + { + return std::numeric_limits::min(); + } + return static_cast (get_value (bucket_hi_value_ptr (i))); } template<> - double HistogramReader::bucket_hi (std::uint32_t i) const + double HistogramReader::bucket_hi (std::int32_t i) const { + if (i < 0) + { + return std::numeric_limits::min(); + } + return get_value (bucket_hi_value_ptr (i)); } template<> - std::string_view HistogramReader::bucket_hi (std::uint32_t i) const + std::string_view HistogramReader::bucket_hi (std::int32_t i) const { + if (i < 0) + { + return std::string_view{""}; + } + const char *p = bucket_hi_value_ptr (i); std::uint32_t len32 = get_value (p); std::uint32_t off32 = get_value (p + 4); @@ -190,9 +214,9 @@ namespace hist } template<> - std::string HistogramReader::bucket_hi (std::uint32_t i) const + std::string HistogramReader::bucket_hi (std::int32_t i) const { - const char *p = bucket_hi_value_ptr (i); + const char *p = bucket_hi_value_ptr (static_cast (i)); std::uint32_t len32 = get_value (p); std::uint32_t off32 = get_value (p + 4); @@ -205,9 +229,9 @@ namespace hist } template<> - unsigned long HistogramReader::bucket_hi (std::uint32_t i) const + unsigned long HistogramReader::bucket_hi (std::int32_t i) const { - return static_cast (get_value (bucket_hi_value_ptr (i))); + return static_cast (get_value (bucket_hi_value_ptr (static_cast (i)))); } // ---------- bucket_hi dump template specialization ---------- diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index 84600e749f6..79c73a60450 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -85,11 +85,11 @@ namespace hist return nb_ ? bucket_cumulative (nb_ - 1) : 0; } - std::int64_t bucket_cumulative (std::uint32_t i) const; + std::int64_t bucket_cumulative (std::int32_t i) const; std::int64_t bucket_approx_ndv (std::uint32_t i) const; template - T bucket_hi (std::uint32_t i) const; + T bucket_hi (std::int32_t i) const; template std::string bucket_hi_dump (std::uint32_t i) const; std::string bucket_hi_dump_with_type (std::uint32_t i, DB_TYPE attr_type) const; diff --git a/src/optimizer/query_planner.c b/src/optimizer/query_planner.c index 155eea869fb..5e8b0261628 100644 --- a/src/optimizer/query_planner.c +++ b/src/optimizer/query_planner.c @@ -409,19 +409,6 @@ QO_PLAN_VTBL *all_vtbls[] = { &qo_worst_plan_vtbl }; -/* Structural equivalence classes for expressions */ - -typedef enum PRED_CLASS -{ - PC_ATTR, - PC_CONST, - PC_HOST_VAR, - PC_SUBQUERY, - PC_SET, - PC_OTHER, - PC_MULTI_ATTR -} PRED_CLASS; - static double qo_or_selectivity (QO_ENV * env, double lhs_sel, double rhs_sel); static double qo_and_selectivity (QO_ENV * env, double lhs_sel, double rhs_sel); @@ -438,8 +425,6 @@ static double qo_range_selectivity (QO_ENV * env, PT_NODE * pt_expr); static double qo_all_some_in_selectivity (QO_ENV * env, PT_NODE * pt_expr); -static PRED_CLASS qo_classify (PT_NODE * attr); - static int qo_index_cardinality (QO_ENV * env, PT_NODE * attr); /* @@ -9840,7 +9825,22 @@ qo_comp_selectivity (QO_ENV * env, PT_NODE * pt_expr) break; case PC_CONST: - histogram_get_comp_selectivity (lhs, rhs, &selectivity); + if (pt_expr->info.expr.op == PT_GE) + { + histogram_get_comp_selectivity (lhs, rhs, true, true, &selectivity); + } + else if (pt_expr->info.expr.op == PT_GT) + { + histogram_get_comp_selectivity (lhs, rhs, true, false, &selectivity); + } + else if (pt_expr->info.expr.op == PT_LE) + { + histogram_get_comp_selectivity (lhs, rhs, false, true, &selectivity); + } + else if (pt_expr->info.expr.op == PT_LT) + { + histogram_get_comp_selectivity (lhs, rhs, false, false, &selectivity); + } break; default: @@ -9853,7 +9853,22 @@ qo_comp_selectivity (QO_ENV * env, PT_NODE * pt_expr) switch (pc_rhs) { case PC_ATTR: - histogram_get_comp_selectivity (rhs, lhs, &selectivity); + if (pt_expr->info.expr.op == PT_GE) + { + histogram_get_comp_selectivity (rhs, lhs, false, false, &selectivity); + } + else if (pt_expr->info.expr.op == PT_GT) + { + histogram_get_comp_selectivity (rhs, lhs, false, true, &selectivity); + } + else if (pt_expr->info.expr.op == PT_LE) + { + histogram_get_comp_selectivity (rhs, lhs, true, false, &selectivity); + } + else if (pt_expr->info.expr.op == PT_LT) + { + histogram_get_comp_selectivity (rhs, lhs, true, true, &selectivity); + } break; default: @@ -9975,9 +9990,42 @@ qo_range_selectivity (QO_ENV * env, PT_NODE * pt_expr) pc1 = qo_classify (arg1); if (op_type == PT_BETWEEN_GE_LE || op_type == PT_BETWEEN_GE_LT || op_type == PT_BETWEEN_GT_LE - || op_type == PT_BETWEEN_GT_LT) + || op_type == PT_BETWEEN_GT_LT || op_type == PT_BETWEEN_INF_LT || op_type == PT_BETWEEN_INF_LE + || op_type == PT_BETWEEN_GE_INF || op_type == PT_BETWEEN_GT_INF) { - selectivity = DEFAULT_BETWEEN_SELECTIVITY; + double selectivity_a = 0.0, selectivity_b = 0.0; + if (op_type == PT_BETWEEN_GE_LE) + { + /* selectivity = sel_le(b) - sel_lt(a) */ + histogram_get_comp_selectivity (lhs, arg1, false, false, &selectivity_a); + histogram_get_comp_selectivity (lhs, arg2, false, true, &selectivity_b); + selectivity = selectivity_b - selectivity_a; + } + else if (op_type == PT_BETWEEN_GE_LT) + { + /* selectivity = sel_lt(b) - sel_lt(a) */ + histogram_get_comp_selectivity (lhs, arg1, false, false, &selectivity_a); + histogram_get_comp_selectivity (lhs, arg2, false, false, &selectivity_b); + selectivity = selectivity_b - selectivity_a; + } + else if (op_type == PT_BETWEEN_GT_LE) + { + /* selectivity = sel_le(b) - sel_lt(a) */ + histogram_get_comp_selectivity (lhs, arg1, false, true, &selectivity_a); + histogram_get_comp_selectivity (lhs, arg2, false, true, &selectivity_b); + selectivity = selectivity_b - selectivity_a; + } + else if (op_type == PT_BETWEEN_GT_LT) + { + /* selectivity = sel_lt(b) - sel_lt(a) */ + histogram_get_comp_selectivity (lhs, arg1, false, true, &selectivity_a); + histogram_get_comp_selectivity (lhs, arg2, false, false, &selectivity_b); + selectivity = selectivity_b - selectivity_a; + } + if (selectivity <= 0.0) + { + selectivity = DEFAULT_RANGE_SELECTIVITY; + } } else if (op_type == PT_BETWEEN_EQ_NA) { @@ -10128,7 +10176,7 @@ qo_all_some_in_selectivity (QO_ENV * env, PT_NODE * pt_expr) * return: PRED_CLASS * attr(in): pt node to classify */ -static PRED_CLASS +PRED_CLASS qo_classify (PT_NODE * attr) { switch (attr->node_type) diff --git a/src/optimizer/query_planner.h b/src/optimizer/query_planner.h index cb9e060c398..a2c8a477451 100644 --- a/src/optimizer/query_planner.h +++ b/src/optimizer/query_planner.h @@ -120,6 +120,17 @@ typedef enum #define DEFAULT_IN_SELECTIVITY (double) 0.01 #define DEFAULT_RANGE_SELECTIVITY (double) 0.1 +typedef enum PRED_CLASS +{ + PC_ATTR, + PC_CONST, + PC_HOST_VAR, + PC_SUBQUERY, + PC_SET, + PC_OTHER, + PC_MULTI_ATTR +} PRED_CLASS; + struct qo_plan { QO_INFO *info; @@ -436,6 +447,8 @@ extern int qo_has_like_recompile_candidate (QO_PLAN * plan, void *arg); extern PT_NODE *qo_plan_compute_iscan_sort_list (QO_PLAN * root, PT_NODE * group_by, bool * is_index_w_prefix, bool for_min_max_optimize); +extern PRED_CLASS qo_classify (PT_NODE * node); + extern QO_PLAN_PARALLEL_OPT_USE qo_check_hjoin_for_parallel_opt (QO_PLAN * plan); #endif /* _QUERY_PLANNER_H_ */ From b636de2e1cc789e0f62352d31472a5c3a18738e1 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 12 Dec 2025 17:59:35 +0900 Subject: [PATCH 058/112] =?UTF-8?q?(feature/bugfix)=20selectivity=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=EC=8B=9D=20=EA=B4=80=EB=A0=A8=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 60 ++++++++-------- src/histogram/histogram_cl.hpp | 8 +-- src/optimizer/query_planner.c | 122 ++++++++++++++++++++++----------- 3 files changed, 116 insertions(+), 74 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 1b4a4939063..215b035c94b 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -459,7 +459,7 @@ numeric_domain_frac_i32_lt (std::int32_t lo, std::int32_t hi, std::int32_t v) { return 1.0; } - return (v - lo) / (hi - lo); + return (static_cast (v) - static_cast (lo)) / (static_cast (hi) - static_cast (lo)); } double numeric_domain_frac_u64_lt (std::uint64_t lo, std::uint64_t hi, std::uint64_t v) @@ -528,6 +528,11 @@ string_pos (const unsigned char *s, std::size_t len, std::size_t max_len = 16) static double string_domain_frac_lt (const std::string &lo, const std::string &hi, const std::string &v) { + if (hi >= v) + { + return 1.0; + } + auto to_bytes = [] (const std::string &s) -> const unsigned char * { return reinterpret_cast (s.data ()); @@ -543,21 +548,27 @@ string_domain_frac_lt (const std::string &lo, const std::string &hi, const std:: } void -histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) +histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity, bool *success) { assert (selectivity != NULL); + PRED_CLASS pc_rhs = qo_classify (rhs); + if (pc_rhs != PC_CONST) + { + *success = false; + return; + } hist::HistogramReader histogram_reader; if (!histogram_init_reader_from_lhs (lhs, histogram_reader)) { - *selectivity = DEFAULT_EQUAL_SELECTIVITY; + *success = false; return; } histogram_key key; if (!histogram_extract_key (&rhs->info.value.db_value, key)) { - *selectivity = DEFAULT_EQUAL_SELECTIVITY; + *success = false; return; } @@ -591,6 +602,7 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity if (!found || bucket_index < 0) { /* not found in histogram */ + *success = true; *selectivity = 0.0; return; } @@ -602,23 +614,25 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity if (total_rows <= 0.0 || approx_ndv <= 0.0) { /* safe default */ - *selectivity = DEFAULT_EQUAL_SELECTIVITY; + *success = false; return; } *selectivity = (bucket_rows / total_rows) / approx_ndv; + *success = true; return; } void -histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool include_equal, double *selectivity) +histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool include_equal, double *selectivity, + bool *success) { assert (selectivity != NULL); PRED_CLASS pc_rhs = qo_classify (rhs); if (pc_rhs != PC_CONST) { - *selectivity = DEFAULT_COMP_SELECTIVITY; + *success = false; return; } @@ -626,14 +640,14 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc if (!histogram_init_reader_from_lhs (lhs, histogram_reader)) { - *selectivity = DEFAULT_COMP_SELECTIVITY; + *success = false; return; } histogram_key key; if (!histogram_extract_key (&rhs->info.value.db_value, key)) { - *selectivity = DEFAULT_COMP_SELECTIVITY; + *success = false; return; } @@ -657,13 +671,13 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc { if (histogram_reader.check_value_included (bucket_index, key.i32)) { - if (!is_ge && include_equal) + if (is_ge == include_equal) { - bucket_rows = histogram_reader.bucket_cumulative (bucket_index); + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); } else { - bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + bucket_rows = histogram_reader.bucket_cumulative (bucket_index); } } else @@ -686,6 +700,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc if (bucket_index < 0) { + *success = true; *selectivity = 0.0; return; } @@ -722,6 +737,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc bucket_index = histogram_reader.find_bucket (key.str); if (bucket_index < 0) { + *success = true; *selectivity = 0.0; return; } @@ -759,6 +775,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc if (bucket_index < 0) { + *success = true; *selectivity = 0.0; return; } @@ -800,6 +817,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc if (bucket_index < 0) { /* not found in histogram */ + *success = true; *selectivity = 0.0; return; } @@ -811,24 +829,8 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc { *selectivity = 1.0 - *selectivity; } - return; -} - -void -histogram_get_between_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) -{ - return; -} -void -histogram_get_range_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) -{ - return; -} - -void -histogram_get_all_some_in_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity) -{ + *success = true; return; } diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index 7b53bc714f3..02575106271 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -86,11 +86,9 @@ int set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *att int histogram_total_length, MOP classop); /* histogram selectivity evaluation functions */ -void histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); -void histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool include_equal, double *selectivity); -void histogram_get_between_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); -void histogram_get_range_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); -void histogram_get_all_some_in_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity); +void histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity, bool *success); +void histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool include_equal, double *selectivity, + bool *success); /* histogram utility functions */ int db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj); diff --git a/src/optimizer/query_planner.c b/src/optimizer/query_planner.c index 5e8b0261628..c2f05332dd1 100644 --- a/src/optimizer/query_planner.c +++ b/src/optimizer/query_planner.c @@ -9533,6 +9533,8 @@ qo_equal_selectivity (QO_ENV * env, PT_NODE * pt_expr) selectivity = DEFAULT_EQUAL_SELECTIVITY; + bool success = false; + switch (pc_lhs) { case PC_ATTR: @@ -9560,8 +9562,8 @@ qo_equal_selectivity (QO_ENV * env, PT_NODE * pt_expr) break; case PC_CONST: - histogram_get_equal_selectivity (lhs, rhs, &selectivity); - if (selectivity != DEFAULT_EQUAL_SELECTIVITY) + histogram_get_equal_selectivity (lhs, rhs, &selectivity, &success); + if (success) { break; } @@ -9598,13 +9600,13 @@ qo_equal_selectivity (QO_ENV * env, PT_NODE * pt_expr) switch (pc_rhs) { case PC_ATTR: - histogram_get_equal_selectivity (rhs, lhs, &selectivity); + histogram_get_equal_selectivity (rhs, lhs, &selectivity, &success); break; default: break; } - if (selectivity != DEFAULT_EQUAL_SELECTIVITY) + if (success) { break; } @@ -9814,6 +9816,7 @@ qo_comp_selectivity (QO_ENV * env, PT_NODE * pt_expr) selectivity = DEFAULT_COMP_SELECTIVITY; + bool success = false; switch (pc_lhs) { case PC_ATTR: @@ -9827,19 +9830,19 @@ qo_comp_selectivity (QO_ENV * env, PT_NODE * pt_expr) case PC_CONST: if (pt_expr->info.expr.op == PT_GE) { - histogram_get_comp_selectivity (lhs, rhs, true, true, &selectivity); + histogram_get_comp_selectivity (lhs, rhs, true, true, &selectivity, &success); } else if (pt_expr->info.expr.op == PT_GT) { - histogram_get_comp_selectivity (lhs, rhs, true, false, &selectivity); + histogram_get_comp_selectivity (lhs, rhs, true, false, &selectivity, &success); } else if (pt_expr->info.expr.op == PT_LE) { - histogram_get_comp_selectivity (lhs, rhs, false, true, &selectivity); + histogram_get_comp_selectivity (lhs, rhs, false, true, &selectivity, &success); } else if (pt_expr->info.expr.op == PT_LT) { - histogram_get_comp_selectivity (lhs, rhs, false, false, &selectivity); + histogram_get_comp_selectivity (lhs, rhs, false, false, &selectivity, &success); } break; @@ -9855,19 +9858,19 @@ qo_comp_selectivity (QO_ENV * env, PT_NODE * pt_expr) case PC_ATTR: if (pt_expr->info.expr.op == PT_GE) { - histogram_get_comp_selectivity (rhs, lhs, false, false, &selectivity); + histogram_get_comp_selectivity (rhs, lhs, false, false, &selectivity, &success); } else if (pt_expr->info.expr.op == PT_GT) { - histogram_get_comp_selectivity (rhs, lhs, false, true, &selectivity); + histogram_get_comp_selectivity (rhs, lhs, false, true, &selectivity, &success); } else if (pt_expr->info.expr.op == PT_LE) { - histogram_get_comp_selectivity (rhs, lhs, true, false, &selectivity); + histogram_get_comp_selectivity (rhs, lhs, true, false, &selectivity, &success); } else if (pt_expr->info.expr.op == PT_LT) { - histogram_get_comp_selectivity (rhs, lhs, true, true, &selectivity); + histogram_get_comp_selectivity (rhs, lhs, true, true, &selectivity, &success); } break; @@ -9893,7 +9896,7 @@ qo_comp_selectivity (QO_ENV * env, PT_NODE * pt_expr) break; } - return selectivity; + return success ? selectivity : DEFAULT_COMP_SELECTIVITY; } /* @@ -9994,35 +9997,74 @@ qo_range_selectivity (QO_ENV * env, PT_NODE * pt_expr) || op_type == PT_BETWEEN_GE_INF || op_type == PT_BETWEEN_GT_INF) { double selectivity_a = 0.0, selectivity_b = 0.0; - if (op_type == PT_BETWEEN_GE_LE) + bool success1 = false; + bool success2 = false; + switch (op_type) { - /* selectivity = sel_le(b) - sel_lt(a) */ - histogram_get_comp_selectivity (lhs, arg1, false, false, &selectivity_a); - histogram_get_comp_selectivity (lhs, arg2, false, true, &selectivity_b); - selectivity = selectivity_b - selectivity_a; - } - else if (op_type == PT_BETWEEN_GE_LT) - { - /* selectivity = sel_lt(b) - sel_lt(a) */ - histogram_get_comp_selectivity (lhs, arg1, false, false, &selectivity_a); - histogram_get_comp_selectivity (lhs, arg2, false, false, &selectivity_b); - selectivity = selectivity_b - selectivity_a; - } - else if (op_type == PT_BETWEEN_GT_LE) - { - /* selectivity = sel_le(b) - sel_lt(a) */ - histogram_get_comp_selectivity (lhs, arg1, false, true, &selectivity_a); - histogram_get_comp_selectivity (lhs, arg2, false, true, &selectivity_b); - selectivity = selectivity_b - selectivity_a; - } - else if (op_type == PT_BETWEEN_GT_LT) - { - /* selectivity = sel_lt(b) - sel_lt(a) */ - histogram_get_comp_selectivity (lhs, arg1, false, true, &selectivity_a); - histogram_get_comp_selectivity (lhs, arg2, false, false, &selectivity_b); - selectivity = selectivity_b - selectivity_a; + case PT_BETWEEN_GE_LE: + { + /* selectivity = sel_le(b) - sel_lt(a) */ + histogram_get_comp_selectivity (lhs, arg1, false, false, &selectivity_a, &success1); + histogram_get_comp_selectivity (lhs, arg2, false, true, &selectivity_b, &success2); + selectivity = selectivity_b - selectivity_a; + break; + } + case PT_BETWEEN_GE_LT: + { + /* selectivity = sel_lt(b) - sel_lt(a) */ + histogram_get_comp_selectivity (lhs, arg1, false, false, &selectivity_a, &success1); + histogram_get_comp_selectivity (lhs, arg2, false, false, &selectivity_b, &success2); + selectivity = selectivity_b - selectivity_a; + break; + } + case PT_BETWEEN_GT_LE: + { + /* selectivity = sel_le(b) - sel_lt(a) */ + histogram_get_comp_selectivity (lhs, arg1, false, true, &selectivity_a, &success1); + histogram_get_comp_selectivity (lhs, arg2, false, true, &selectivity_b, &success2); + selectivity = selectivity_b - selectivity_a; + break; + } + case PT_BETWEEN_GT_LT: + { + /* selectivity = sel_lt(b) - sel_lt(a) */ + histogram_get_comp_selectivity (lhs, arg1, false, true, &selectivity_a, &success1); + histogram_get_comp_selectivity (lhs, arg2, false, false, &selectivity_b, &success2); + selectivity = selectivity_b - selectivity_a; + break; + } + case PT_BETWEEN_INF_LT: + { + histogram_get_comp_selectivity (lhs, arg1, false, false, &selectivity_a, &success1); + success2 = true; + selectivity = selectivity_a; + break; + } + case PT_BETWEEN_INF_LE: + { + histogram_get_comp_selectivity (lhs, arg1, false, true, &selectivity_a, &success1); + success2 = true; + selectivity = selectivity_a; + break; + } + case PT_BETWEEN_GT_INF: + { + histogram_get_comp_selectivity (lhs, arg1, true, false, &selectivity_a, &success1); + success2 = true; + selectivity = selectivity_a; + break; + } + case PT_BETWEEN_GE_INF: + { + histogram_get_comp_selectivity (lhs, arg1, true, true, &selectivity_a, &success1); + success2 = true; + selectivity = selectivity_a; + break; + } + default: + break; } - if (selectivity <= 0.0) + if (!(success1 && success2)) { selectivity = DEFAULT_RANGE_SELECTIVITY; } From 94a622d1e479d70605b1df730a414432c2922515 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 12 Dec 2025 18:54:48 +0900 Subject: [PATCH 059/112] =?UTF-8?q?(refactor):=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=201=EC=B0=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_builder.cpp | 81 ++++++---- src/histogram/histogram_builder.hpp | 2 +- src/histogram/histogram_cl.cpp | 230 ++++++++++++---------------- src/histogram/histogram_cl.hpp | 37 +++-- src/histogram/histogram_reader.cpp | 24 ++- src/optimizer/query_graph.c | 6 +- 6 files changed, 196 insertions(+), 184 deletions(-) diff --git a/src/histogram/histogram_builder.cpp b/src/histogram/histogram_builder.cpp index 5830de3c79c..d51a87a6d5a 100644 --- a/src/histogram/histogram_builder.cpp +++ b/src/histogram/histogram_builder.cpp @@ -38,7 +38,14 @@ namespace hist template<> void HistogramBuilder::write (char *&dest, std::int64_t v) { - OR_PUT_INT64 (dest, &v); // 포인터 전달 필요 + OR_PUT_INT64 (dest, &v); + dest += OR_INT64_SIZE; + } + + template<> + void HistogramBuilder::write (char *&dest, std::uint64_t v) + { + OR_PUT_INT64 (dest, reinterpret_cast (&v)); dest += OR_INT64_SIZE; } @@ -57,10 +64,12 @@ namespace hist dest += OR_INT_SIZE; if (v.length() <= 4) { + // inline data memcpy (dest, v.data(), v.length()); } else { + // str blob data (length + pointer) OR_PUT_INT (dest, cur_str_off_); cur_str_off_ += v.length(); } @@ -75,45 +84,49 @@ namespace hist char *HistogramBuilder::build (THREAD_ENTRY *thread_p, DB_TYPE type, int *histogram_total_length) { - // ---- precompute record sizes ---- + /* ---- precompute record sizes ---- */ const std::uint32_t bucket_area_size = hist::BUCKET_RECORD_SIZE * buckets_.size(); - // ---- header ---- + /* ---- header ---- */ HeaderV1 H{}; std::memcpy (H.magic, "HST1", 4); H.version = htonl (1); H.nbuckets = htonl (static_cast (buckets_.size())); H.type = htonl (static_cast (type)); - H.str_size = 0; // Fix Later - H.total_size = 0; // Fix Later + H.str_size = 0; + H.total_size = 0; - char *buffer = static_cast (db_private_alloc (thread_p, sizeof (HeaderV1) + bucket_area_size)); // records + /* ---- records ---- */ + char *buffer = static_cast (db_private_alloc (thread_p, sizeof (HeaderV1) + bucket_area_size)); if (buffer == NULL) { return NULL; } - std::memset (buffer, 0, sizeof (HeaderV1) + bucket_area_size); // initialize to zero + std::memset (buffer, 0, sizeof (HeaderV1) + bucket_area_size); // must be initialized to zero char *end_buffer = buffer + sizeof (HeaderV1) + bucket_area_size; char *buffer_ptr = buffer + sizeof (HeaderV1); char *str_blob_ptr; - // buckets area + + /* ---- buckets area ---- */ if (buckets_.empty()) { return buffer; // return empty buffer if no buckets } - // Use index-based loop for safer access + /* ---- index-based loop for safer access ---- */ for (size_t i = 0; i < buckets_.size(); ++i) { const Bucket b = buckets_[i]; switch (type) { + /* ---- int64_t value ---- */ case DB_TYPE_INTEGER: + case DB_TYPE_SHORT: + case DB_TYPE_BIGINT: { - // DB_TYPE_INTEGER는 std::int64_t로 저장됨 (HistogramTypes에 std::int32_t 없음) if (std::holds_alternative (b.data_hi)) { - // int64_t 값을 int32_t로 변환하여 저장 (실제로는 32bit 값이므로) + // ---- int64_t value to int32_t value ---- std::int64_t val = std::get (b.data_hi); write (buffer_ptr, static_cast (val)); } @@ -124,7 +137,10 @@ namespace hist } } break; + /* ---- double value ---- */ case DB_TYPE_DOUBLE: + case DB_TYPE_FLOAT: + case DB_TYPE_NUMERIC: { if (std::holds_alternative (b.data_hi)) { @@ -137,11 +153,20 @@ namespace hist } } break; - case DB_TYPE_BIGINT: + /* ---- string value ---- */ + case DB_TYPE_STRING: + case DB_TYPE_BIT: + case DB_TYPE_VARBIT: + case DB_TYPE_CHAR: { - if (std::holds_alternative (b.data_hi)) + if (std::holds_alternative (b.data_hi)) + { + write (buffer_ptr, std::get (b.data_hi)); + } + else if (std::holds_alternative (b.data_hi)) { - write (buffer_ptr, std::get (b.data_hi)); + std::string_view sv = std::get (b.data_hi); + write (buffer_ptr, std::string (sv)); } else { @@ -149,17 +174,17 @@ namespace hist return NULL; } } - break; - case DB_TYPE_STRING: + /* ---- uint64_t value ---- */ + case DB_TYPE_TIME: + case DB_TYPE_TIMESTAMP: + case DB_TYPE_TIMESTAMPLTZ: + case DB_TYPE_DATE: + case DB_TYPE_MONETARY: + case DB_TYPE_TIMESTAMPTZ: { - if (std::holds_alternative (b.data_hi)) + if (std::holds_alternative (b.data_hi)) { - write (buffer_ptr, std::get (b.data_hi)); - } - else if (std::holds_alternative (b.data_hi)) - { - std::string_view sv = std::get (b.data_hi); - write (buffer_ptr, std::string (sv)); + write (buffer_ptr, std::get (b.data_hi)); } else { @@ -169,7 +194,7 @@ namespace hist } break; default: - // not_implemented + /* never reach here */ assert (false); return NULL; } @@ -179,7 +204,7 @@ namespace hist assert (buffer_ptr == end_buffer); - // build string blob + /* ---- build string blob ---- */ if (cur_str_off_ > 0) { assert (DB_TYPE_STRING == type); @@ -189,7 +214,7 @@ namespace hist return NULL; } char *cur_str_blob_ptr = str_blob_ptr; - std::memset (str_blob_ptr, 0, cur_str_off_); // initialize to zero + std::memset (str_blob_ptr, 0, cur_str_off_); // must be initialized to zero char *str_blob_ptr_end = str_blob_ptr + cur_str_off_; for (const auto &b : buckets_) { @@ -217,7 +242,7 @@ namespace hist } } } - // write string + /* ---- write string ---- */ assert (cur_str_blob_ptr == str_blob_ptr_end); buffer = static_cast (db_private_realloc (thread_p, buffer, sizeof (HeaderV1) + bucket_area_size + cur_str_off_)); @@ -230,12 +255,12 @@ namespace hist db_private_free (thread_p, str_blob_ptr); } + /* ---- write header ---- */ H.str_size = htonl (static_cast (cur_str_off_)); H.total_size = htonl (static_cast (sizeof (HeaderV1) + bucket_area_size + cur_str_off_)); memcpy (buffer, &H, sizeof (HeaderV1)); *histogram_total_length = sizeof (HeaderV1) + bucket_area_size + cur_str_off_; - // write header return buffer; } } // namespace hist diff --git a/src/histogram/histogram_builder.hpp b/src/histogram/histogram_builder.hpp index 7c8d6389743..d97d29cdf80 100644 --- a/src/histogram/histogram_builder.hpp +++ b/src/histogram/histogram_builder.hpp @@ -36,7 +36,7 @@ namespace hist using HistogramTypes = std::variant; struct Bucket { - HistogramTypes data_hi; // std::variant: int32_t, int64_t, double, string 중 하나 + HistogramTypes data_hi; /* std::variant: int64_t, uint64_t, double, string_view, string */ std::int64_t cumulative; std::int64_t approx_ndv; }; diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 215b035c94b..d301b8a8bb5 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -17,7 +17,7 @@ */ /* - * histogram_cl.cpp - Histogram Client implementation + * histogram_cl.cpp - Histogram Client Library implementation */ @@ -39,13 +39,18 @@ #include "authenticate.h" #include "query_planner.h" +static bool histogram_extract_key (const DB_VALUE *db_val, hist::histogram_key &key); + /* - * analyze_all_classes + * analyze_classes () * - * return: + * return: NO_ERROR if successful, otherwise an error code + * thread_p(in): thread pointer + * tbl_name(in): table name + * attr_name(in): attribute name + * max_number_of_buckets(in): maximum number of buckets * with_fullscan(in): true iff WITH FULLSCAN - * - * NOTE: + * classop(in): class object pointer */ int analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, @@ -54,6 +59,8 @@ analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_ int error = NO_ERROR; char *histogram_blob = NULL; int histogram_total_length = 0; + + // ---- get histogram ---- error = get_histogram (thread_p, tbl_name, attr_name, max_number_of_buckets, with_fullscan, &histogram_blob, &histogram_total_length); @@ -61,16 +68,32 @@ analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_ { return error; } + + // ---- set histogram ---- error = set_histogram (thread_p, tbl_name, attr_name, histogram_blob, histogram_total_length, classop); if (error != NO_ERROR) { return error; } + + // ---- free histogram blob ---- db_private_free (thread_p, histogram_blob); return NO_ERROR; } +/* + * get_histogram () + * + * return: NO_ERROR if successful, otherwise an error code + * thread_p(in): thread pointer + * tbl_name(in): table name + * attr_name(in): attribute name + * max_number_of_buckets(in): maximum number of buckets + * with_fullscan(in): true iff WITH FULLSCAN + * histogram_blob(out): histogram blob + * histogram_total_length(out): histogram total length + */ int get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, bool with_fullscan, char **histogram_blob, int *histogram_total_length) @@ -80,9 +103,12 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na DB_QUERY_ERROR query_error; hist::HistogramBuilder histogram_builder; DB_TYPE type = DB_TYPE_UNKNOWN; - int number_of_mcv = 3; // TODO + // ---- number of MCV ---- + int number_of_mcv = std::min (100, max_number_of_buckets / 2); + + // ---- query buffer ---- (query_length + table_name_length + attr_name_length) + char query_buf[1024+222+254]; - char query_buf[1024+222+254]; // TODO GET MAX TABLE NAME LENGTH FROM SQL.H if (!with_fullscan) { snprintf (query_buf, sizeof (query_buf), HISTOGRAM_WITH_SAMPLING_SCAN_QUERY_TEMPLATE, attr_name, tbl_name, @@ -102,6 +128,7 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na } error = db_query_first_tuple (query_result); + if (error != DB_CURSOR_SUCCESS) { if (error == DB_CURSOR_END) @@ -129,112 +156,43 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na { return error; } - switch (value[1].domain.general_info.type) - { - case DB_TYPE_INTEGER: - { - hi = static_cast < std::int64_t > (db_get_int (&value[1])); - break; - } - case DB_TYPE_SHORT: - { - hi = static_cast < std::int64_t > (db_get_short (&value[1])); - break; - } - case DB_TYPE_FLOAT: - { - double val = db_get_float (&value[1]); - hi = val; - break; - } - case DB_TYPE_DOUBLE: - { - double val = db_get_double (&value[1]); - hi = val; - break; - } - case DB_TYPE_NUMERIC: - { - /* Actually, the numeric type is a 16-byte value with very high precision, - * but for approximate statistical calculations it's probably better not to - * rely on the full 16-byte precision. */ - double val; - numeric_coerce_num_to_double (db_get_numeric (&value[1]), db_value_scale (&value[1]), &val); - hi = val; - break; - } - case DB_TYPE_BIT: - case DB_TYPE_VARBIT: - { - /* deal as char type */ - int length = 0; - const char *str = db_get_bit (&value[1], &length); - if (str == NULL) - { - return ER_FAILED; - } - std::string str_val (str, length); - hi = str_val; - break; - } - case DB_TYPE_CHAR: /* later consider for null trailing exists */ - case DB_TYPE_STRING: + + /* ---- extract key from DB_VALUE ---- */ + hist::histogram_key key; + if (!histogram_extract_key (&value[1], key)) { - const char *str = db_get_string (&value[1]); - if (str == NULL) - { - return ER_FAILED; - } - std::string str_val (str); - hi = str_val; - break; + return error; } - case DB_TYPE_TIME: + + switch (key.kind) { - DB_TIME *time = db_get_time (&value[1]); - hi = static_cast (*time); - break; - } - case DB_TYPE_TIMESTAMP: - case DB_TYPE_TIMESTAMPLTZ: + case hist::histogram_key_kind::i64: { - DB_TIMESTAMP *timestamp = db_get_timestamp (&value[1]); - hi = static_cast (*timestamp); + histogram_builder.add (static_cast (key.i64), db_get_bigint (&value[3]), db_get_bigint (&value[4])); break; } - case DB_TYPE_DATE: + case hist::histogram_key_kind::dbl: { - DB_DATE *date = db_get_date (&value[1]); - hi = static_cast (*date); + histogram_builder.add (static_cast (key.dbl), db_get_bigint (&value[3]), db_get_bigint (&value[4])); break; } - case DB_TYPE_MONETARY: + case hist::histogram_key_kind::str: { - /* Its use is deprecated, but it has been kept for backporting purposes. */ - DB_MONETARY *monetary = db_get_monetary (&value[1]); - hi = static_cast (monetary->amount); + histogram_builder.add (key.str, db_get_bigint (&value[3]), db_get_bigint (&value[4])); break; } - case DB_TYPE_TIMESTAMPTZ: + case hist::histogram_key_kind::u64: { - DB_TIMESTAMPTZ *timestamptz = db_get_timestamptz (&value[1]); - hi = static_cast (timestamptz->timestamp); + histogram_builder.add (key.u64, db_get_bigint (&value[3]), db_get_bigint (&value[4])); break; } - case DB_TYPE_DATETIMETZ: - case DB_TYPE_DATETIMELTZ: + default: { - /* in comparison, the order is maintained by date and time */ - DB_DATETIMETZ *datetimetz = db_get_datetimetz (&value[1]); - hi = static_cast (datetimetz->datetime.date) << 32 | datetimetz->datetime.time; - break; + /* never reach here */ + assert (false); + return ER_FAILED; } - default: - assert (false); /* impossible to reach here - blocked at parser layer first */ - break; } - histogram_builder.add (hi, db_get_bigint (&value[3]), db_get_bigint (&value[4])); - type = static_cast (value[1].domain.general_info.type); } while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS); @@ -333,34 +291,39 @@ histogram_init_reader_from_lhs (PT_NODE *lhs, hist::HistogramReader &reader) } static bool -histogram_extract_key (const DB_VALUE *db_val, histogram_key &key) +histogram_extract_key (const DB_VALUE *db_val, hist::histogram_key &key) { const DB_TYPE type = static_cast (db_val->domain.general_info.type); switch (type) { case DB_TYPE_INTEGER: - key.kind = histogram_key_kind::i32; - key.i32 = db_get_int (db_val); + key.kind = hist::histogram_key_kind::i64; + key.i64 = db_get_int (db_val); return true; case DB_TYPE_SHORT: - key.kind = histogram_key_kind::i32; - key.i32 = static_cast (db_get_short (db_val)); + key.kind = hist::histogram_key_kind::i64; + key.i64 = static_cast (db_get_short (db_val)); + return true; + + case DB_TYPE_BIGINT: + key.kind = hist::histogram_key_kind::i64; + key.i64 = db_get_bigint (db_val); return true; case DB_TYPE_FLOAT: - key.kind = histogram_key_kind::dbl; + key.kind = hist::histogram_key_kind::dbl; key.dbl = static_cast (db_get_float (db_val)); return true; case DB_TYPE_DOUBLE: - key.kind = histogram_key_kind::dbl; + key.kind = hist::histogram_key_kind::dbl; key.dbl = db_get_double (db_val); return true; case DB_TYPE_NUMERIC: - key.kind = histogram_key_kind::dbl; + key.kind = hist::histogram_key_kind::dbl; numeric_coerce_num_to_double (db_get_numeric (db_val), db_value_scale (db_val), &key.dbl); return true; @@ -373,7 +336,7 @@ histogram_extract_key (const DB_VALUE *db_val, histogram_key &key) { return false; } - key.kind = histogram_key_kind::str; + key.kind = hist::histogram_key_kind::str; key.str.assign (str, length); return true; } @@ -386,7 +349,7 @@ histogram_extract_key (const DB_VALUE *db_val, histogram_key &key) { return false; } - key.kind = histogram_key_kind::str; + key.kind = hist::histogram_key_kind::str; key.str.assign (str); return true; } @@ -394,7 +357,7 @@ histogram_extract_key (const DB_VALUE *db_val, histogram_key &key) case DB_TYPE_TIME: { DB_TIME *timep = db_get_time (db_val); - key.kind = histogram_key_kind::u64; + key.kind = hist::histogram_key_kind::u64; key.u64 = static_cast (*timep); return true; } @@ -403,7 +366,7 @@ histogram_extract_key (const DB_VALUE *db_val, histogram_key &key) case DB_TYPE_TIMESTAMPLTZ: { DB_TIMESTAMP *tsp = db_get_timestamp (db_val); - key.kind = histogram_key_kind::u64; + key.kind = hist::histogram_key_kind::u64; key.u64 = static_cast (*tsp); return true; } @@ -411,7 +374,7 @@ histogram_extract_key (const DB_VALUE *db_val, histogram_key &key) case DB_TYPE_DATE: { DB_DATE *datep = db_get_date (db_val); - key.kind = histogram_key_kind::u64; + key.kind = hist::histogram_key_kind::u64; key.u64 = static_cast (*datep); return true; } @@ -419,7 +382,7 @@ histogram_extract_key (const DB_VALUE *db_val, histogram_key &key) case DB_TYPE_MONETARY: { DB_MONETARY *monetary = db_get_monetary (db_val); - key.kind = histogram_key_kind::u64; + key.kind = hist::histogram_key_kind::u64; key.u64 = static_cast (monetary->amount); return true; } @@ -427,7 +390,7 @@ histogram_extract_key (const DB_VALUE *db_val, histogram_key &key) case DB_TYPE_TIMESTAMPTZ: { DB_TIMESTAMPTZ *timestamptz = db_get_timestamptz (db_val); - key.kind = histogram_key_kind::u64; + key.kind = hist::histogram_key_kind::u64; key.u64 = static_cast (timestamptz->timestamp); return true; } @@ -436,7 +399,7 @@ histogram_extract_key (const DB_VALUE *db_val, histogram_key &key) case DB_TYPE_DATETIMELTZ: { DB_DATETIMETZ *datetimetz = db_get_datetimetz (db_val); - key.kind = histogram_key_kind::u64; + key.kind = hist::histogram_key_kind::u64; key.u64 = (static_cast (datetimetz->datetime.date) << 32) | static_cast (datetimetz->datetime.time); return true; @@ -448,8 +411,10 @@ histogram_extract_key (const DB_VALUE *db_val, histogram_key &key) } } +/* numeric domain fraction less than function for int64_t and uint64_t and double and string */ + static double -numeric_domain_frac_i32_lt (std::int32_t lo, std::int32_t hi, std::int32_t v) +numeric_domain_frac_i64_lt (std::int64_t lo, std::int64_t hi, std::int64_t v) { if (v <= lo) { @@ -525,6 +490,7 @@ string_pos (const unsigned char *s, std::size_t len, std::size_t max_len = 16) return static_cast (acc); } + static double string_domain_frac_lt (const std::string &lo, const std::string &hi, const std::string &v) { @@ -547,6 +513,8 @@ string_domain_frac_lt (const std::string &lo, const std::string &hi, const std:: return clamp01 (t); } +/* histogram get selectivity functions */ + void histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity, bool *success) { @@ -565,7 +533,7 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity return; } - histogram_key key; + hist::histogram_key key; if (!histogram_extract_key (&rhs->info.value.db_value, key)) { *success = false; @@ -577,23 +545,23 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity switch (key.kind) { - case histogram_key_kind::i32: - found = histogram_reader.find_bucket_and_check (key.i32, bucket_index); + case hist::histogram_key_kind::i64: + found = histogram_reader.find_bucket_and_check (key.i64, bucket_index); break; - case histogram_key_kind::dbl: + case hist::histogram_key_kind::dbl: found = histogram_reader.find_bucket_and_check (key.dbl, bucket_index); break; - case histogram_key_kind::str: + case hist::histogram_key_kind::str: found = histogram_reader.find_bucket_and_check (key.str, bucket_index); break; - case histogram_key_kind::u64: + case hist::histogram_key_kind::u64: found = histogram_reader.find_bucket_and_check (key.u64, bucket_index); break; - case histogram_key_kind::invalid: + case hist::histogram_key_kind::invalid: default: assert (false); break; @@ -644,7 +612,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc return; } - histogram_key key; + hist::histogram_key key; if (!histogram_extract_key (&rhs->info.value.db_value, key)) { *success = false; @@ -658,8 +626,8 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc /* caculate bucket_rows for column <= rhs or column < rhs */ switch (key.kind) { - case histogram_key_kind::i32: - bucket_index = histogram_reader.find_bucket (key.i32); + case hist::histogram_key_kind::i64: + bucket_index = histogram_reader.find_bucket (key.i64); if (bucket_index < 0) { @@ -669,7 +637,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc if (histogram_reader.bucket_approx_ndv (bucket_index) == 1) { - if (histogram_reader.check_value_included (bucket_index, key.i32)) + if (histogram_reader.check_value_included (bucket_index, key.i64)) { if (is_ge == include_equal) { @@ -688,14 +656,14 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc else { /* linear interpolation */ - const double frac = numeric_domain_frac_i32_lt (histogram_reader.bucket_hi (bucket_index - 1), - histogram_reader.bucket_hi (bucket_index), key.i32); + const double frac = numeric_domain_frac_i64_lt (histogram_reader.bucket_hi (bucket_index - 1), + histogram_reader.bucket_hi (bucket_index), key.i64); bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1) + histogram_reader.bucket_rows ( bucket_index) * frac; } break; - case histogram_key_kind::dbl: + case hist::histogram_key_kind::dbl: bucket_index = histogram_reader.find_bucket (key.dbl); if (bucket_index < 0) @@ -733,7 +701,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc } break; - case histogram_key_kind::str: + case hist::histogram_key_kind::str: bucket_index = histogram_reader.find_bucket (key.str); if (bucket_index < 0) { @@ -770,7 +738,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc } break; - case histogram_key_kind::u64: + case hist::histogram_key_kind::u64: bucket_index = histogram_reader.find_bucket (key.u64); if (bucket_index < 0) @@ -808,8 +776,9 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc } break; - case histogram_key_kind::invalid: + case hist::histogram_key_kind::invalid: default: + /* never reach here */ assert (false); break; } @@ -914,7 +883,7 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) return error; } - (*histogram)->histogram[i] = histogram_value; // should clear histogram_value + (*histogram)->histogram[i] = histogram_value; /* should clear histogram_value */ i++; } return NO_ERROR; @@ -953,6 +922,7 @@ is_histogrammable_type (DB_TYPE type) case DB_TYPE_DOUBLE: case DB_TYPE_NUMERIC: case DB_TYPE_MONETARY: + case DB_TYPE_BIGINT: return true; /* bit string */ diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index 02575106271..eecafe58d99 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -33,6 +33,7 @@ struct parser_node; typedef struct parser_node PT_NODE; typedef struct hist_stats HIST_STATS; +/* histogram query template */ static const char *HISTOGRAM_QUERY_TEMPLATE = "WITH src AS (SELECT %s AS val FROM %s WHERE %s IS NOT NULL), " "cnt AS (SELECT val, COUNT(*) AS c FROM src GROUP BY val), " @@ -45,6 +46,7 @@ static const char *HISTOGRAM_QUERY_TEMPLATE = "all_buckets AS (SELECT * FROM hist_buckets UNION ALL SELECT * FROM mcv_buckets) " "SELECT bid, MAX(val) AS endpoint, SUM(c) AS rows_in_bucket, SUM(SUM(c)) OVER (ORDER BY MAX(val)) AS cumulative, " "COUNT(*) AS approx_ndv, MAX(is_mcv) AS is_mcv FROM all_buckets GROUP BY bid ORDER BY MAX(val);"; +/* histogram with sampling scan query template */ static const char *HISTOGRAM_WITH_SAMPLING_SCAN_QUERY_TEMPLATE = "WITH src AS (SELECT /*+ SAMPLING_SCAN */ %s AS val FROM %s WHERE %s IS NOT NULL), " "cnt AS (SELECT val, COUNT(*) AS c FROM src GROUP BY val), " @@ -59,23 +61,28 @@ static const char *HISTOGRAM_WITH_SAMPLING_SCAN_QUERY_TEMPLATE = "COUNT(*) AS approx_ndv, MAX(is_mcv) AS is_mcv FROM all_buckets GROUP BY bid ORDER BY MAX(val);"; /* histogram key kind */ -enum class histogram_key_kind +namespace hist { - invalid, - i32, - dbl, - str, - u64 -}; -struct histogram_key -{ - histogram_key_kind kind = histogram_key_kind::invalid; - std::int32_t i32 = 0; - double dbl = 0.0; - std::string str; - std::uint64_t u64 = 0; -}; + enum class histogram_key_kind + { + invalid, + i64, + dbl, + str, + u64 + }; + + struct histogram_key + { + histogram_key_kind kind = histogram_key_kind::invalid; + std::int32_t i64 = 0; + double dbl = 0.0; + std::string str; + std::uint64_t u64 = 0; + }; + +} // namespace hist /* histogram analysis functions */ int analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index ff3163fd9cf..030330d7605 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -43,6 +43,14 @@ namespace hist return value; } + template<> + std::uint64_t HistogramReader::get_value (const void *ptr) const + { + std::uint64_t value; + OR_GET_INT64 (ptr, reinterpret_cast (&value)); + return value; + } + template<> double HistogramReader::get_value (const void *ptr) const { @@ -229,9 +237,9 @@ namespace hist } template<> - unsigned long HistogramReader::bucket_hi (std::int32_t i) const + std::uint64_t HistogramReader::bucket_hi (std::int32_t i) const { - return static_cast (get_value (bucket_hi_value_ptr (static_cast (i)))); + return static_cast (get_value (bucket_hi_value_ptr (static_cast (i)))); } // ---------- bucket_hi dump template specialization ---------- @@ -253,6 +261,12 @@ namespace hist return std::to_string (get_value (bucket_hi_value_ptr (i))); } + template<> + std::string HistogramReader::bucket_hi_dump (std::uint32_t i) const + { + return std::to_string (static_cast (get_value (bucket_hi_value_ptr (i)))); + } + template<> std::string HistogramReader::bucket_hi_dump (std::uint32_t i) const { @@ -283,12 +297,6 @@ namespace hist return std::string{str_blob_.data() + off32, static_cast (std::min (len32, static_cast (8)))}; } - template<> - std::string HistogramReader::bucket_hi_dump (std::uint32_t i) const - { - return std::to_string (static_cast (get_value (bucket_hi_value_ptr (i)))); - } - std::string HistogramReader::bucket_hi_dump_with_type (std::uint32_t i, DB_TYPE attr_type) const { switch (attr_type) diff --git a/src/optimizer/query_graph.c b/src/optimizer/query_graph.c index 78ca1da08f9..5a015f3d49a 100644 --- a/src/optimizer/query_graph.c +++ b/src/optimizer/query_graph.c @@ -2903,7 +2903,6 @@ set_seg_node (PT_NODE * attr, QO_ENV * env, BITSET * bitset) QO_SEGMENT *seg; PT_NODE *entity; - assert (attr->node_type == PT_NAME); node = lookup_node (attr, env, &entity); /* node will be null if this attr resolves to an enclosing scope */ @@ -2914,7 +2913,10 @@ set_seg_node (PT_NODE * attr, QO_ENV * env, BITSET * bitset) * for shared variables, and it doesn't really hurt anyone just * to ignore failures here. */ - attr->info.name.histogram = seg->pt_node->info.name.histogram; + if (attr->node_type == PT_NAME) + { + attr->info.name.histogram = seg->pt_node->info.name.histogram; + } bitset_add (bitset, QO_SEG_IDX (seg)); } From b19d2748f1906a44ab4386799392a31753f28e45 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 17 Dec 2025 13:27:10 +0900 Subject: [PATCH 060/112] (bugfix) histogram bug fix --- src/histogram/histogram_builder.cpp | 7 +------ src/histogram/histogram_cl.cpp | 9 +++++++++ src/object/schema_manager.c | 4 ++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/histogram/histogram_builder.cpp b/src/histogram/histogram_builder.cpp index d51a87a6d5a..f54886d3dbc 100644 --- a/src/histogram/histogram_builder.cpp +++ b/src/histogram/histogram_builder.cpp @@ -107,12 +107,6 @@ namespace hist char *buffer_ptr = buffer + sizeof (HeaderV1); char *str_blob_ptr; - /* ---- buckets area ---- */ - if (buckets_.empty()) - { - return buffer; // return empty buffer if no buckets - } - /* ---- index-based loop for safer access ---- */ for (size_t i = 0; i < buckets_.size(); ++i) { @@ -174,6 +168,7 @@ namespace hist return NULL; } } + break; /* ---- uint64_t value ---- */ case DB_TYPE_TIME: case DB_TYPE_TIMESTAMP: diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index d301b8a8bb5..87df93f31bb 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -127,6 +127,11 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na return error; } + if (error == 0) /* empty histogram */ + { + goto build_histogram; + } + error = db_query_first_tuple (query_result); if (error != DB_CURSOR_SUCCESS) @@ -164,6 +169,8 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na return error; } + type = static_cast (value[1].domain.general_info.type); + switch (key.kind) { case hist::histogram_key_kind::i64: @@ -196,6 +203,8 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na } while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS); +build_histogram: + *histogram_blob = histogram_builder.build (thread_p, type, histogram_total_length); if (*histogram_blob == NULL) { diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 3228bf42aeb..fb806637c84 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -15582,6 +15582,10 @@ sm_add_histogram (MOP classop, const char *attr_name, int bucket_count, bool wit error = smt_check_histogram_exist (classop, attr_name); if (error != NO_ERROR) { + if (error == ER_LC_CLASSNAME_EXIST) + { + return error; + } goto error_exit; } From 0b9b7af85386c34f6bd5dc68ab74b2864f97854c Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 17 Dec 2025 16:02:35 +0900 Subject: [PATCH 061/112] =?UTF-8?q?(feature)=20null=20frequency=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 156 +++++++++++++++++- src/histogram/histogram_cl.hpp | 8 + src/object/schema_manager.c | 1 - src/object/schema_system_catalog_install.cpp | 2 +- ...hema_system_catalog_install_query_spec.cpp | 2 +- src/object/schema_template.c | 17 +- src/storage/statistics.h | 1 + 7 files changed, 178 insertions(+), 9 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 87df93f31bb..1d729238c97 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -60,6 +60,13 @@ analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_ char *histogram_blob = NULL; int histogram_total_length = 0; + // ---- get null frequency ---- + error = get_null_frequency (thread_p, tbl_name, attr_name, with_fullscan, classop); + if (error != NO_ERROR) + { + return error; + } + // ---- get histogram ---- error = get_histogram (thread_p, tbl_name, attr_name, max_number_of_buckets, with_fullscan, &histogram_blob, @@ -82,6 +89,103 @@ analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_ return NO_ERROR; } +/* + * get_null_frequency () + * + * return: NO_ERROR if successful, otherwise an error code + * classop(in): class object pointer + * attr_name(in): attribute name + * null_frequency(out): null frequency + */ +int +get_null_frequency (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, bool with_fullscan, + MOP classop) +{ + int error = NO_ERROR; + DB_OBJECT *histogram_obj, *edit_histogram_object = NULL; + DB_OTMPL *obj_tmpl = NULL; + DB_VALUE null_frequency_value; + DB_QUERY_RESULT *query_result; + DB_QUERY_ERROR query_error; + + char query_buf[512+222+254]; // (query_length + table_name_length + attr_name_length) + + if (!with_fullscan) + { + snprintf (query_buf, sizeof (query_buf), NULL_FREQUENCY_WITH_SAMPLING_SCAN_QUERY_TEMPLATE, attr_name, tbl_name); + } + else + { + snprintf (query_buf, sizeof (query_buf), NULL_FREQUENCY_QUERY_TEMPLATE, attr_name, tbl_name); + } + + error = db_compile_and_execute_local (query_buf, &query_result, &query_error); + + if (error < 1) + { + return error; + } + + error = db_query_first_tuple (query_result); + + if (error != DB_CURSOR_SUCCESS) + { + if (error == DB_CURSOR_END) + { + error = NO_ERROR; + } + else + { + ASSERT_ERROR (); + } + return error; + } + + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("null_frequency"), &null_frequency_value); + + error = db_get_histogram (classop, attr_name, &histogram_obj); + if (error != NO_ERROR) + { + return error; + } + + obj_tmpl = dbt_edit_object (histogram_obj); + if (obj_tmpl == NULL) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + goto end; + } + + error = dbt_put (obj_tmpl, "null_frequency", &null_frequency_value); + if (error != NO_ERROR) + { + goto end; + } + + edit_histogram_object = dbt_finish_object (obj_tmpl); + if (edit_histogram_object == NULL) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + goto end; + } + + assert (edit_histogram_object == histogram_obj); + obj_tmpl = NULL; + + error = locator_flush_instance (edit_histogram_object); + if (error != NO_ERROR) + { + goto end; + } + +end: + db_value_clear (&null_frequency_value); + assert (error == NO_ERROR); // for debug + return error; +} + /* * get_histogram () * @@ -200,6 +304,11 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na return ER_FAILED; } } + db_value_clear (&value[0]); + db_value_clear (&value[1]); + db_value_clear (&value[2]); + db_value_clear (&value[3]); + db_value_clear (&value[4]); } while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS); @@ -849,6 +958,7 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) DB_OBJECT *histogram_obj = NULL; SM_ATTRIBUTE *att; SM_CLASS *class_ = NULL; + error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT); if (error != NO_ERROR) { @@ -867,11 +977,18 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) return ER_OUT_OF_VIRTUAL_MEMORY; } + (*histogram)->null_frequency = (double *) db_ws_alloc (sizeof (double)); + if ((*histogram)->null_frequency == NULL) + { + return ER_OUT_OF_VIRTUAL_MEMORY; + } + + int i = 0; for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) { const char *attname = (char *) att->header.name; - DB_VALUE *histogram_value = NULL; + DB_VALUE *histogram_value = NULL, *null_frequency_value = NULL; error = db_get_histogram (classop, attname, &histogram_obj); if (error != NO_ERROR) { @@ -881,18 +998,32 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) if (histogram_obj == NULL) { (*histogram)->histogram[i] = nullptr; + (*histogram)->null_frequency[i] = 0.0; i++; continue; } histogram_value = (DB_VALUE *) db_ws_alloc (sizeof (DB_VALUE)); error = db_get (histogram_obj, "histogram_values", histogram_value); + if (error != NO_ERROR) + { + return error; + } + error = db_get (histogram_obj, "null_frequency", null_frequency_value); if (error != NO_ERROR) { return error; } (*histogram)->histogram[i] = histogram_value; /* should clear histogram_value */ + if (db_value_is_null (null_frequency_value)) + { + (*histogram)->null_frequency[i] = 0.0; + } + else + { + (*histogram)->null_frequency[i] = db_get_double (null_frequency_value); + } i++; } return NO_ERROR; @@ -914,6 +1045,7 @@ int stats_free_histogram_and_init (HIST_STATS *histogram) db_ws_free (histogram->histogram[i]); histogram->histogram[i] = nullptr; } + db_ws_free (histogram->null_frequency); db_ws_free (histogram->histogram); db_ws_free (histogram); return NO_ERROR; @@ -985,7 +1117,7 @@ dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with const char *type_name = db_get_type_name (attr_type); int rows_scanned = 0; int bucket_count = 0; - DB_VALUE histogram_value; + DB_VALUE histogram_value, null_frequency_value; DB_OBJECT *histogram_obj = NULL; int histogram_total_length = 0; @@ -1022,6 +1154,22 @@ dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with return ER_FAILED; } + /* get histgoram */ + error = db_get (histogram_obj, "null_frequency", &null_frequency_value); + if (error != NO_ERROR) + { + return ER_FAILED; + } + + if (db_value_is_null (&null_frequency_value)) + { + null_frequency = 0.0; + } + else + { + null_frequency = db_get_double (&null_frequency_value); + } + const char *histogram_blob_ptr = db_get_bit (&histogram_value, &histogram_total_length); if (histogram_blob_ptr == NULL || histogram_total_length <= 0) { @@ -1069,7 +1217,9 @@ dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with } fprintf (f, "| %-47s|\n", line); - /* buckets + null frec line : TODO add null frequency */ + snprintf (line, sizeof (line), " null frequency : %.3f", null_frequency); + fprintf (f, "| %-47s|\n", line); + snprintf (line, sizeof (line), " buckets + mcv: %d", static_cast (histogram_reader.bucket_count())); diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index eecafe58d99..32da09c9790 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -33,6 +33,12 @@ struct parser_node; typedef struct parser_node PT_NODE; typedef struct hist_stats HIST_STATS; +/* null frequency query template */ +static const char *NULL_FREQUENCY_QUERY_TEMPLATE = + "SELECT SUM(CASE WHEN %s IS NULL THEN 1 ELSE 0 END) * 1.0 / NULLIF(COUNT(*), 0) AS null_frequency FROM %s;"; +static const char *NULL_FREQUENCY_WITH_SAMPLING_SCAN_QUERY_TEMPLATE = + "SELECT /*+ SAMPLING_SCAN */ SUM(CASE WHEN %s IS NULL THEN 1 ELSE 0 END) * 1.0 / NULLIF(COUNT(*), 0) AS null_frequency FROM %s;"; + /* histogram query template */ static const char *HISTOGRAM_QUERY_TEMPLATE = "WITH src AS (SELECT %s AS val FROM %s WHERE %s IS NOT NULL), " @@ -87,6 +93,8 @@ namespace hist /* histogram analysis functions */ int analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, bool with_fullscan, MOP classop); +int get_null_frequency (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, bool with_fullscan, + MOP classop); int get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, int max_number_of_buckets, bool with_fullscan, char **histogram_blob, int *histogram_total_length); int set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_name, char *histogram_blob, diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index fb806637c84..e632247733a 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -12493,7 +12493,6 @@ install_new_representation (MOP classop, SM_CLASS * class_, SM_TEMPLATE * flat) class_->stats = NULL; } - /* TODO: HISTOGRAM */ if (newrep && class_->histogram != NULL) { stats_free_histogram_and_init (class_->histogram); diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index 5e6447c059b..90bec15c3ec 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -1270,7 +1270,7 @@ namespace cubschema {"class_of", "object"}, {"key_attr", format_varchar (255)}, {"with_fullscan","integer"}, - {"bucket_count", "integer"}, + {"null_frequency", "double"}, {"histogram_values", format_varbit (1073741823) } }, // constraint diff --git a/src/object/schema_system_catalog_install_query_spec.cpp b/src/object/schema_system_catalog_install_query_spec.cpp index 76ee34a25c7..870d41eacd5 100644 --- a/src/object/schema_system_catalog_install_query_spec.cpp +++ b/src/object/schema_system_catalog_install_query_spec.cpp @@ -1648,7 +1648,7 @@ sm_define_view_db_histogram_spec (void) "[h].[class_of] AS [class_of], " "[h].[key_attr] AS [key_attr], " "[h].[with_fullscan] AS [with_fullscan], " // TODO : integer -> varchar(32) - "[h].[bucket_count] AS [bucket_count], " + "[h].[null_frequency] AS [null_frequency], " "[h].[histogram_values] AS [histogram_values] " "FROM " /* CT_DB_HISTOGRAM_NAME */ diff --git a/src/object/schema_template.c b/src/object/schema_template.c index 77c5a2dbdf3..9ee92b09bef 100644 --- a/src/object/schema_template.c +++ b/src/object/schema_template.c @@ -2068,6 +2068,7 @@ smt_add_histogram (MOP classop, const char *attr_name, int bucket_count, bool wi DB_OBJECT *ret_obj = NULL, *histogram_class = NULL; DB_VALUE value; DB_OTMPL *obj_tmpl = NULL; + double null_frequency = 0; db_make_null (&value); /* temporarily disable authorization to access db_serial class */ @@ -2108,14 +2109,24 @@ smt_add_histogram (MOP classop, const char *attr_name, int bucket_count, bool wi goto end; } - /* bucket_count */ - db_make_int (&value, bucket_count); - error = dbt_put_internal (obj_tmpl, "bucket_count", &value); + /* with_fullscan */ + db_make_int (&value, with_fullscan); + error = dbt_put_internal (obj_tmpl, "with_fullscan", &value); pr_clear_value (&value); if (error != NO_ERROR) { goto end; } + + + db_make_double (&value, null_frequency); + error = dbt_put_internal (obj_tmpl, "null_frequency", &value); + pr_clear_value (&value); + if (error != NO_ERROR) + { + goto end; + } + /* histogram_values */ db_make_null (&value); error = dbt_put_internal (obj_tmpl, "histogram_values", &value); diff --git a/src/storage/statistics.h b/src/storage/statistics.h index 1bb1855952d..bb30795426b 100644 --- a/src/storage/statistics.h +++ b/src/storage/statistics.h @@ -104,6 +104,7 @@ struct hist_stats { int n_attrs; /* number of attributes; size of the histogram[] */ DB_VALUE **histogram; /* column histogram , null if not exists */ + double *null_frequency; /* column null frequency , 0 if not exists */ }; /* Statistical Information about the attribute NDV */ From f2beb136140ac4fdbb7ac14ce799a338bf501b29 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 17 Dec 2025 16:09:35 +0900 Subject: [PATCH 062/112] (feature) sampling weight rate 33% max 5000 pages, min 100 pages --- src/query/scan_manager.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/query/scan_manager.c b/src/query/scan_manager.c index 84c870c0d07..19ef494e883 100644 --- a/src/query/scan_manager.c +++ b/src/query/scan_manager.c @@ -2898,8 +2898,14 @@ scan_open_heap_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id, return ER_FAILED; } - /* sampling_weight = total_page / sampling_page */ - hsidp->sampling.weight = MAX ((total_pages / NUMBER_OF_SAMPLING_PAGES), 1); + /* sampling_weight: default 30% sampling, minimum 100 pages, maximum 5000 pages */ + /* 30% sampling = weight approximately 3.33 (1/0.3) */ + int base_weight = 3; /* base weight for 33% sampling */ + int min_weight = (total_pages + 99) / 100; /* ensure minimum 100 pages (rounded up) */ + int max_weight = total_pages / 5000; /* limit maximum 5000 pages */ + + /* select the smaller value between base_weight and min_weight, and greater than max_weight */ + hsidp->sampling.weight = MAX (MIN (base_weight, min_weight), MAX (max_weight, 1)); } return NO_ERROR; From fb8ce8b9c9cc7c3b57d4eef96517dfeb95d1771e Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 17 Dec 2025 16:48:04 +0900 Subject: [PATCH 063/112] =?UTF-8?q?(bugfix)=20=ED=9E=88=EC=8A=A4=ED=86=A0?= =?UTF-8?q?=EA=B7=B8=EB=9E=A8=20=EC=98=A4=EB=A5=98=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 1d729238c97..fabea45bf52 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -977,7 +977,7 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) return ER_OUT_OF_VIRTUAL_MEMORY; } - (*histogram)->null_frequency = (double *) db_ws_alloc (sizeof (double)); + (*histogram)->null_frequency = (double *) db_ws_alloc (sizeof (double) * class_->att_count); if ((*histogram)->null_frequency == NULL) { return ER_OUT_OF_VIRTUAL_MEMORY; From 59449d964a36e60b5f81fd11f844a35720150bf9 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 14:35:52 +0900 Subject: [PATCH 064/112] =?UTF-8?q?(bugfix,=20refactor)=20sql=20test=20?= =?UTF-8?q?=EC=A4=91=EB=8C=80=EB=B2=84=EA=B7=B8=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/transform.c | 14 -------------- src/optimizer/query_graph.c | 8 ++++---- src/parser/parser_message.h | 2 -- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/object/transform.c b/src/object/transform.c index fba54614821..a6dba46bda0 100644 --- a/src/object/transform.c +++ b/src/object/transform.c @@ -431,13 +431,6 @@ static CT_ATTR ct_partition_atts[] = { {"comment", NULL_ATTRID, DB_TYPE_VARCHAR} }; -static CT_ATTR ct_histogram_atts[] = { - {"class_of", NULL_ATTRID, DB_TYPE_OBJECT}, - {"key_attr", NULL_ATTRID, DB_TYPE_VARCHAR}, - {"with_fullscan", NULL_ATTRID, DB_TYPE_INTEGER}, - {"bucket_count", NULL_ATTRID, DB_TYPE_INTEGER} -}; - CT_CLASS ct_Class = { CT_CLASS_NAME, OID_INITIALIZER, @@ -529,12 +522,6 @@ CT_CLASS ct_Indexkey = { ct_indexkey_atts }; -CT_CLASS ct_Histogram = { - CT_DB_HISTOGRAM_NAME, - OID_INITIALIZER, - (sizeof (ct_histogram_atts) / sizeof (ct_histogram_atts[0])), - ct_histogram_atts -}; CT_CLASS *ct_Classes[] = { &ct_Class, @@ -548,7 +535,6 @@ CT_CLASS *ct_Classes[] = { &ct_Index, &ct_Indexkey, &ct_Partition, - &ct_Histogram, NULL }; diff --git a/src/optimizer/query_graph.c b/src/optimizer/query_graph.c index 5a015f3d49a..9101573e67b 100644 --- a/src/optimizer/query_graph.c +++ b/src/optimizer/query_graph.c @@ -5183,7 +5183,7 @@ qo_get_attr_info (QO_ENV * env, QO_SEGMENT * seg) int attr_id; QO_ATTR_CUM_STATS *cum_statsp; ATTR_STATS *attr_statsp; - DB_VALUE *attr_hist_statsp; + int attr_hist_statsp_index = 0; BTREE_STATS *bt_statsp; int n_attrs; const char *name; @@ -5283,9 +5283,9 @@ qo_get_attr_info (QO_ENV * env, QO_SEGMENT * seg) /* search the attribute from the class information */ attr_statsp = stats->attr_stats; - attr_hist_statsp = hist_stats->histogram[0]; + attr_hist_statsp_index = 0; n_attrs = stats->n_attrs; - for (j = 0; j < n_attrs; j++, attr_statsp++, attr_hist_statsp++) + for (j = 0; j < n_attrs; j++, attr_statsp++, attr_hist_statsp_index++) { if (attr_statsp->id == attr_id) { @@ -5303,7 +5303,7 @@ qo_get_attr_info (QO_ENV * env, QO_SEGMENT * seg) attr_infop->ndv += attr_statsp->ndv; /* set histogram */ - QO_SEG_PT_NODE (seg)->info.name.histogram = attr_hist_statsp; + QO_SEG_PT_NODE (seg)->info.name.histogram = hist_stats->histogram[attr_hist_statsp_index]; if (cum_statsp->valid_limits == false) { diff --git a/src/parser/parser_message.h b/src/parser/parser_message.h index 9d3a171a112..043612c3a14 100644 --- a/src/parser/parser_message.h +++ b/src/parser/parser_message.h @@ -174,8 +174,6 @@ #define MSGCAT_SYNTAX_MAX_SERVER_USER_LEN MSGCAT_SYNTAX_NO(137) #define MSGCAT_SYNTAX_INVALID_LEVEL MSGCAT_SYNTAX_NO(138) #define MSGCAT_SYNTAX_NO_PRECISION_IN_SP_FUNCTION MSGCAT_SYNTAX_NO(139) -#define MSGCAT_SYNTAX_INVALID_update_histogram MSGCAT_SYNTAX_NO(140) -#define MSGCAT_SYNTAX_INVALID_DROP_HISTOGRAM MSGCAT_SYNTAX_NO(141) /* Message id in the set MSGCAT_SET_PARSER_SEMANTIC */ From f0693afc7e86b8de3d47b14496a81d799a718ceb Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 15:00:12 +0900 Subject: [PATCH 065/112] =?UTF-8?q?(bugfix)=20column=EC=9D=B4=20=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=ED=85=8C=EC=9D=B4=EB=B8=94=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=20=EC=98=A4=EB=A5=98=EB=B0=9C=EC=83=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index fabea45bf52..5c840ced0f0 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -971,6 +971,12 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) return ER_OUT_OF_VIRTUAL_MEMORY; } (*histogram)->n_attrs = class_->att_count; + if (class_->att_count == 0) + { + (*histogram)->histogram = nullptr; + (*histogram)->null_frequency = nullptr; + return NO_ERROR; + } (*histogram)->histogram = (DB_VALUE **) db_ws_alloc (sizeof (DB_VALUE *) * class_->att_count); if ((*histogram)->histogram == NULL) { @@ -1045,8 +1051,11 @@ int stats_free_histogram_and_init (HIST_STATS *histogram) db_ws_free (histogram->histogram[i]); histogram->histogram[i] = nullptr; } - db_ws_free (histogram->null_frequency); - db_ws_free (histogram->histogram); + if (histogram->n_attrs != 0) + { + db_ws_free (histogram->null_frequency); + db_ws_free (histogram->histogram); + } db_ws_free (histogram); return NO_ERROR; } From 1d4e3f388da08cdcfe055c16ce707f1daac44d59 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 15:39:13 +0900 Subject: [PATCH 066/112] =?UTF-8?q?(bugfix/feature)=20null=5Ffrequency=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20bug=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_builder.cpp | 38 +++++++++++++---------------- src/histogram/histogram_cl.cpp | 12 ++++++--- src/optimizer/query_graph.c | 2 ++ src/parser/parse_tree.h | 1 + 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/histogram/histogram_builder.cpp b/src/histogram/histogram_builder.cpp index f54886d3dbc..68d97fac1b3 100644 --- a/src/histogram/histogram_builder.cpp +++ b/src/histogram/histogram_builder.cpp @@ -202,7 +202,6 @@ namespace hist /* ---- build string blob ---- */ if (cur_str_off_ > 0) { - assert (DB_TYPE_STRING == type); str_blob_ptr = static_cast (db_private_alloc (thread_p, cur_str_off_)); if (str_blob_ptr == NULL) { @@ -213,28 +212,25 @@ namespace hist char *str_blob_ptr_end = str_blob_ptr + cur_str_off_; for (const auto &b : buckets_) { - if (DB_TYPE_STRING == type) + std::string str_val; + if (std::holds_alternative (b.data_hi)) + { + str_val = std::get (b.data_hi); + } + else if (std::holds_alternative (b.data_hi)) { - std::string str_val; - if (std::holds_alternative (b.data_hi)) - { - str_val = std::get (b.data_hi); - } - else if (std::holds_alternative (b.data_hi)) - { - str_val = std::string (std::get (b.data_hi)); - } - else - { - assert (false); - return NULL; - } + str_val = std::string (std::get (b.data_hi)); + } + else + { + assert (false); + return NULL; + } - if (str_val.length() > 4) - { - memcpy (cur_str_blob_ptr, str_val.data(), str_val.length()); - cur_str_blob_ptr += str_val.length(); - } + if (str_val.length() > 4) + { + memcpy (cur_str_blob_ptr, str_val.data(), str_val.length()); + cur_str_blob_ptr += str_val.length(); } } /* ---- write string ---- */ diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 5c840ced0f0..788bec6ed4d 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -696,6 +696,7 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity const double bucket_rows = static_cast (histogram_reader.bucket_rows (bucket_index)); const double total_rows = static_cast (histogram_reader.total_rows ()); const double approx_ndv = static_cast (histogram_reader.bucket_approx_ndv (bucket_index)); + const double null_frequency = lhs->info.name.null_frequency; if (total_rows <= 0.0 || approx_ndv <= 0.0) { @@ -705,6 +706,7 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity } *selectivity = (bucket_rows / total_rows) / approx_ndv; + *selectivity *= (1.0 - null_frequency); *success = true; return; } @@ -917,6 +919,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc *selectivity = 1.0 - *selectivity; } + *selectivity *= (1.0 - lhs->info.name.null_frequency); *success = true; return; } @@ -994,7 +997,8 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) { const char *attname = (char *) att->header.name; - DB_VALUE *histogram_value = NULL, *null_frequency_value = NULL; + DB_VALUE *histogram_value = NULL; + DB_VALUE null_frequency_value; error = db_get_histogram (classop, attname, &histogram_obj); if (error != NO_ERROR) { @@ -1015,20 +1019,20 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) { return error; } - error = db_get (histogram_obj, "null_frequency", null_frequency_value); + error = db_get (histogram_obj, "null_frequency", &null_frequency_value); if (error != NO_ERROR) { return error; } (*histogram)->histogram[i] = histogram_value; /* should clear histogram_value */ - if (db_value_is_null (null_frequency_value)) + if (db_value_is_null (&null_frequency_value)) { (*histogram)->null_frequency[i] = 0.0; } else { - (*histogram)->null_frequency[i] = db_get_double (null_frequency_value); + (*histogram)->null_frequency[i] = db_get_double (&null_frequency_value); } i++; } diff --git a/src/optimizer/query_graph.c b/src/optimizer/query_graph.c index 9101573e67b..6e2977f05ff 100644 --- a/src/optimizer/query_graph.c +++ b/src/optimizer/query_graph.c @@ -2916,6 +2916,7 @@ set_seg_node (PT_NODE * attr, QO_ENV * env, BITSET * bitset) if (attr->node_type == PT_NAME) { attr->info.name.histogram = seg->pt_node->info.name.histogram; + attr->info.name.null_frequency = seg->pt_node->info.name.null_frequency; } bitset_add (bitset, QO_SEG_IDX (seg)); } @@ -5304,6 +5305,7 @@ qo_get_attr_info (QO_ENV * env, QO_SEGMENT * seg) /* set histogram */ QO_SEG_PT_NODE (seg)->info.name.histogram = hist_stats->histogram[attr_hist_statsp_index]; + QO_SEG_PT_NODE (seg)->info.name.null_frequency = hist_stats->null_frequency[attr_hist_statsp_index]; if (cum_statsp->valid_limits == false) { diff --git a/src/parser/parse_tree.h b/src/parser/parse_tree.h index c7b589e75d3..384decd22d3 100644 --- a/src/parser/parse_tree.h +++ b/src/parser/parse_tree.h @@ -2677,6 +2677,7 @@ struct pt_name_info PT_RESERVED_NAME_ID reserved_id; /* used to identify reserved name */ size_t json_table_column_index; /* will be used only for json_table to gather attributes in the correct order */ DB_VALUE *histogram; /* histogram value */ + double null_frequency; /* null frequency value */ }; /* From 11226b91b8aa14b9e161b795d1c0129641e99b6e Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 19:10:10 +0900 Subject: [PATCH 067/112] =?UTF-8?q?(feature)=20alter=20column=EC=8B=9C=20h?= =?UTF-8?q?istogram=EC=9D=B4=20=EC=A0=9C=EA=B1=B0=EB=90=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_reader.cpp | 5 ++-- src/object/schema_manager.c | 20 ++------------- src/parser/semantic_check.c | 2 +- src/query/execute_schema.c | 41 ++++++++++++++++++++++++++++-- 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index 030330d7605..59c8185c2c0 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -215,7 +215,7 @@ namespace hist if (len32 <= 4) // inline data { - return std::string_view{ p+4, static_cast (len32-4) }; + return std::string_view{ p+4, static_cast (len32) }; } assert (off32 + len32 <= str_size_); return std::string_view{str_blob_.data() + off32, static_cast (len32)}; @@ -276,7 +276,7 @@ namespace hist if (len32 <= 4) // inline data { - return std::string{ p+4, static_cast (len32-4) }; + return std::string{ p+4, static_cast (len32) }; } assert (off32 + len32 <= str_size_); return std::string{str_blob_.data() + off32, static_cast (std::min (len32, static_cast (8)))}; @@ -314,6 +314,7 @@ namespace hist case DB_TYPE_STRING: return bucket_hi_dump (i); case DB_TYPE_TIME: + case DB_TYPE_BIGINT: return bucket_hi_dump (i); case DB_TYPE_TIMESTAMP: case DB_TYPE_TIMESTAMPLTZ: diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index e632247733a..78ee64b890b 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -13582,10 +13582,7 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) char *fk_name = NULL; const char *table_name; MOP save_user, owner; - DB_OBJECT *histogram_class, *histogram_obj = NULL; - DB_VALUE value[2]; - DB_VALUE *value_ptrs[2] = { &value[0], &value[1] }; - const char *search_attrs[2] = { "class_of", "key_attr" }; + DB_OBJECT *histogram_obj = NULL; int au_save; int save; bool is_au_disabled = false; @@ -13689,27 +13686,16 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) } } - histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); - if (histogram_class == NULL) - { - error = ER_BO_MISSING_OR_INVALID_CATALOG; - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); - goto end; - } AU_DISABLE (au_save); for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) { /* class_of, key_attr */ - db_make_object (&value[0], op); - db_make_string (&value[1], att->header.name); - histogram_obj = db_find_multi_unique (histogram_class, 2, (char **) search_attrs, value_ptrs, DB_FETCH_WRITE); + db_get_histogram (op, att->header.name, &histogram_obj); if (histogram_obj != NULL) { error = db_drop (histogram_obj); - db_value_clear (&value[0]); - db_value_clear (&value[1]); if (error != NO_ERROR) { AU_ENABLE (au_save); @@ -13717,8 +13703,6 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) } } - db_value_clear (&value[0]); - db_value_clear (&value[1]); } AU_ENABLE (au_save); diff --git a/src/parser/semantic_check.c b/src/parser/semantic_check.c index 41f26a5414d..3a65d17e0ff 100644 --- a/src/parser/semantic_check.c +++ b/src/parser/semantic_check.c @@ -12405,7 +12405,7 @@ pt_check_with_info (PARSER_CONTEXT * parser, PT_NODE * node, SEMANTIC_CHK_INFO * { sc_info_ptr->system_class = false; node = pt_resolve_names (parser, node, sc_info_ptr); - if (!pt_has_error (parser) && node->node_type == PT_UPDATE_HISTOGRAM) + if (!pt_has_error (parser) && node->node_type == PT_DROP_HISTOGRAM) { pt_check_update_histogram (parser, node); } diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 59560965310..9fddba970cf 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -1634,7 +1634,8 @@ do_alter (PARSER_CONTEXT * parser, PT_NODE * alter) PT_NODE *crt_clause = NULL; bool do_semantic_checks = false; bool do_rollback = false; - + int au_save = 0; + DB_OBJECT *histogram_obj = NULL; CHECK_MODIFICATION_ERROR (); /* Multiple alter operations in a single statement need to be atomic. */ @@ -1666,7 +1667,43 @@ do_alter (PARSER_CONTEXT * parser, PT_NODE * alter) } assert (crt_result == crt_clause); } - + AU_DISABLE (au_save); + /* HANDLE HISTOGRAM DROP WHILE COLUMN MODIFY, CHANGE, RENAME, DROP */ + switch (alter_code) + { + case PT_DROP_ATTR_MTHD: + case PT_MODIFY_ATTR_MTHD: + case PT_CHANGE_ATTR: + { + const char *attr_name = crt_clause->info.alter.alter_clause.attr_mthd.attr_old_name->info.name.original; + if (attr_name != NULL) + { + db_get_histogram (crt_clause->info.alter.entity_name->info.name.db_object, attr_name, &histogram_obj); + if (histogram_obj != NULL) + { + db_drop (histogram_obj); + } + } + break; + } + case PT_RENAME_ATTR_MTHD: + case PT_RENAME_ENTITY: + { + const char *attr_name = crt_clause->info.alter.alter_clause.rename.old_name->info.name.original; + if (attr_name != NULL) + { + db_get_histogram (crt_clause->info.alter.entity_name->info.name.db_object, attr_name, &histogram_obj); + if (histogram_obj != NULL) + { + db_drop (histogram_obj); + } + } + break; + } + default: + break; + } + AU_ENABLE (au_save); switch (alter_code) { case PT_RENAME_ENTITY: From d35da08288ed1f5395073a016b0597be016b85cf Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 19:17:42 +0900 Subject: [PATCH 068/112] (codex) review --- src/optimizer/query_graph.h | 2 +- src/query/execute_schema.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/optimizer/query_graph.h b/src/optimizer/query_graph.h index 920fe65048b..3dace5db0a3 100644 --- a/src/optimizer/query_graph.h +++ b/src/optimizer/query_graph.h @@ -201,7 +201,7 @@ struct qo_index #define QO_GET_CLASS_STATS(entryp) \ ((entryp)->self_allocated ? (entryp)->stats : (entryp)->smclass->stats) #define QO_GET_HIST_STATS(entryp) \ - ((entryp)->self_allocated ? NULL : ((entryp)->smclass->histogram)) + ((entryp)->smclass->histogram) /* * This structure is the head of a list of QO_INDEX_ENTRY index structures. * The purpose for this node is to have a place to store cumulative diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 9fddba970cf..a26767d58dd 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -3973,6 +3973,10 @@ update_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, SM_ATTRIBUTE *att; SM_CLASS *class_ = NULL; error = au_fetch_class (obj, &class_, AU_FETCH_READ, AU_SELECT); + if (error != NO_ERROR) + { + return error; + } for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) { attname = (char *) att->header.name; From 4ce9cf227c0d593d7aa05b3c3dd9dd9aebc52ff7 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 19:31:18 +0900 Subject: [PATCH 069/112] (cursor bugbot) bugfix --- src/histogram/histogram_builder.cpp | 8 ++++++++ src/histogram/histogram_cl.cpp | 19 ++++++++++++++++--- src/histogram/histogram_cl.hpp | 2 +- src/histogram/histogram_reader.cpp | 10 ++++++++++ src/object/object_accessor.c | 4 ++-- 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/histogram/histogram_builder.cpp b/src/histogram/histogram_builder.cpp index 68d97fac1b3..2f2b5667510 100644 --- a/src/histogram/histogram_builder.cpp +++ b/src/histogram/histogram_builder.cpp @@ -126,6 +126,7 @@ namespace hist } else { + db_private_free (thread_p, buffer); assert (false); return NULL; } @@ -142,6 +143,7 @@ namespace hist } else { + db_private_free (thread_p, buffer); assert (false); return NULL; } @@ -164,6 +166,7 @@ namespace hist } else { + db_private_free (thread_p, buffer); assert (false); return NULL; } @@ -183,6 +186,7 @@ namespace hist } else { + db_private_free (thread_p, buffer); assert (false); return NULL; } @@ -190,6 +194,7 @@ namespace hist break; default: /* never reach here */ + db_private_free (thread_p, buffer); assert (false); return NULL; } @@ -205,6 +210,7 @@ namespace hist str_blob_ptr = static_cast (db_private_alloc (thread_p, cur_str_off_)); if (str_blob_ptr == NULL) { + db_private_free (thread_p, buffer); return NULL; } char *cur_str_blob_ptr = str_blob_ptr; @@ -223,6 +229,8 @@ namespace hist } else { + db_private_free (thread_p, buffer); + db_private_free (thread_p, str_blob_ptr); assert (false); return NULL; } diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 788bec6ed4d..e17adf1cefe 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -73,6 +73,10 @@ analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_ &histogram_total_length); if (error != NO_ERROR) { + if (histogram_blob != NULL) + { + db_private_free (thread_p, histogram_blob); + } return error; } @@ -80,11 +84,18 @@ analyze_classes (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_ error = set_histogram (thread_p, tbl_name, attr_name, histogram_blob, histogram_total_length, classop); if (error != NO_ERROR) { + if (histogram_blob != NULL) + { + db_private_free (thread_p, histogram_blob); + } return error; } // ---- free histogram blob ---- - db_private_free (thread_p, histogram_blob); + if (histogram_blob != NULL) + { + db_private_free (thread_p, histogram_blob); + } return NO_ERROR; } @@ -270,7 +281,8 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na hist::histogram_key key; if (!histogram_extract_key (&value[1], key)) { - return error; + assert (false); + return ER_FAILED; } type = static_cast (value[1].domain.general_info.type); @@ -371,7 +383,7 @@ set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na end: db_value_clear (&histogram_value); - assert (error == NO_ERROR); // for debug + assert (error == NO_ERROR); return error; } @@ -751,6 +763,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc if (bucket_index < 0) { + *success = true; *selectivity = 0.0; return; } diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index 32da09c9790..278c933d509 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -82,7 +82,7 @@ namespace hist struct histogram_key { histogram_key_kind kind = histogram_key_kind::invalid; - std::int32_t i64 = 0; + std::int64_t i64 = 0; double dbl = 0.0; std::string str; std::uint64_t u64 = 0; diff --git a/src/histogram/histogram_reader.cpp b/src/histogram/histogram_reader.cpp index 59c8185c2c0..2647166648f 100644 --- a/src/histogram/histogram_reader.cpp +++ b/src/histogram/histogram_reader.cpp @@ -224,6 +224,11 @@ namespace hist template<> std::string HistogramReader::bucket_hi (std::int32_t i) const { + if (i < 0) + { + return std::string{""}; + } + const char *p = bucket_hi_value_ptr (static_cast (i)); std::uint32_t len32 = get_value (p); std::uint32_t off32 = get_value (p + 4); @@ -239,6 +244,11 @@ namespace hist template<> std::uint64_t HistogramReader::bucket_hi (std::int32_t i) const { + if (i < 0) + { + return std::numeric_limits::min(); + } + return static_cast (get_value (bucket_hi_value_ptr (static_cast (i)))); } diff --git a/src/object/object_accessor.c b/src/object/object_accessor.c index d2f4c677e4a..ac75103f1c5 100644 --- a/src/object/object_accessor.c +++ b/src/object/object_accessor.c @@ -3687,8 +3687,8 @@ obj_find_multi_attr (MOP op, int size, const char *attr_names[], const DB_VALUE DB_VALUE *unique_key = NULL; BTREE_SEARCH result; SCAN_OPERATION_TYPE op_type = S_SELECT; - OID *oids; - int oid_count; + OID *oids = NULL; + int oid_count = 0; DB_OTMPL *obj_tmpl = dbt_create_object_internal (op); if (obj_tmpl == NULL) From a5b053015f4d1359c8e9eed39f111ce2d0941373 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 19:51:51 +0900 Subject: [PATCH 070/112] (bugfix) cursor bugfix --- src/histogram/histogram_cl.cpp | 67 ++++++++++++++++++++++++++-------- src/object/schema_manager.c | 2 + 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index e17adf1cefe..c1f7b119fe7 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -119,7 +119,8 @@ get_null_frequency (THREAD_ENTRY *thread_p, const char *tbl_name, const char *at DB_QUERY_RESULT *query_result; DB_QUERY_ERROR query_error; - char query_buf[512+222+254]; // (query_length + table_name_length + attr_name_length) + /* (query_length + table_name_length + attr_name_length) */ + char query_buf[512+222+254]; if (!with_fullscan) { @@ -153,24 +154,30 @@ get_null_frequency (THREAD_ENTRY *thread_p, const char *tbl_name, const char *at } error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("null_frequency"), &null_frequency_value); + if (error != NO_ERROR) + { + error = ER_FAILED; + goto end; + } error = db_get_histogram (classop, attr_name, &histogram_obj); if (error != NO_ERROR) { - return error; + error = ER_FAILED; + goto end; } obj_tmpl = dbt_edit_object (histogram_obj); if (obj_tmpl == NULL) { - assert (er_errid () != NO_ERROR); - error = er_errid (); + error = ER_FAILED; goto end; } error = dbt_put (obj_tmpl, "null_frequency", &null_frequency_value); if (error != NO_ERROR) { + error = ER_FAILED; goto end; } @@ -188,10 +195,12 @@ get_null_frequency (THREAD_ENTRY *thread_p, const char *tbl_name, const char *at error = locator_flush_instance (edit_histogram_object); if (error != NO_ERROR) { + error = ER_FAILED; goto end; } end: + db_query_end (query_result); db_value_clear (&null_frequency_value); assert (error == NO_ERROR); // for debug return error; @@ -259,7 +268,8 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na { ASSERT_ERROR (); } - return error; + error = ER_FAILED; + goto error_end; } @@ -274,7 +284,8 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("approx_ndv"), &value[4]); if (error != NO_ERROR) { - return error; + error = ER_FAILED; + goto error_end; } /* ---- extract key from DB_VALUE ---- */ @@ -282,7 +293,8 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na if (!histogram_extract_key (&value[1], key)) { assert (false); - return ER_FAILED; + error = ER_FAILED; + goto error_end; } type = static_cast (value[1].domain.general_info.type); @@ -313,7 +325,8 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na { /* never reach here */ assert (false); - return ER_FAILED; + error = ER_FAILED; + goto error_end; } } db_value_clear (&value[0]); @@ -326,6 +339,7 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na build_histogram: + db_query_end (query_result); *histogram_blob = histogram_builder.build (thread_p, type, histogram_total_length); if (*histogram_blob == NULL) { @@ -333,6 +347,10 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na } return NO_ERROR; + +error_end: + db_query_end (query_result); + return error; } int @@ -753,6 +771,13 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc int bucket_index = -1; const double total_rows = histogram_reader.total_rows (); + if (total_rows <= 0.0) + { + *success = true; + *selectivity = 0.0; + return; + } + double bucket_rows = 0.0; /* caculate bucket_rows for column <= rhs or column < rhs */ @@ -1050,6 +1075,9 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) i++; } return NO_ERROR; + +error_end: + return error; } int stats_free_histogram_and_init (HIST_STATS *histogram) @@ -1058,20 +1086,27 @@ int stats_free_histogram_and_init (HIST_STATS *histogram) { return NO_ERROR; } - for (int i = 0; i < histogram->n_attrs; i++) + if (histogram->histogram != NULL) { - if (histogram->histogram[i] == nullptr) + for (int i = 0; i < histogram->n_attrs; i++) { - continue; + if (histogram->histogram[i] == nullptr) + { + continue; + } + db_value_clear (histogram->histogram[i]); + db_ws_free (histogram->histogram[i]); + histogram->histogram[i] = nullptr; } - db_value_clear (histogram->histogram[i]); - db_ws_free (histogram->histogram[i]); - histogram->histogram[i] = nullptr; } + if (histogram->n_attrs != 0) { - db_ws_free (histogram->null_frequency); - db_ws_free (histogram->histogram); + if (histogram->null_frequency != NULL) + { + db_ws_free (histogram->null_frequency); + histogram->null_frequency = nullptr; + } } db_ws_free (histogram); return NO_ERROR; diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 78ee64b890b..0554dd18e4a 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -4149,6 +4149,7 @@ sm_get_class_with_statistics (MOP classop) int err = stats_get_histogram (classop, &class_->histogram); if (err != NO_ERROR) { + stats_free_histogram_and_init (class_->histogram); return NULL; } } @@ -4159,6 +4160,7 @@ sm_get_class_with_statistics (MOP classop) int err = stats_get_histogram (classop, &class_->histogram); if (err != NO_ERROR) { + stats_free_histogram_and_init (class_->histogram); return NULL; } } From 62572315ce2ff8827634e2dc84ded3cd276fa48c Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 20:00:36 +0900 Subject: [PATCH 071/112] (codex) bugfix --- src/query/execute_schema.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index a26767d58dd..f4cb59a1402 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -4114,6 +4114,7 @@ do_update_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) if (obj == NULL) { assert (er_errid () != NO_ERROR); + AU_ENABLE (save); return er_errid (); } @@ -4123,6 +4124,7 @@ do_update_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) { assert (er_errid () != NO_ERROR); error = er_errid (); + AU_ENABLE (save); return error; } @@ -4155,6 +4157,7 @@ do_drop_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) if (obj == NULL) { assert (er_errid () != NO_ERROR); + AU_ENABLE (save); return er_errid (); } @@ -4164,6 +4167,7 @@ do_drop_histogram (PARSER_CONTEXT * parser, PT_NODE * statement) { assert (er_errid () != NO_ERROR); error = er_errid (); + AU_ENABLE (save); return error; } From c143145c97210d33c0de2cedbb0cb19ef9308334 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 20:12:13 +0900 Subject: [PATCH 072/112] (codex) bug --- src/histogram/histogram_cl.cpp | 41 ++++++++++++++++++++++++---------- src/query/execute_schema.c | 13 +++++++++++ 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index c1f7b119fe7..b500700dd7c 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -275,13 +275,27 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na do { - DB_VALUE value[5]; + DB_VALUE value[4]; hist::HistogramTypes hi{}; - error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("bid"), &value[0]); - error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("endpoint"), &value[1]); - error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("rows_in_bucket"), &value[2]); - error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("cumulative"), &value[3]); - error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("approx_ndv"), &value[4]); + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("endpoint"), &value[0]); + if (error != NO_ERROR) + { + error = ER_FAILED; + goto error_end; + } + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("rows_in_bucket"), &value[1]); + if (error != NO_ERROR) + { + error = ER_FAILED; + goto error_end; + } + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("cumulative"), &value[2]); + if (error != NO_ERROR) + { + error = ER_FAILED; + goto error_end; + } + error = db_query_get_tuple_value_by_name (query_result, const_cast < char *> ("approx_ndv"), &value[3]); if (error != NO_ERROR) { error = ER_FAILED; @@ -290,7 +304,7 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na /* ---- extract key from DB_VALUE ---- */ hist::histogram_key key; - if (!histogram_extract_key (&value[1], key)) + if (!histogram_extract_key (&value[0], key)) { assert (false); error = ER_FAILED; @@ -303,28 +317,32 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na { case hist::histogram_key_kind::i64: { - histogram_builder.add (static_cast (key.i64), db_get_bigint (&value[3]), db_get_bigint (&value[4])); + histogram_builder.add (static_cast (key.i64), db_get_bigint (&value[2]), db_get_bigint (&value[3])); break; } case hist::histogram_key_kind::dbl: { - histogram_builder.add (static_cast (key.dbl), db_get_bigint (&value[3]), db_get_bigint (&value[4])); + histogram_builder.add (static_cast (key.dbl), db_get_bigint (&value[2]), db_get_bigint (&value[3])); break; } case hist::histogram_key_kind::str: { - histogram_builder.add (key.str, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + histogram_builder.add (key.str, db_get_bigint (&value[2]), db_get_bigint (&value[3])); break; } case hist::histogram_key_kind::u64: { - histogram_builder.add (key.u64, db_get_bigint (&value[3]), db_get_bigint (&value[4])); + histogram_builder.add (key.u64, db_get_bigint (&value[2]), db_get_bigint (&value[3])); break; } default: { /* never reach here */ assert (false); + db_value_clear (&value[0]); + db_value_clear (&value[1]); + db_value_clear (&value[2]); + db_value_clear (&value[3]); error = ER_FAILED; goto error_end; } @@ -333,7 +351,6 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na db_value_clear (&value[1]); db_value_clear (&value[2]); db_value_clear (&value[3]); - db_value_clear (&value[4]); } while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS); diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index f4cb59a1402..9a2b2128f91 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -4045,7 +4045,20 @@ update_or_drop_histogram_helper (PARSER_CONTEXT * parser, DB_OBJECT * const obj, DB_DOMAIN *attr_domain; attribute = db_get_attribute (obj, attname); + if (attribute == NULL) + { + error = ER_OBJ_INVALID_ARGUMENTS; + assert (false); + return error; + } attr_domain = db_attribute_domain (attribute); + if (attr_domain == NULL) + { + error = ER_OBJ_INVALID_ARGUMENTS; + assert (false); + return error; + } + attr_type = TP_DOMAIN_TYPE (attr_domain); if (!is_histogrammable_type (attr_type)) From 836bfd829b9f96a3893ce17af3027bea67d3d72f Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 20:23:47 +0900 Subject: [PATCH 073/112] (codex) bugfix --- src/histogram/histogram_cl.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index b500700dd7c..edbb5e28d81 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -135,6 +135,7 @@ get_null_frequency (THREAD_ENTRY *thread_p, const char *tbl_name, const char *at if (error < 1) { + db_query_end (query_result); return error; } @@ -150,6 +151,7 @@ get_null_frequency (THREAD_ENTRY *thread_p, const char *tbl_name, const char *at { ASSERT_ERROR (); } + db_query_end (query_result); return error; } @@ -248,6 +250,7 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na if (error < 0) { + db_query_end (query_result); return error; } @@ -581,11 +584,11 @@ histogram_extract_key (const DB_VALUE *db_val, hist::histogram_key &key) static double numeric_domain_frac_i64_lt (std::int64_t lo, std::int64_t hi, std::int64_t v) { - if (v <= lo) + if (lo >= v) { return 0.0; } - if (v >= hi) + if (hi <= v) { return 1.0; } @@ -594,7 +597,7 @@ numeric_domain_frac_i64_lt (std::int64_t lo, std::int64_t hi, std::int64_t v) double numeric_domain_frac_u64_lt (std::uint64_t lo, std::uint64_t hi, std::uint64_t v) { - if (v >= hi) + if (hi <= v) { return 1.0; } @@ -609,7 +612,7 @@ double numeric_domain_frac_u64_lt (std::uint64_t lo, std::uint64_t hi, std::uint double numeric_domain_frac_dbl_lt (double lo, double hi, double v) { - if (v >= hi) + if (hi <= v) { return 1.0; } @@ -659,7 +662,7 @@ string_pos (const unsigned char *s, std::size_t len, std::size_t max_len = 16) static double string_domain_frac_lt (const std::string &lo, const std::string &hi, const std::string &v) { - if (hi >= v) + if (hi <= v) { return 1.0; } From 752043728b64e1133bc243e8f8226c11b9af3cc4 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 20:25:14 +0900 Subject: [PATCH 074/112] \ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (주석누락 제거) --- src/histogram/histogram_cl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index edbb5e28d81..de3a0e35501 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -395,6 +395,7 @@ set_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na goto end; } + /* SM_MAX_STRING_LENGTH = 1073741823 */ db_make_varbit (&histogram_value, 1073741823, histogram_blob, histogram_total_length * 8); error = dbt_put (obj_tmpl, "histogram_values", &histogram_value); if (error != NO_ERROR) From 96936fcc5d8d174a6d76a7d2dec6fd733e870f4f Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 20:59:40 +0900 Subject: [PATCH 075/112] (bugfix) adapt rand possion shifted --- src/storage/heap_file.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/storage/heap_file.c b/src/storage/heap_file.c index 18d1d06b356..9189216572a 100644 --- a/src/storage/heap_file.c +++ b/src/storage/heap_file.c @@ -7894,15 +7894,19 @@ static int random_poisson_weight (int weight) { // *INDENT-OFF* + static thread_local std::mt19937 rng { std::random_device{} () }; // *INDENT-ON* - if (weight <= 0) + if (weight < 1) { - return 0; + assert (false); + return 1; } - std::poisson_distribution < int >dist (weight); - return dist (rng); +/* shifted version of random_poisson_weight */ + const int lambda = weight - 1; // E[1 + Poisson(lambda)] = weight + std::poisson_distribution < int >dist (lambda); + return dist (rng) + 1; // always >= 1 } From 374e06ae1cc12f8774de37b7377846578e6a756e Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 21:09:57 +0900 Subject: [PATCH 076/112] (codex) bugifx --- src/histogram/histogram_cl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index de3a0e35501..df5acbe45eb 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -314,7 +314,7 @@ get_histogram (THREAD_ENTRY *thread_p, const char *tbl_name, const char *attr_na goto error_end; } - type = static_cast (value[1].domain.general_info.type); + type = static_cast (value[0].domain.general_info.type); switch (key.kind) { From eb465fc181ffb33882dfa0daa98e354b87ef00f0 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 18 Dec 2025 21:23:23 +0900 Subject: [PATCH 077/112] (codex)bugfix --- src/histogram/histogram_cl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index df5acbe45eb..ab2bef4f803 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -715,7 +715,7 @@ histogram_get_equal_selectivity (PT_NODE *lhs, PT_NODE *rhs, double *selectivity switch (key.kind) { case hist::histogram_key_kind::i64: - found = histogram_reader.find_bucket_and_check (key.i64, bucket_index); + found = histogram_reader.find_bucket_and_check (key.i64, bucket_index); break; case hist::histogram_key_kind::dbl: From 6eca82fa6b8479d1cf0db0f2645dce3ca915e18b Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 23 Dec 2025 16:02:52 +0900 Subject: [PATCH 078/112] =?UTF-8?q?(bugfix)=20=EC=8B=A4=EC=88=98=EB=A1=9C?= =?UTF-8?q?=20=EB=88=84=EB=9D=BD=EB=90=9C=20=EB=B6=80=EB=B6=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/query/execute_statement.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/query/execute_statement.c b/src/query/execute_statement.c index 190069d3355..7297a25b855 100644 --- a/src/query/execute_statement.c +++ b/src/query/execute_statement.c @@ -12078,7 +12078,7 @@ do_create_midxkey_for_constraint (DB_OTMPL * tmpl, SM_CLASS_CONSTRAINT * constra error = ER_FAILED; goto error_return; } - //midxkey.domain = tp_domain_cache (midxkey.domain); + midxkey.domain = tp_domain_cache (midxkey.domain); assert (midxkey.domain->type->id <= DB_TYPE_LAST); midxkey.min_max_val.position = -1; midxkey.min_max_val.type = MIN_COLUMN; From 297ba6bef63b775b3262b242fccbff6c07b11a11 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 23 Dec 2025 16:32:06 +0900 Subject: [PATCH 079/112] (cursor) bugfix --- src/histogram/histogram_cl.cpp | 2 +- src/query/execute_statement.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index ab2bef4f803..49d4d04e76d 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -506,7 +506,7 @@ histogram_extract_key (const DB_VALUE *db_val, hist::histogram_key &key) return false; } key.kind = hist::histogram_key_kind::str; - key.str.assign (str, length); + key.str.assign (str, static_cast ((length + 7) / 8)); return true; } diff --git a/src/query/execute_statement.c b/src/query/execute_statement.c index 7297a25b855..5806bc7e157 100644 --- a/src/query/execute_statement.c +++ b/src/query/execute_statement.c @@ -12002,13 +12002,13 @@ do_create_midxkey_for_constraint (DB_OTMPL * tmpl, SM_CLASS_CONSTRAINT * constra } attr_dom = tp_domain_copy ((*attr)->domain, false); - assert (attr_dom->type->id <= DB_TYPE_LAST); if (attr_dom == NULL) { error = ER_FAILED; goto error_return; } + assert (attr_dom->type->id <= DB_TYPE_LAST); if (asc_desc != NULL && asc_desc[attr_count] == 1) { attr_dom->is_desc = 1; From 85c2f2842208efab0520040dad4034ebe5124f16 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 24 Dec 2025 15:12:45 +0900 Subject: [PATCH 080/112] (naming fix) --- src/executables/csql_result.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/executables/csql_result.c b/src/executables/csql_result.c index cf5c01484a6..aeeb4b05759 100644 --- a/src/executables/csql_result.c +++ b/src/executables/csql_result.c @@ -108,8 +108,8 @@ static CSQL_CMD_STRING_TABLE csql_Cmd_string_table[] = { {CUBRID_STMT_ROLLBACK_WORK, "ROLLBACK"}, {CUBRID_STMT_GRANT, "GRANT"}, {CUBRID_STMT_REVOKE, "REVOKE"}, - {CUBRID_STMT_UPDATE_HISTOGRAM, "CREATE HISTOGRAM"}, - {CUBRID_STMT_DROP_HISTOGRAM, "DROP HISTOGRAM"}, + {CUBRID_STMT_UPDATE_HISTOGRAM, "ANALYZE UPDATE HISTOGRAM"}, + {CUBRID_STMT_DROP_HISTOGRAM, "ANALYZE DROP HISTOGRAM"}, {CUBRID_STMT_CREATE_USER, "CREATE USER"}, {CUBRID_STMT_DROP_USER, "DROP USER"}, {CUBRID_STMT_ALTER_USER, "ALTER USER"}, From 835d75ad69183ab0f2eb5832efcbee61e49d8d2f Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 31 Dec 2025 14:35:22 +0900 Subject: [PATCH 081/112] (bugfix) schema-modify bug fix --- src/query/execute_schema.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index 9a2b2128f91..f14077640bc 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -1675,13 +1675,17 @@ do_alter (PARSER_CONTEXT * parser, PT_NODE * alter) case PT_MODIFY_ATTR_MTHD: case PT_CHANGE_ATTR: { - const char *attr_name = crt_clause->info.alter.alter_clause.attr_mthd.attr_old_name->info.name.original; - if (attr_name != NULL) + if (crt_clause->info.alter.alter_clause.attr_mthd.attr_old_name != NULL) { - db_get_histogram (crt_clause->info.alter.entity_name->info.name.db_object, attr_name, &histogram_obj); - if (histogram_obj != NULL) + const char *attr_name = crt_clause->info.alter.alter_clause.attr_mthd.attr_old_name->info.name.original; + if (attr_name != NULL) { - db_drop (histogram_obj); + db_get_histogram (crt_clause->info.alter.entity_name->info.name.db_object, attr_name, + &histogram_obj); + if (histogram_obj != NULL) + { + db_drop (histogram_obj); + } } } break; From 9c28834b545f0d98e7bce80b2e213752f808f35a Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 31 Dec 2025 14:59:52 +0900 Subject: [PATCH 082/112] (bugfix) schema file rename bugfix --- src/query/execute_schema.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index f14077640bc..9990d8d389e 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -1693,13 +1693,17 @@ do_alter (PARSER_CONTEXT * parser, PT_NODE * alter) case PT_RENAME_ATTR_MTHD: case PT_RENAME_ENTITY: { - const char *attr_name = crt_clause->info.alter.alter_clause.rename.old_name->info.name.original; - if (attr_name != NULL) + if (alter->info.alter.alter_clause.rename.old_name != NULL) { - db_get_histogram (crt_clause->info.alter.entity_name->info.name.db_object, attr_name, &histogram_obj); - if (histogram_obj != NULL) + const char *attr_name = crt_clause->info.alter.alter_clause.rename.old_name->info.name.original; + if (attr_name != NULL) { - db_drop (histogram_obj); + db_get_histogram (crt_clause->info.alter.entity_name->info.name.db_object, attr_name, + &histogram_obj); + if (histogram_obj != NULL) + { + db_drop (histogram_obj); + } } } break; From 45a1da4292c51d4757c9e5c8a66a196743608265 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 31 Dec 2025 18:12:36 +0900 Subject: [PATCH 083/112] =?UTF-8?q?(merge=20bug=20fix)=20merge=20=EC=97=90?= =?UTF-8?q?=EC=84=9C=20histogram=20=EC=82=AC=EC=9A=A9=EC=8B=9C=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=EB=82=98=EB=8A=94=20=EC=83=81=ED=99=A9=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/compat/db.h | 1 + src/compat/db_obj.c | 15 +++ src/object/object_accessor.c | 2 +- src/object/object_template.c | 200 +++++++++++++++++++++++++++++++++++ src/object/object_template.h | 1 + 5 files changed, 218 insertions(+), 1 deletion(-) diff --git a/src/compat/db.h b/src/compat/db.h index 5b0fa6eed4c..8d40a7598e5 100644 --- a/src/compat/db.h +++ b/src/compat/db.h @@ -253,6 +253,7 @@ extern DB_OBJECT *db_create_internal (DB_OBJECT * obj); extern DB_OBJECT *db_create_by_name_internal (const char *name); extern int db_put_internal (DB_OBJECT * obj, const char *name, DB_VALUE * value); extern DB_OTMPL *dbt_create_object_internal (DB_OBJECT * classobj); +extern DB_OTMPL *dbt_create_object_internal_for_read_only (DB_OBJECT * classobj); extern int dbt_put_internal (DB_OTMPL * def, const char *name, DB_VALUE * value); extern int db_dput_internal (DB_OBJECT * obj, DB_ATTDESC * attribute, DB_VALUE * value); extern int dbt_dput_internal (DB_OTMPL * def, DB_ATTDESC * attribute, DB_VALUE * value); diff --git a/src/compat/db_obj.c b/src/compat/db_obj.c index aeec1a4d546..4aab9e04361 100644 --- a/src/compat/db_obj.c +++ b/src/compat/db_obj.c @@ -512,6 +512,20 @@ dbt_create_object_internal (MOP classobj) return def; } +DB_OTMPL * +dbt_create_object_internal_for_read_only (MOP classobj) +{ + DB_OTMPL *def = NULL; + + CHECK_CONNECT_NULL (); + CHECK_1ARG_NULL (classobj); + CHECK_MODIFICATION_NULL (); + + def = obt_def_object_for_read_only (classobj); + + return def; +} + /* * dbt_edit_object() - This function creates an object template for an existing * object. The template is initially empty. The template is populated with @@ -1184,6 +1198,7 @@ db_find_multi_unique (MOP classmop, int size, char *attr_names[], DB_VALUE * val obj_find_multi_attr (classmop, size, (const char **) attr_names, (const DB_VALUE **) values, purpose == DB_FETCH_WRITE ? AU_FETCH_UPDATE : AU_FETCH_READ); + er_clear (); return retval; } diff --git a/src/object/object_accessor.c b/src/object/object_accessor.c index ac75103f1c5..cafe7ba46b7 100644 --- a/src/object/object_accessor.c +++ b/src/object/object_accessor.c @@ -3690,7 +3690,7 @@ obj_find_multi_attr (MOP op, int size, const char *attr_names[], const DB_VALUE OID *oids = NULL; int oid_count = 0; - DB_OTMPL *obj_tmpl = dbt_create_object_internal (op); + DB_OTMPL *obj_tmpl = dbt_create_object_internal_for_read_only (op); if (obj_tmpl == NULL) { error = ER_FAILED; diff --git a/src/object/object_template.c b/src/object/object_template.c index fc80dcb1aed..c4885e2311a 100644 --- a/src/object/object_template.c +++ b/src/object/object_template.c @@ -923,6 +923,184 @@ make_template (MOP object, MOP classobj) return template_ptr; } + +/* + * make_template - This initializes a new object template. + * return: new object template + * object(in): the object that the template is being created for + * classobj(in): the class of the object + * + */ + +static OBJ_TEMPLATE * +make_template_for_read_only (MOP object, MOP classobj) +{ + OBJ_TEMPLATE *template_ptr; + AU_FETCHMODE mode; + AU_TYPE auth; + SM_CLASS *class_, *base_class; + MOP base_classobj, base_object; + MOBJ obj; + OBJ_TEMPASSIGN **vec; + + base_classobj = NULL; + base_class = NULL; + base_object = NULL; + + /* fetch & lock the class with the appropriate options */ + mode = AU_FETCH_READ; + auth = AU_SELECT; + + if (au_fetch_class (classobj, &class_, mode, auth)) + { + return NULL; + } + + /* + * we only need to keep track of the base class if this is a + * virtual class, for proxies, the instances look like usual + */ + + if (class_->class_type == SM_VCLASS_CT /* a view, and... */ + && object != classobj /* we are not doing a meta class update */ ) + { + /* + * could use vid_is_updatable() if + * the instance was supplied but since this can be NULL for + * insert templates, use mq_is_updatable on the class object instead. + * NOTE: Don't call this yet, try to use mq_fetch_one_real_class() + * to perform the updatability test. + */ + if (!mq_is_updatable (classobj)) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_NOT_UPDATABLE_STMT, 0); + return NULL; + } + + + base_classobj = mq_fetch_one_real_class (classobj); + if (base_classobj == NULL) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IT_NOT_UPDATABLE_STMT, 0); + return NULL; + } + + if (au_fetch_class (base_classobj, &base_class, AU_FETCH_READ, auth)) + { + return NULL; + } + + /* get the associated base object (if this isn't a proxy) */ + if (object != NULL && !vid_is_base_instance (object)) + { + base_object = vid_get_referenced_mop (object); + } + } + + /* + * If this is an instance update, fetch & lock the instance. + * NOTE: It might be good to use AU_FETCH_WRITE and use locator_update_instance + * to set the dirty bit after the template has been successfully applied. + * + * If this is a virtual instance on a non-proxy, could be locking + * the associated instance as well. Is this already being done ? + */ + if (object != NULL && object != classobj) + { + if (au_fetch_instance (object, &obj, AU_FETCH_UPDATE, LC_FETCH_MVCC_VERSION, AU_UPDATE)) + { + return NULL; + } + + /* + * Could cache the object memory pointer this in the template as + * well but that would require that it be pinned for a long + * duration through code that we don't control. Dangerous. + */ + } + + template_ptr = (OBJ_TEMPLATE *) area_alloc (Template_area); + if (template_ptr != NULL) + { + template_ptr->object = object; + template_ptr->classobj = classobj; + + /* + * cache the class info directly in the template, will need + * to remember the transaction id and chn for validation + */ + template_ptr->class_ = class_; + + /* cache the base class if this is a virtual class template */ + template_ptr->base_classobj = base_classobj; + template_ptr->base_class = base_class; + template_ptr->base_object = base_object; + + template_ptr->tran_id = tm_Tran_index; + template_ptr->schema_id = sm_local_schema_version (); + template_ptr->assignments = NULL; + template_ptr->label = NULL; + template_ptr->traversal = 0; + template_ptr->write_lock = mode != AU_FETCH_READ; + template_ptr->traversed = 0; + template_ptr->is_old_template = 0; + template_ptr->is_class_update = (object == classobj); + template_ptr->check_uniques = obt_Check_uniques; + if (TM_TRAN_ISOLATION () >= TRAN_REPEATABLE_READ) + { + template_ptr->check_serializable_conflict = 1; + } + else + { + template_ptr->check_serializable_conflict = 0; + } + template_ptr->uniques_were_modified = 0; + template_ptr->function_key_modified = 0; + + template_ptr->shared_was_modified = 0; + template_ptr->discard_on_finish = 1; + template_ptr->fkeys_were_modified = 0; + template_ptr->force_check_not_null = 0; + template_ptr->force_flush = 0; + template_ptr->is_autoincrement_set = 0; + template_ptr->pruning_type = DB_NOT_PARTITIONED_CLASS; + /* + * Don't do this until we've initialized the other stuff; + * OTMPL_NASSIGNS relies on the "class" attribute of the template. + */ + + if (template_ptr->is_class_update) + { + template_ptr->nassigns = template_ptr->class_->class_attribute_count; + } + else + { + template_ptr->nassigns = (template_ptr->class_->att_count + template_ptr->class_->shared_count); + } + + vec = NULL; + if (template_ptr->nassigns) + { + int i; + + vec = (OBJ_TEMPASSIGN **) malloc (template_ptr->nassigns * sizeof (OBJ_TEMPASSIGN *)); + if (!vec) + { + return NULL; + } + for (i = 0; i < template_ptr->nassigns; i++) + { + vec[i] = NULL; + } + } + + template_ptr->assignments = vec; + } + + return template_ptr; +} + + /* * validate_template - This is used to validate a template before each operation * return: error code @@ -1424,6 +1602,28 @@ obt_def_object (MOP class_mop) return template_ptr; } +OBJ_TEMPLATE * +obt_def_object_for_read_only (MOP class_mop) +{ + OBJ_TEMPLATE *template_ptr = NULL; + int is_class = locator_is_class (class_mop, DB_FETCH_CLREAD_INSTWRITE); + + if (is_class < 0) + { + return NULL; + } + if (!is_class) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_NOT_A_CLASS, 0); + } + else + { + template_ptr = make_template_for_read_only (NULL, class_mop); + } + + return template_ptr; +} + /* * obt_edit_object - This is used to initialize an editing template * on an existing object. diff --git a/src/object/object_template.h b/src/object/object_template.h index 4927a54092a..f0b133e57cd 100644 --- a/src/object/object_template.h +++ b/src/object/object_template.h @@ -213,6 +213,7 @@ extern bool obt_Last_insert_id_generated; /* OBJECT TEMPLATE FUNCTIONS */ extern OBJ_TEMPLATE *obt_def_object (MOP class_); +extern OBJ_TEMPLATE *obt_def_object_for_read_only (MOP class_); extern OBJ_TEMPLATE *obt_edit_object (MOP object); extern int obt_quit (OBJ_TEMPLATE * template_ptr); From 5824034569a67041285cd31212e3f61b83c16b61 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 6 Jan 2026 13:21:10 +0900 Subject: [PATCH 084/112] =?UTF-8?q?(bugfix)=20sql=5Ftest=20bug=20finded=20?= =?UTF-8?q?fix=20-=20sql=20test=EC=A4=91=20sel=EC=9D=B4=20=EB=92=A4?= =?UTF-8?q?=EB=B0=94=EB=80=8C=EC=96=B4=20=EC=98=A4=EB=A5=98=EA=B0=80=20?= =?UTF-8?q?=EC=83=9D=EA=B8=B0=EB=8A=94=20=EC=BC=80=EC=9D=B4=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/optimizer/query_planner.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/optimizer/query_planner.c b/src/optimizer/query_planner.c index c2f05332dd1..65c71dcfb7a 100644 --- a/src/optimizer/query_planner.c +++ b/src/optimizer/query_planner.c @@ -9996,7 +9996,7 @@ qo_range_selectivity (QO_ENV * env, PT_NODE * pt_expr) || op_type == PT_BETWEEN_GT_LT || op_type == PT_BETWEEN_INF_LT || op_type == PT_BETWEEN_INF_LE || op_type == PT_BETWEEN_GE_INF || op_type == PT_BETWEEN_GT_INF) { - double selectivity_a = 0.0, selectivity_b = 0.0; + double selectivity_a = 0.0, selectivity_b = 0.0, selectivity_backup = selectivity; bool success1 = false; bool success2 = false; switch (op_type) @@ -10066,7 +10066,7 @@ qo_range_selectivity (QO_ENV * env, PT_NODE * pt_expr) } if (!(success1 && success2)) { - selectivity = DEFAULT_RANGE_SELECTIVITY; + selectivity = selectivity_backup; } } else if (op_type == PT_BETWEEN_EQ_NA) From 0ed4166dcb4fb4d75f7614c712e4208ee3f7be2e Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 6 Jan 2026 13:32:20 +0900 Subject: [PATCH 085/112] (bugfix) build_error --- src/optimizer/query_planner.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/optimizer/query_planner.c b/src/optimizer/query_planner.c index 65c71dcfb7a..21b3c1f7cac 100644 --- a/src/optimizer/query_planner.c +++ b/src/optimizer/query_planner.c @@ -9931,7 +9931,8 @@ qo_range_selectivity (QO_ENV * env, PT_NODE * pt_expr) { PT_NODE *lhs, *arg1, *arg2; PRED_CLASS pc1, pc2; - double total_selectivity, selectivity; + double total_selectivity = DEFAULT_RANGE_SELECTIVITY; + double selectivity = DEFAULT_RANGE_SELECTIVITY; int lhs_icard = 0, rhs_icard = 0, icard = 0; PT_NODE *range_node; PT_OP_TYPE op_type; From f0b47f78a41ef62ce986ac687361f1dce9c3e65a Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 7 Jan 2026 17:45:32 +0900 Subject: [PATCH 086/112] =?UTF-8?q?(bugfix)=20=EC=9E=98=EB=AA=BB=20?= =?UTF-8?q?=EA=B3=A0=EC=B9=9C=20=EB=9D=BC=EC=9D=B8=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/optimizer/query_planner.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/optimizer/query_planner.c b/src/optimizer/query_planner.c index 21b3c1f7cac..41a4b5957ef 100644 --- a/src/optimizer/query_planner.c +++ b/src/optimizer/query_planner.c @@ -9931,8 +9931,8 @@ qo_range_selectivity (QO_ENV * env, PT_NODE * pt_expr) { PT_NODE *lhs, *arg1, *arg2; PRED_CLASS pc1, pc2; - double total_selectivity = DEFAULT_RANGE_SELECTIVITY; - double selectivity = DEFAULT_RANGE_SELECTIVITY; + double total_selectivity; + double selectivity = DEFAULT_BETWEEN_SELECTIVITY; int lhs_icard = 0, rhs_icard = 0, icard = 0; PT_NODE *range_node; PT_OP_TYPE op_type; From 319987b3260379c6b5d6f8f32ad8e7848d3cf796 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 7 Jan 2026 20:00:17 +0900 Subject: [PATCH 087/112] (bugfix) --- src/optimizer/query_planner.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/optimizer/query_planner.c b/src/optimizer/query_planner.c index 41a4b5957ef..4980918ec18 100644 --- a/src/optimizer/query_planner.c +++ b/src/optimizer/query_planner.c @@ -10067,7 +10067,15 @@ qo_range_selectivity (QO_ENV * env, PT_NODE * pt_expr) } if (!(success1 && success2)) { - selectivity = selectivity_backup; + if (op_type == PT_BETWEEN_INF_LT || op_type == PT_BETWEEN_INF_LE || op_type == PT_BETWEEN_GE_INF + || op_type == PT_BETWEEN_GT_INF) + { + selectivity = DEFAULT_COMP_SELECTIVITY; + } + else + { + selectivity = selectivity_backup; + } } } else if (op_type == PT_BETWEEN_EQ_NA) @@ -10104,12 +10112,7 @@ qo_range_selectivity (QO_ENV * env, PT_NODE * pt_expr) } } } - else - { - /* PT_BETWEEN_INF_LE, PT_BETWEEN_INF_LT, PT_BETWEEN_GE_INF, and PT_BETWEEN_GT_INF have only one argument */ - selectivity = DEFAULT_COMP_SELECTIVITY; - } selectivity = MAX (selectivity, 0.0); selectivity = MIN (selectivity, 1.0); From 37d0a3b38216da2f2cafa83273530039dfaabafb Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 20 Jan 2026 16:28:51 +0900 Subject: [PATCH 088/112] (bugfix) core super bug fix --- src/histogram/histogram_cl.cpp | 68 +++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 49d4d04e76d..11bfaeda211 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -1042,12 +1042,22 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) (*histogram)->histogram = (DB_VALUE **) db_ws_alloc (sizeof (DB_VALUE *) * class_->att_count); if ((*histogram)->histogram == NULL) { + db_ws_free (*histogram); + *histogram = NULL; return ER_OUT_OF_VIRTUAL_MEMORY; } + /* Initialize array to NULL */ + for (int j = 0; j < class_->att_count; j++) + { + (*histogram)->histogram[j] = NULL; + } (*histogram)->null_frequency = (double *) db_ws_alloc (sizeof (double) * class_->att_count); if ((*histogram)->null_frequency == NULL) { + db_ws_free ((*histogram)->histogram); + db_ws_free (*histogram); + *histogram = NULL; return ER_OUT_OF_VIRTUAL_MEMORY; } @@ -1061,27 +1071,35 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) error = db_get_histogram (classop, attname, &histogram_obj); if (error != NO_ERROR) { - return error; + goto error_end; } if (histogram_obj == NULL) { - (*histogram)->histogram[i] = nullptr; + (*histogram)->histogram[i] = NULL; (*histogram)->null_frequency[i] = 0.0; i++; continue; } histogram_value = (DB_VALUE *) db_ws_alloc (sizeof (DB_VALUE)); + if (histogram_value == NULL) + { + error = ER_OUT_OF_VIRTUAL_MEMORY; + goto error_end; + } error = db_get (histogram_obj, "histogram_values", histogram_value); if (error != NO_ERROR) { - return error; + db_ws_free (histogram_value); + goto error_end; } error = db_get (histogram_obj, "null_frequency", &null_frequency_value); if (error != NO_ERROR) { - return error; + db_value_clear (histogram_value); + db_ws_free (histogram_value); + goto error_end; } (*histogram)->histogram[i] = histogram_value; /* should clear histogram_value */ @@ -1098,6 +1116,31 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) return NO_ERROR; error_end: + /* Free all allocated memory */ + if (*histogram != NULL) + { + if ((*histogram)->histogram != NULL) + { + for (int j = 0; j < (*histogram)->n_attrs; j++) + { + if ((*histogram)->histogram[j] != NULL) + { + db_value_clear ((*histogram)->histogram[j]); + db_ws_free ((*histogram)->histogram[j]); + (*histogram)->histogram[j] = NULL; + } + } + db_ws_free ((*histogram)->histogram); + (*histogram)->histogram = NULL; + } + if ((*histogram)->null_frequency != NULL) + { + db_ws_free ((*histogram)->null_frequency); + (*histogram)->null_frequency = NULL; + } + db_ws_free (*histogram); + *histogram = NULL; + } return error; } @@ -1107,27 +1150,26 @@ int stats_free_histogram_and_init (HIST_STATS *histogram) { return NO_ERROR; } - if (histogram->histogram != NULL) + if (histogram->histogram != NULL && histogram->n_attrs > 0) { for (int i = 0; i < histogram->n_attrs; i++) { - if (histogram->histogram[i] == nullptr) + if (histogram->histogram[i] == NULL) { continue; } db_value_clear (histogram->histogram[i]); db_ws_free (histogram->histogram[i]); - histogram->histogram[i] = nullptr; + histogram->histogram[i] = NULL; } + db_ws_free (histogram->histogram); + histogram->histogram = NULL; } - if (histogram->n_attrs != 0) + if (histogram->null_frequency != NULL) { - if (histogram->null_frequency != NULL) - { - db_ws_free (histogram->null_frequency); - histogram->null_frequency = nullptr; - } + db_ws_free (histogram->null_frequency); + histogram->null_frequency = NULL; } db_ws_free (histogram); return NO_ERROR; From 69f43f1affef913fa59b2a2ab7425e5911ba6a29 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 20 Jan 2026 17:55:35 +0900 Subject: [PATCH 089/112] (bugfix) no core --- src/histogram/histogram_cl.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 11bfaeda211..c166fdd87a5 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -1069,10 +1069,6 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) DB_VALUE *histogram_value = NULL; DB_VALUE null_frequency_value; error = db_get_histogram (classop, attname, &histogram_obj); - if (error != NO_ERROR) - { - goto error_end; - } if (histogram_obj == NULL) { From 1847ff35c0e38d0a2b5f35752dcd4ec1a0b20dc9 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 21 Jan 2026 17:58:51 +0900 Subject: [PATCH 090/112] =?UTF-8?q?(core=20bug=20final=20fix)=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index c166fdd87a5..6d1a436e695 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -1028,6 +1028,7 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) } *histogram = (HIST_STATS *) db_ws_alloc (sizeof (HIST_STATS)); + memset (*histogram, 0, sizeof (HIST_STATS)); if (*histogram == NULL) { return ER_OUT_OF_VIRTUAL_MEMORY; @@ -1035,10 +1036,11 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) (*histogram)->n_attrs = class_->att_count; if (class_->att_count == 0) { - (*histogram)->histogram = nullptr; - (*histogram)->null_frequency = nullptr; + (*histogram)->histogram = NULL; + (*histogram)->null_frequency = NULL; return NO_ERROR; } + (*histogram)->histogram = (DB_VALUE **) db_ws_alloc (sizeof (DB_VALUE *) * class_->att_count); if ((*histogram)->histogram == NULL) { @@ -1046,11 +1048,6 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) *histogram = NULL; return ER_OUT_OF_VIRTUAL_MEMORY; } - /* Initialize array to NULL */ - for (int j = 0; j < class_->att_count; j++) - { - (*histogram)->histogram[j] = NULL; - } (*histogram)->null_frequency = (double *) db_ws_alloc (sizeof (double) * class_->att_count); if ((*histogram)->null_frequency == NULL) @@ -1061,7 +1058,6 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) return ER_OUT_OF_VIRTUAL_MEMORY; } - int i = 0; for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) { @@ -1070,10 +1066,16 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) DB_VALUE null_frequency_value; error = db_get_histogram (classop, attname, &histogram_obj); + (*histogram)->histogram[i] = NULL; + (*histogram)->null_frequency[i] = 0.0; + + if (error != NO_ERROR) + { + goto error_end; + } + if (histogram_obj == NULL) { - (*histogram)->histogram[i] = NULL; - (*histogram)->null_frequency[i] = 0.0; i++; continue; } @@ -1117,7 +1119,7 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) { if ((*histogram)->histogram != NULL) { - for (int j = 0; j < (*histogram)->n_attrs; j++) + for (int j = 0; j < i; j++) { if ((*histogram)->histogram[j] != NULL) { From 6d8ebaac2662a32871cf0994ee055ed8a811abb7 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 21 Jan 2026 18:50:27 +0900 Subject: [PATCH 091/112] =?UTF-8?q?(core=20bugfix)=20=EC=BD=94=EC=96=B4?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=ED=94=BD=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 6d1a436e695..4e91fcd8f96 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -1158,17 +1158,15 @@ int stats_free_histogram_and_init (HIST_STATS *histogram) } db_value_clear (histogram->histogram[i]); db_ws_free (histogram->histogram[i]); - histogram->histogram[i] = NULL; } db_ws_free (histogram->histogram); - histogram->histogram = NULL; } if (histogram->null_frequency != NULL) { db_ws_free (histogram->null_frequency); - histogram->null_frequency = NULL; } + db_ws_free (histogram); return NO_ERROR; } From 538a3d53b0545cd8cb3b909705ecda8123ef1ede Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 21 Jan 2026 20:42:38 +0900 Subject: [PATCH 092/112] =?UTF-8?q?(=E3=85=A0=E3=85=A0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/schema_class_truncator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/object/schema_class_truncator.cpp b/src/object/schema_class_truncator.cpp index a1a977177f3..0e490e0c94c 100644 --- a/src/object/schema_class_truncator.cpp +++ b/src/object/schema_class_truncator.cpp @@ -528,7 +528,7 @@ namespace cubschema STATEMENT_ID stmt_id; DB_VALUE value; char select_query[DB_MAX_IDENTIFIER_LENGTH + 256] = { 0 }; - constexpr int CNT_CATCLS_OBJECTS = 6; + constexpr int CNT_CATCLS_OBJECTS = 8; DB_BIGINT cnt_refers = CNT_CATCLS_OBJECTS + 1; int au_save; From 37ab4c99bbca75a13d58f54bb7af35b660419da8 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 23 Jan 2026 15:35:07 +0900 Subject: [PATCH 093/112] =?UTF-8?q?(refactor)=20=EA=B3=A0=EC=A0=95=20?= =?UTF-8?q?=EC=8B=9C=EB=93=9C=EA=B0=92=20=EA=B3=A0=EC=A0=95/=20=EA=B8=80?= =?UTF-8?q?=EB=A1=9C=EB=B2=8C=20=EB=B3=80=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/schema_class_truncator.cpp | 17 +--------- src/object/schema_system_catalog_constants.h | 33 ++++++++++++++++++++ src/storage/heap_file.c | 3 +- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/object/schema_class_truncator.cpp b/src/object/schema_class_truncator.cpp index 0e490e0c94c..f94e3cb09f3 100644 --- a/src/object/schema_class_truncator.cpp +++ b/src/object/schema_class_truncator.cpp @@ -24,6 +24,7 @@ #include "dbtype_function.h" #include "execute_statement.h" #include "network_interface_cl.h" +#include "schema_system_catalog_constants.h" #include @@ -528,7 +529,6 @@ namespace cubschema STATEMENT_ID stmt_id; DB_VALUE value; char select_query[DB_MAX_IDENTIFIER_LENGTH + 256] = { 0 }; - constexpr int CNT_CATCLS_OBJECTS = 8; DB_BIGINT cnt_refers = CNT_CATCLS_OBJECTS + 1; int au_save; @@ -538,21 +538,6 @@ namespace cubschema return ER_FAILED; } - /* - * !!CAUTION!! - * If [data_type] is DB_TYPE_OBJECT and [class_of] is NULL, it is a general object domain, but we have to check only user classes. - * To do this, we use an walkaround in which we count the number of general object domains in existing system catalogs - * and if the SELECT result is over this, we asuume that there are some general object domain in some user class. - * - * The number is now 6 and hard-coded, so we MUST consider it when add or remove a general object domain in a system class. - * If it is changed, we MUST also change the value of CNT_CATCLS_OBJECTS. - * - * We add a QA test case to confirm there are only 6 general object domains in system classes, which will help notice this constraint - * and this test case also has to be changed along if CNT_CATCLS_OBJECTS is changed. - * - * See CBRD-23983 and CBRD-25697 for the details. - */ - AU_DISABLE (au_save); (void) snprintf (select_query, sizeof (select_query), diff --git a/src/object/schema_system_catalog_constants.h b/src/object/schema_system_catalog_constants.h index 602620d8e8e..252cdadfc2f 100644 --- a/src/object/schema_system_catalog_constants.h +++ b/src/object/schema_system_catalog_constants.h @@ -97,4 +97,37 @@ #define SP_ATTR_TARGET_METHOD_LEN (4096) +/* + * !! CAUTION !! + * + * If [data_type] is DB_TYPE_OBJECT and [class_of] is NULL, this represents a + * general object domain. However, for correctness we must consider only + * general object domains that belong to user-defined classes. + * + * This distinction is especially important for TRUNCATE processing, where + * domain validation must ignore system-class object domains and detect only + * user-class dependencies. + * + * Since there is no direct way to distinguish system-class object domains + * from user-class ones at this point, we use a workaround: we count the + * number of general object domains that are known to exist in system catalogs, + * and if the SELECT result exceeds this number, we assume that at least one + * general object domain exists in a user class. + * + * The number of general object domains in system classes is currently 6 and + * is hard-coded. Therefore, when a general object domain is added to or + * removed from any system class, this value MUST be reviewed. + * + * If the number changes, CNT_CATCLS_OBJECTS MUST be updated accordingly. + * + * A QA test case has been added to verify that system classes contain exactly + * 6 general object domains. This test is intended to catch violations of this + * assumption early. If CNT_CATCLS_OBJECTS is modified, the corresponding QA + * test MUST also be updated. + * + * See CBRD-23983 and CBRD-25697 for details. + */ + +#define CNT_CATCLS_OBJECTS (8) /* number of general object domains in system classes */ + #endif /* _SCHEMA_SYSTEM_CATALOG_CONSTANTS_H_ */ diff --git a/src/storage/heap_file.c b/src/storage/heap_file.c index 2e92e029e05..8487d265124 100644 --- a/src/storage/heap_file.c +++ b/src/storage/heap_file.c @@ -7894,8 +7894,7 @@ static int random_poisson_weight (int weight) { // *INDENT-OFF* - - static thread_local std::mt19937 rng { std::random_device{} () }; + static thread_local std::mt19937 rng { 123456789u }; // fixed seed // *INDENT-ON* if (weight < 1) { From be28dcb081707d07863996615d2267c34c000097 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Fri, 23 Jan 2026 17:47:52 +0900 Subject: [PATCH 094/112] (core bug) final fix --- src/histogram/histogram_cl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 4e91fcd8f96..2ccb5591e19 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -1028,7 +1028,6 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) } *histogram = (HIST_STATS *) db_ws_alloc (sizeof (HIST_STATS)); - memset (*histogram, 0, sizeof (HIST_STATS)); if (*histogram == NULL) { return ER_OUT_OF_VIRTUAL_MEMORY; @@ -1040,6 +1039,7 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) (*histogram)->null_frequency = NULL; return NO_ERROR; } + memset (*histogram, 0, sizeof (HIST_STATS)); (*histogram)->histogram = (DB_VALUE **) db_ws_alloc (sizeof (DB_VALUE *) * class_->att_count); if ((*histogram)->histogram == NULL) @@ -1048,6 +1048,7 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) *histogram = NULL; return ER_OUT_OF_VIRTUAL_MEMORY; } + memset ((*histogram)->histogram, 0, sizeof (DB_VALUE *) * class_->att_count); (*histogram)->null_frequency = (double *) db_ws_alloc (sizeof (double) * class_->att_count); if ((*histogram)->null_frequency == NULL) @@ -1057,6 +1058,7 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) *histogram = NULL; return ER_OUT_OF_VIRTUAL_MEMORY; } + memset ((*histogram)->null_frequency, 0, sizeof (double) * class_->att_count); int i = 0; for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) From ae0a9732dba047561757090aab802ca18a729106 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 3 Feb 2026 07:42:56 +0900 Subject: [PATCH 095/112] (Refactor) --- src/histogram/histogram_cl.cpp | 6 +++--- src/object/class_object.h | 10 ---------- src/object/object_accessor.c | 1 + 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 2ccb5591e19..b587dec8e3b 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -805,7 +805,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc switch (key.kind) { case hist::histogram_key_kind::i64: - bucket_index = histogram_reader.find_bucket (key.i64); + bucket_index = histogram_reader.find_bucket (key.i64); if (bucket_index < 0) { @@ -816,7 +816,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc if (histogram_reader.bucket_approx_ndv (bucket_index) == 1) { - if (histogram_reader.check_value_included (bucket_index, key.i64)) + if (histogram_reader.check_value_included (bucket_index, key.i64)) { if (is_ge == include_equal) { @@ -835,7 +835,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc else { /* linear interpolation */ - const double frac = numeric_domain_frac_i64_lt (histogram_reader.bucket_hi (bucket_index - 1), + const double frac = numeric_domain_frac_i64_lt (histogram_reader.bucket_hi (bucket_index - 1), histogram_reader.bucket_hi (bucket_index), key.i64); bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1) + histogram_reader.bucket_rows ( bucket_index) * frac; diff --git a/src/object/class_object.h b/src/object/class_object.h index 4c376749c4c..28cf59f1449 100644 --- a/src/object/class_object.h +++ b/src/object/class_object.h @@ -581,14 +581,6 @@ struct sm_class_constraint #define GET_OPTION_DEDUPLICATE(opt) \ (((opt) >> OPTION_DEDUPLICATE_SHIFT) & OPTION_DEDUPLICATE_MASK) -/* histogram */ -typedef struct sm_class_histogram SM_CLASS_HISTOGRAM; - -struct sm_class_histogram -{ - struct sm_class_histogram *next; - DB_OBJECT *histogram_object; -}; /* * Holds information about a method argument. This will be used @@ -997,8 +989,6 @@ extern int classobj_put_index (DB_SEQ ** properties, SM_CLASS_CONSTRAINT * con, extern int classobj_find_prop_constraint (DB_SEQ * properties, const char *prop_name, const char *cnstr_name, DB_VALUE * cnstr_val); -extern int classobj_put_histogram (DB_OBJLIST * histograms, SM_CLASS_HISTOGRAM * histogram); - #if defined (ENABLE_RENAME_CONSTRAINT) extern int classobj_rename_constraint (DB_SEQ * properties, const char *prop_name, const char *old_name, const char *new_name); diff --git a/src/object/object_accessor.c b/src/object/object_accessor.c index cafe7ba46b7..a8500f3189b 100644 --- a/src/object/object_accessor.c +++ b/src/object/object_accessor.c @@ -3794,6 +3794,7 @@ obj_find_multi_attr (MOP op, int size, const char *attr_names[], const DB_VALUE else if (result == BTREE_KEY_FOUND) { obj = ws_mop (oids, NULL); + free (oids); } end_find: From c2fc08a974640fbf30a76c84d0478d6a1131d28f Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 3 Feb 2026 10:46:51 +0900 Subject: [PATCH 096/112] =?UTF-8?q?(mcv)=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_reader.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/histogram/histogram_reader.hpp b/src/histogram/histogram_reader.hpp index 79c73a60450..a4952dfb84a 100644 --- a/src/histogram/histogram_reader.hpp +++ b/src/histogram/histogram_reader.hpp @@ -155,10 +155,13 @@ namespace hist return false; } - if (!this->check_value_included (bucket_index, value)) + while (!this->check_value_included (bucket_index, value)) { - bucket_index = -1; - return false; + bucket_index += 1; + if (bucket_index == static_cast (nb_ - 1)) + { + return true; + } } return true; From ad13404f1f8b35f113dc703185fa3401a9e9c646 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 3 Feb 2026 11:02:51 +0900 Subject: [PATCH 097/112] (memset bugfix) --- src/histogram/histogram_cl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index b587dec8e3b..c18ebad4e16 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -1032,6 +1032,7 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) { return ER_OUT_OF_VIRTUAL_MEMORY; } + memset (*histogram, 0, sizeof (HIST_STATS)); (*histogram)->n_attrs = class_->att_count; if (class_->att_count == 0) { @@ -1039,7 +1040,6 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) (*histogram)->null_frequency = NULL; return NO_ERROR; } - memset (*histogram, 0, sizeof (HIST_STATS)); (*histogram)->histogram = (DB_VALUE **) db_ws_alloc (sizeof (DB_VALUE *) * class_->att_count); if ((*histogram)->histogram == NULL) From f95bb08ff3dcb3e4ceb3901fee7587586424c0f6 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 3 Feb 2026 13:55:04 +0900 Subject: [PATCH 098/112] (no core anymore) --- src/histogram/histogram_cl.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index c18ebad4e16..e867cba3842 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -1020,6 +1020,7 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) DB_OBJECT *histogram_obj = NULL; SM_ATTRIBUTE *att; SM_CLASS *class_ = NULL; + int attr_count = 0; error = au_fetch_class (classop, &class_, AU_FETCH_READ, AU_SELECT); if (error != NO_ERROR) @@ -1027,30 +1028,32 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) return error; } + attr_count = class_->att_count; *histogram = (HIST_STATS *) db_ws_alloc (sizeof (HIST_STATS)); if (*histogram == NULL) { return ER_OUT_OF_VIRTUAL_MEMORY; } memset (*histogram, 0, sizeof (HIST_STATS)); - (*histogram)->n_attrs = class_->att_count; - if (class_->att_count == 0) + + (*histogram)->n_attrs = attr_count; + if (attr_count == 0) { (*histogram)->histogram = NULL; (*histogram)->null_frequency = NULL; return NO_ERROR; } - (*histogram)->histogram = (DB_VALUE **) db_ws_alloc (sizeof (DB_VALUE *) * class_->att_count); + (*histogram)->histogram = (DB_VALUE **) db_ws_alloc (sizeof (DB_VALUE *) * attr_count); if ((*histogram)->histogram == NULL) { db_ws_free (*histogram); *histogram = NULL; return ER_OUT_OF_VIRTUAL_MEMORY; } - memset ((*histogram)->histogram, 0, sizeof (DB_VALUE *) * class_->att_count); + memset ((*histogram)->histogram, 0, sizeof (DB_VALUE *) * attr_count); - (*histogram)->null_frequency = (double *) db_ws_alloc (sizeof (double) * class_->att_count); + (*histogram)->null_frequency = (double *) db_ws_alloc (sizeof (double) * attr_count); if ((*histogram)->null_frequency == NULL) { db_ws_free ((*histogram)->histogram); @@ -1058,7 +1061,7 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) *histogram = NULL; return ER_OUT_OF_VIRTUAL_MEMORY; } - memset ((*histogram)->null_frequency, 0, sizeof (double) * class_->att_count); + memset ((*histogram)->null_frequency, 0, sizeof (double) * attr_count); int i = 0; for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) From a4ee36f7b24f75a3c59ee1364763a4d933d4dbba Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 5 Feb 2026 14:38:18 +0900 Subject: [PATCH 099/112] (merge conflict fix) --- src/parser/csql_grammar.y | 47 +++++++++++++++------------------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/src/parser/csql_grammar.y b/src/parser/csql_grammar.y index 43c33e6b508..42964bff5ff 100644 --- a/src/parser/csql_grammar.y +++ b/src/parser/csql_grammar.y @@ -1918,14 +1918,11 @@ stmt_ | rename_stmt { $$ = $1; } | update_statistics_stmt - { DBG_TRACE_GRAMMAR(stmt_, | update_statstics_stmt); - $$ = $1; } + { $$ = $1; } | update_histogram_stmt - { DBG_TRACE_GRAMMAR(stmt_, | update_histogram_stmt); - $$ = $1; } + { $$ = $1; } | drop_histogram_stmt - { DBG_TRACE_GRAMMAR(stmt_, | drop_histogram_stmt); - $$ = $1; } + { $$ = $1; } | drop_stmt { $$ = $1; } | do_stmt @@ -4694,28 +4691,20 @@ index_column_name_list histogram_column_list : /* empty */ - {{ DBG_TRACE_GRAMMAR(histogram_column_list, : ); - $$ = NULL; - DBG_PRINT}} + {{ $$ = NULL; }} | histogram_column_list ',' histogram_column - {{ DBG_TRACE_GRAMMAR(histogram_column_list, | histogram_column_list ',' histogram_column); - $$ = parser_make_link ($1, $3); - PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - DBG_PRINT}} + {{ $$ = parser_make_link ($1, $3); + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos)}} | histogram_column - {{ DBG_TRACE_GRAMMAR(histogram_column_list, | histogram_column); - $$ = $1; - PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - DBG_PRINT}} + {{ $$ = $1; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) }} ; histogram_column : identifier - {{ DBG_TRACE_GRAMMAR(histogram_column, | name); - $$ = $1; - PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - DBG_PRINT}} + {{ $$ = $1; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) }} ; update_statistics_stmt @@ -4759,7 +4748,7 @@ update_statistics_stmt update_histogram_stmt : ANALYZE TABLE only_class_name UPDATE HISTOGRAM ON_ histogram_column_list WITH unsigned_integer BUCKETS opt_with_fullscan - {{ DBG_TRACE_GRAMMAR(update_histogram_stmt, | ANALYZE TABLE only_class_name UPDATE HISTOGRAM ON histogram_column_list WITH unsigned_integer BUCKETS opt_with_fullscan ); + {{ PT_NODE *uhs = parser_new_node (this_parser, PT_UPDATE_HISTOGRAM); PT_NODE *target_t = parser_new_node (this_parser, PT_SPEC); if (uhs && target_t) @@ -4776,9 +4765,9 @@ update_histogram_stmt $$ = uhs; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - DBG_PRINT }} + }} | ANALYZE TABLE only_class_name UPDATE HISTOGRAM WITH unsigned_integer BUCKETS opt_with_fullscan - {{ DBG_TRACE_GRAMMAR(update_histogram_stmt, | ANALYZE TABLE only_class_name UPDATE HISTOGRAM WITH unsigned_integer BUCKETS opt_with_fullscan ); + {{ PT_NODE *uhs = parser_new_node (this_parser, PT_UPDATE_HISTOGRAM); PT_NODE *target_t = parser_new_node (this_parser, PT_SPEC); if (uhs && target_t) @@ -4794,11 +4783,11 @@ update_histogram_stmt $$ = uhs; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - DBG_PRINT }} + }} ; drop_histogram_stmt : ANALYZE TABLE only_class_name DROP HISTOGRAM ON_ histogram_column_list - {{ DBG_TRACE_GRAMMAR(drop_histogram_stmt, | ANALYZE TABLE only_class_name DROP HISTOGRAM ON histogram_column_list); + {{ PT_NODE *dhs = parser_new_node (this_parser, PT_DROP_HISTOGRAM); PT_NODE *target_t = parser_new_node (this_parser, PT_SPEC); if (dhs && target_t) @@ -4811,9 +4800,9 @@ drop_histogram_stmt } $$ = dhs; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - DBG_PRINT }} + }} | ANALYZE TABLE only_class_name DROP HISTOGRAM - {{ DBG_TRACE_GRAMMAR(drop_histogram_stmt, | ANALYZE TABLE only_class_name DROP HISTOGRAM ON histogram_column_list); + {{ PT_NODE *dhs = parser_new_node (this_parser, PT_DROP_HISTOGRAM); PT_NODE *target_t = parser_new_node (this_parser, PT_SPEC); if (dhs && target_t) @@ -4825,7 +4814,7 @@ drop_histogram_stmt } $$ = dhs; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) - DBG_PRINT }} + }} ; only_class_name_list From 4af81b12b6d57a6159adf5b20790ec1be5f52cd8 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 5 Feb 2026 15:35:26 +0900 Subject: [PATCH 100/112] (bugfix) --- src/object/schema_manager.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 0554dd18e4a..b47e14f5417 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -4157,10 +4157,12 @@ sm_get_class_with_statistics (MOP classop) { /* to do : implement timestamp check and update */ stats_free_histogram_and_init (class_->histogram); + class_->histogram = NULL; int err = stats_get_histogram (classop, &class_->histogram); if (err != NO_ERROR) { stats_free_histogram_and_init (class_->histogram); + class_->histogram = NULL; return NULL; } } From ffc36a71b455d9ae444690b5d36c6b5a80e41e7f Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 5 Feb 2026 17:56:17 +0900 Subject: [PATCH 101/112] (core bugfix) --- src/histogram/histogram_cl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index e867cba3842..4d65f0ff06e 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -1064,7 +1064,7 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) memset ((*histogram)->null_frequency, 0, sizeof (double) * attr_count); int i = 0; - for (att = class_->attributes; att != NULL; att = (SM_ATTRIBUTE *) att->header.next) + for (att = class_->attributes; att != NULL && class_->attributes != NULL; att = (SM_ATTRIBUTE *) att->header.next) { const char *attname = (char *) att->header.name; DB_VALUE *histogram_value = NULL; From 055e89f7626a80f2088d3a97da0dbce294f48e6e Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 10 Feb 2026 16:41:57 +0900 Subject: [PATCH 102/112] (bugfix) core bug fix --- src/object/class_object.c | 2 +- src/object/schema_manager.c | 19 ++++++++++++++----- src/storage/statistics.h | 8 ++++++++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/object/class_object.c b/src/object/class_object.c index 4de682d0ff4..9603f302ce2 100644 --- a/src/object/class_object.c +++ b/src/object/class_object.c @@ -6967,7 +6967,7 @@ classobj_free_class (SM_CLASS * class_) if (class_->histogram != NULL) { - stats_free_histogram_and_init (class_->histogram); + stats_free_histogram_and_init_and_set_null (class_->histogram); } if (class_->properties != NULL) diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index b47e14f5417..472c64a2a44 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -4145,12 +4145,21 @@ sm_get_class_with_statistics (MOP classop) /* get the histogram of the class */ if (class_->histogram == NULL) { - /* we don't need to flush the class here */ - int err = stats_get_histogram (classop, &class_->histogram); - if (err != NO_ERROR) + if (!OID_ISTEMP (WS_OID (classop))) { - stats_free_histogram_and_init (class_->histogram); - return NULL; + /* make sure the class is flushed before asking for statistics, this handles the case where an index + * has been added to the class but the catalog & statistics do not reflect this fact until the class + * is flushed. We might want to flush instances as well but that shouldn't affect the statistics ? */ + if (locator_flush_class (classop) != NO_ERROR) + { + return NULL; + } + int err = stats_get_histogram (classop, &class_->histogram); + if (err != NO_ERROR) + { + stats_free_histogram_and_init (class_->histogram); + return NULL; + } } } else diff --git a/src/storage/statistics.h b/src/storage/statistics.h index bb30795426b..b830b752c19 100644 --- a/src/storage/statistics.h +++ b/src/storage/statistics.h @@ -56,6 +56,14 @@ } \ while (0) +#define stats_free_histogram_and_init_and_set_null(histogram) \ + do \ + { \ + stats_free_histogram_and_init (histogram); \ + (histogram) = NULL; \ + } \ + while (0) + /* B+tree statistical information */ typedef struct btree_stats BTREE_STATS; struct btree_stats From f45a957b8453415f898ee92683aa1e952672cf92 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 10 Feb 2026 21:02:04 +0900 Subject: [PATCH 103/112] =?UTF-8?q?(core=20bug=EC=9D=98=20=EC=9B=90?= =?UTF-8?q?=EC=9D=B8=EC=9D=80)=20class=20object=EA=B0=80=20=EC=A4=91?= =?UTF-8?q?=EA=B0=84=EC=97=90=20=EC=82=AC=EB=9D=BC=EC=A7=80=EB=8A=94=20?= =?UTF-8?q?=EA=B2=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cubridmanager | 2 +- src/histogram/histogram_cl.cpp | 14 ++++++++++++++ src/object/schema_manager.c | 6 ++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/cubridmanager b/cubridmanager index 0e6ecb0e75b..aee66659e11 160000 --- a/cubridmanager +++ b/cubridmanager @@ -1 +1 @@ -Subproject commit 0e6ecb0e75b5a3570b0adc42ea0d214e323647e7 +Subproject commit aee66659e11bec1b426ec11f872d36a9345425f8 diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 4d65f0ff06e..f59857a6022 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -1063,7 +1063,15 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) } memset ((*histogram)->null_frequency, 0, sizeof (double) * attr_count); + int i = 0; + + if (*histogram == NULL || (*histogram)->histogram == NULL || (*histogram)->null_frequency == NULL + || class_->attributes == NULL) + { + goto error_end; + } + for (att = class_->attributes; att != NULL && class_->attributes != NULL; att = (SM_ATTRIBUTE *) att->header.next) { const char *attname = (char *) att->header.name; @@ -1071,6 +1079,12 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) DB_VALUE null_frequency_value; error = db_get_histogram (classop, attname, &histogram_obj); + + if (*histogram == NULL || (*histogram)->histogram == NULL || (*histogram)->null_frequency == NULL) + { + goto error_end; + } + (*histogram)->histogram[i] = NULL; (*histogram)->null_frequency[i] = 0.0; diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 472c64a2a44..f945b5a94fb 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -13704,6 +13704,12 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) { /* class_of, key_attr */ + if (class_->attributes == NULL) + { + AU_ENABLE (au_save); + goto end; + } + db_get_histogram (op, att->header.name, &histogram_obj); if (histogram_obj != NULL) From 01d5c63fc9c7326431b23fb79a6d6739a61dcd50 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 10 Feb 2026 21:14:33 +0900 Subject: [PATCH 104/112] (corebug fix) parser --- src/histogram/histogram_cl.cpp | 1 - src/parser/xasl_generation.c | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index f59857a6022..8e3defbe2e0 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -1255,7 +1255,6 @@ dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with const char *col_name = attr_name; const char *type_name = db_get_type_name (attr_type); int rows_scanned = 0; - int bucket_count = 0; DB_VALUE histogram_value, null_frequency_value; DB_OBJECT *histogram_obj = NULL; int histogram_total_length = 0; diff --git a/src/parser/xasl_generation.c b/src/parser/xasl_generation.c index 3d05705c9ea..8ab097c2f98 100644 --- a/src/parser/xasl_generation.c +++ b/src/parser/xasl_generation.c @@ -12446,6 +12446,12 @@ pt_to_class_spec_list (PARSER_CONTEXT * parser, PT_NODE * spec, PT_NODE * where_ NULL, where, NULL, NULL, regu_attributes_pred, regu_attributes_rest, NULL, output_val_list, regu_var_list, NULL, cache_pred, cache_rest, NULL, NO_SCHEMA, db_values_array_p, regu_attributes_reserved); + + if (access == NULL) + { + return NULL; + } + if (access_method == ACCESS_METHOD_SEQUENTIAL && PT_IS_SPEC_FLAG_SET (spec, PT_SPEC_FLAG_NO_PARALLEL_HEAP_SCAN)) { From ac98c5d73b1ff89e923d047c4941de8dcacca501 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 11 Feb 2026 19:01:11 +0900 Subject: [PATCH 105/112] =?UTF-8?q?(=EB=B2=84=EA=B7=B8=EB=82=9C=20?= =?UTF-8?q?=EC=84=9C=EB=B8=8C=EB=AA=A8=EB=93=88=EB=93=A4=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=20=EB=B0=8F=20=EA=B3=A0=EC=B9=98=EA=B8=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cubrid-cci | 2 +- cubrid-jdbc | 2 +- cubridmanager | 2 +- src/histogram/histogram_cl.cpp | 37 +++++++++++++++++++++++++++++----- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/cubrid-cci b/cubrid-cci index ef5470ffae4..2fb8d6d02c4 160000 --- a/cubrid-cci +++ b/cubrid-cci @@ -1 +1 @@ -Subproject commit ef5470ffae4aa934425145e393fefc81899c84a7 +Subproject commit 2fb8d6d02c41386be0d56c3cfc6a14ad7e17ac15 diff --git a/cubrid-jdbc b/cubrid-jdbc index 4a40cb95c9c..8781d2c725d 160000 --- a/cubrid-jdbc +++ b/cubrid-jdbc @@ -1 +1 @@ -Subproject commit 4a40cb95c9c876f8ffea7640906ffae33d2efbf5 +Subproject commit 8781d2c725db5e0e9181c94054b33ad4bf03d9ad diff --git a/cubridmanager b/cubridmanager index aee66659e11..72ce603a376 160000 --- a/cubridmanager +++ b/cubridmanager @@ -1 +1 @@ -Subproject commit aee66659e11bec1b426ec11f872d36a9345425f8 +Subproject commit 72ce603a3761b34aee4b3c86e583aa548b0ffa7c diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 8e3defbe2e0..40e35031b9c 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -829,7 +829,14 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc } else { - bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + if (bucket_index == histogram_reader.bucket_count() - 1) + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index); + } + else + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + } } } else @@ -867,7 +874,14 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc } else { - bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + if (bucket_index == histogram_reader.bucket_count() - 1) + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index); + } + else + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + } } } else @@ -904,7 +918,14 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc } else { - bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + if (bucket_index == histogram_reader.bucket_count() - 1) + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index); + } + else + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + } } } else @@ -942,7 +963,14 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc } else { - bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + if (bucket_index == histogram_reader.bucket_count() - 1) + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index); + } + else + { + bucket_rows = histogram_reader.bucket_cumulative (bucket_index - 1); + } } } else @@ -1079,7 +1107,6 @@ stats_get_histogram (MOP classop, HIST_STATS **histogram) DB_VALUE null_frequency_value; error = db_get_histogram (classop, attname, &histogram_obj); - if (*histogram == NULL || (*histogram)->histogram == NULL || (*histogram)->null_frequency == NULL) { goto error_end; From 40b871cbb7881ef4b4c03f387b2c19f74c021edf Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 11 Feb 2026 19:08:16 +0900 Subject: [PATCH 106/112] Merge remote-tracking branch 'upstream/develop' into CUBRID-HISTOGRAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (서브모듈 이상해) --- cubrid-cci | 2 +- cubrid-jdbc | 2 +- cubridmanager | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cubrid-cci b/cubrid-cci index 2fb8d6d02c4..ef5470ffae4 160000 --- a/cubrid-cci +++ b/cubrid-cci @@ -1 +1 @@ -Subproject commit 2fb8d6d02c41386be0d56c3cfc6a14ad7e17ac15 +Subproject commit ef5470ffae4aa934425145e393fefc81899c84a7 diff --git a/cubrid-jdbc b/cubrid-jdbc index 8781d2c725d..4a40cb95c9c 160000 --- a/cubrid-jdbc +++ b/cubrid-jdbc @@ -1 +1 @@ -Subproject commit 8781d2c725db5e0e9181c94054b33ad4bf03d9ad +Subproject commit 4a40cb95c9c876f8ffea7640906ffae33d2efbf5 diff --git a/cubridmanager b/cubridmanager index 72ce603a376..0e6ecb0e75b 160000 --- a/cubridmanager +++ b/cubridmanager @@ -1 +1 @@ -Subproject commit 72ce603a3761b34aee4b3c86e583aa548b0ffa7c +Subproject commit 0e6ecb0e75b5a3570b0adc42ea0d214e323647e7 From 229e6c9569870155c0930aa63ca353f350f20e32 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Wed, 11 Feb 2026 19:29:52 +0900 Subject: [PATCH 107/112] (build) --- src/histogram/histogram_cl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 40e35031b9c..4cb8fec09a9 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -829,7 +829,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc } else { - if (bucket_index == histogram_reader.bucket_count() - 1) + if (bucket_index == static_cast (histogram_reader.bucket_count()) - 1) { bucket_rows = histogram_reader.bucket_cumulative (bucket_index); } @@ -874,7 +874,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc } else { - if (bucket_index == histogram_reader.bucket_count() - 1) + if (bucket_index == static_cast (histogram_reader.bucket_count()) - 1) { bucket_rows = histogram_reader.bucket_cumulative (bucket_index); } @@ -918,7 +918,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc } else { - if (bucket_index == histogram_reader.bucket_count() - 1) + if (bucket_index == static_cast (histogram_reader.bucket_count()) - 1) { bucket_rows = histogram_reader.bucket_cumulative (bucket_index); } @@ -963,7 +963,7 @@ histogram_get_comp_selectivity (PT_NODE *lhs, PT_NODE *rhs, bool is_ge, bool inc } else { - if (bucket_index == histogram_reader.bucket_count() - 1) + if (bucket_index == static_cast (histogram_reader.bucket_count()) - 1) { bucket_rows = histogram_reader.bucket_cumulative (bucket_index); } From 7c436cdfdc187f7d3411d578dd49ab1c08160efc Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 12 Feb 2026 16:02:18 +0900 Subject: [PATCH 108/112] =?UTF-8?q?(bugfix)=20no=20bucket=20=EC=83=81?= =?UTF-8?q?=ED=99=A9=EC=97=90=EC=84=9C=20=EB=8F=99=EC=9E=91=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8D=98=20=EB=AC=B8=EC=A0=9C=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parser/csql_grammar.y | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/parser/csql_grammar.y b/src/parser/csql_grammar.y index 42964bff5ff..8bd507ef883 100644 --- a/src/parser/csql_grammar.y +++ b/src/parser/csql_grammar.y @@ -582,6 +582,7 @@ BEGIN_SUPPRESS_WARNING_BISON_FLEX %type opt_invisible %type opt_paren_plus %type opt_with_fullscan +%type with_n_buckets %type online_parallel %type comp_op %type opt_of_all_some_any @@ -4747,7 +4748,7 @@ update_statistics_stmt ; update_histogram_stmt - : ANALYZE TABLE only_class_name UPDATE HISTOGRAM ON_ histogram_column_list WITH unsigned_integer BUCKETS opt_with_fullscan + : ANALYZE TABLE only_class_name UPDATE HISTOGRAM ON_ histogram_column_list with_n_buckets opt_with_fullscan {{ PT_NODE *uhs = parser_new_node (this_parser, PT_UPDATE_HISTOGRAM); PT_NODE *target_t = parser_new_node (this_parser, PT_SPEC); @@ -4759,14 +4760,14 @@ update_histogram_stmt uhs->info.histogram.target_table_spec = target_t; uhs->info.histogram.target_columns = $7; - uhs->info.histogram.bucket_count = $9->info.value.data_value.i; - uhs->info.histogram.with_fullscan = $11; + uhs->info.histogram.bucket_count = $8; + uhs->info.histogram.with_fullscan = $9; } $$ = uhs; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) }} - | ANALYZE TABLE only_class_name UPDATE HISTOGRAM WITH unsigned_integer BUCKETS opt_with_fullscan + | ANALYZE TABLE only_class_name UPDATE HISTOGRAM with_n_buckets opt_with_fullscan {{ PT_NODE *uhs = parser_new_node (this_parser, PT_UPDATE_HISTOGRAM); PT_NODE *target_t = parser_new_node (this_parser, PT_SPEC); @@ -4777,8 +4778,8 @@ update_histogram_stmt target_t->info.spec.meta_class = PT_CLASS; uhs->info.histogram.target_table_spec = target_t; uhs->info.histogram.target_columns = NULL; - uhs->info.histogram.bucket_count = $7->info.value.data_value.i; - uhs->info.histogram.with_fullscan = $9; + uhs->info.histogram.bucket_count = $6; + uhs->info.histogram.with_fullscan = $7; } $$ = uhs; @@ -4853,6 +4854,18 @@ opt_with_fullscan }} ; + +with_n_buckets + : /* empty */ + {{ + $$ = 10; + }} + | WITH unsigned_integer BUCKETS + {{ + $$ = $2->info.value.data_value.i; + }} + ; + opt_of_to_eq : /* empty */ | TO From 16c0c34425bea122589442a86266eb1f11058305 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Thu, 12 Feb 2026 16:51:16 +0900 Subject: [PATCH 109/112] =?UTF-8?q?(bugfix)=20=EC=98=88=EC=95=BD=EC=96=B4?= =?UTF-8?q?=20=EA=B4=80=EB=A0=A8=20=EB=B2=84=EA=B7=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index 278c933d509..699e56f99be 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -35,13 +35,13 @@ typedef struct hist_stats HIST_STATS; /* null frequency query template */ static const char *NULL_FREQUENCY_QUERY_TEMPLATE = - "SELECT SUM(CASE WHEN %s IS NULL THEN 1 ELSE 0 END) * 1.0 / NULLIF(COUNT(*), 0) AS null_frequency FROM %s;"; + "SELECT SUM(CASE WHEN [%s] IS NULL THEN 1 ELSE 0 END) * 1.0 / NULLIF(COUNT(*), 0) AS null_frequency FROM [%s];"; static const char *NULL_FREQUENCY_WITH_SAMPLING_SCAN_QUERY_TEMPLATE = - "SELECT /*+ SAMPLING_SCAN */ SUM(CASE WHEN %s IS NULL THEN 1 ELSE 0 END) * 1.0 / NULLIF(COUNT(*), 0) AS null_frequency FROM %s;"; + "SELECT /*+ SAMPLING_SCAN */ SUM(CASE WHEN [%s] IS NULL THEN 1 ELSE 0 END) * 1.0 / NULLIF(COUNT(*), 0) AS null_frequency FROM [%s];"; /* histogram query template */ static const char *HISTOGRAM_QUERY_TEMPLATE = - "WITH src AS (SELECT %s AS val FROM %s WHERE %s IS NOT NULL), " + "WITH src AS (SELECT [%s] AS val FROM [%s] WHERE [%s] IS NOT NULL), " "cnt AS (SELECT val, COUNT(*) AS c FROM src GROUP BY val), " "mcv_ranked AS (SELECT val, c, ROW_NUMBER() OVER (ORDER BY c DESC, val) AS rn FROM cnt ORDER BY c DESC LIMIT %d), " "non_mcv_flagged AS (SELECT val, c FROM cnt WHERE val NOT IN (SELECT val FROM mcv_ranked)), " @@ -54,7 +54,7 @@ static const char *HISTOGRAM_QUERY_TEMPLATE = "COUNT(*) AS approx_ndv, MAX(is_mcv) AS is_mcv FROM all_buckets GROUP BY bid ORDER BY MAX(val);"; /* histogram with sampling scan query template */ static const char *HISTOGRAM_WITH_SAMPLING_SCAN_QUERY_TEMPLATE = - "WITH src AS (SELECT /*+ SAMPLING_SCAN */ %s AS val FROM %s WHERE %s IS NOT NULL), " + "WITH src AS (SELECT /*+ SAMPLING_SCAN */ [%s] AS val FROM [%s] WHERE [%s] IS NOT NULL), " "cnt AS (SELECT val, COUNT(*) AS c FROM src GROUP BY val), " "mcv_ranked AS (SELECT val, c, ROW_NUMBER() OVER (ORDER BY c DESC, val) AS rn FROM cnt ORDER BY c DESC LIMIT %d), " "non_mcv_flagged AS (SELECT val, c FROM cnt WHERE val NOT IN (SELECT val FROM mcv_ranked)), " From 636650e180ee27a4252858e60fe269f8f3509fe1 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Mon, 23 Feb 2026 14:56:40 +0900 Subject: [PATCH 110/112] =?UTF-8?q?(bugfix)=20sum=20=EB=8C=80=EC=8B=A0?= =?UTF-8?q?=EC=97=90=20avg=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/histogram/histogram_cl.hpp b/src/histogram/histogram_cl.hpp index 699e56f99be..06a7ef03606 100644 --- a/src/histogram/histogram_cl.hpp +++ b/src/histogram/histogram_cl.hpp @@ -36,8 +36,10 @@ typedef struct hist_stats HIST_STATS; /* null frequency query template */ static const char *NULL_FREQUENCY_QUERY_TEMPLATE = "SELECT SUM(CASE WHEN [%s] IS NULL THEN 1 ELSE 0 END) * 1.0 / NULLIF(COUNT(*), 0) AS null_frequency FROM [%s];"; +/* Use AVG instead of SUM/COUNT(*) because sampling scales only COUNT(*), not SUM. + * AVG computes ratio over the same sampled set without mixing scaled/unscaled values. */ static const char *NULL_FREQUENCY_WITH_SAMPLING_SCAN_QUERY_TEMPLATE = - "SELECT /*+ SAMPLING_SCAN */ SUM(CASE WHEN [%s] IS NULL THEN 1 ELSE 0 END) * 1.0 / NULLIF(COUNT(*), 0) AS null_frequency FROM [%s];"; + "SELECT /*+ SAMPLING_SCAN */ AVG(CASE WHEN [%s] IS NULL THEN 1.0 ELSE 0.0 END) AS null_frequency FROM [%s];"; /* histogram query template */ static const char *HISTOGRAM_QUERY_TEMPLATE = From e9957bdc3da9bda24c09f39c2373da91c3d49a07 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 24 Feb 2026 15:01:02 +0900 Subject: [PATCH 111/112] =?UTF-8?q?(refactor)=20view=20type=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/object/schema_system_catalog_install.cpp | 5 ++--- src/object/schema_system_catalog_install_query_spec.cpp | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index 90bec15c3ec..4d46a7823f7 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -2143,9 +2143,8 @@ namespace cubschema { {"class_of", "object"}, {"key_attr", format_varchar (255)}, - {"with_fullscan","integer"}, - {"bucket_count", "integer"}, - {"histogram_values", format_varbit (1024)}, + {"with_fullscan", format_varchar (32)}, + {"null_frequency", "double"}, {attribute_kind::QUERY_SPEC, sm_define_view_db_histogram_spec ()} }, // constraint diff --git a/src/object/schema_system_catalog_install_query_spec.cpp b/src/object/schema_system_catalog_install_query_spec.cpp index 81107a266d9..edcc1aceb63 100644 --- a/src/object/schema_system_catalog_install_query_spec.cpp +++ b/src/object/schema_system_catalog_install_query_spec.cpp @@ -1649,9 +1649,8 @@ sm_define_view_db_histogram_spec (void) "SELECT " "[h].[class_of] AS [class_of], " "[h].[key_attr] AS [key_attr], " - "[h].[with_fullscan] AS [with_fullscan], " // TODO : integer -> varchar(32) - "[h].[null_frequency] AS [null_frequency], " - "[h].[histogram_values] AS [histogram_values] " + "CASE WHEN [h].[with_fullscan] = 0 THEN 'sampling scan' ELSE 'full scan' END AS [with_fullscan], " + "[h].[null_frequency] AS [null_frequency] " "FROM " /* CT_DB_HISTOGRAM_NAME */ "[%s] AS [h] " From c5ee6a6d13f33b6af94d318119b7be4d599a1602 Mon Sep 17 00:00:00 2001 From: SOHEE_JUNG Date: Tue, 24 Feb 2026 15:09:45 +0900 Subject: [PATCH 112/112] =?UTF-8?q?(bugfix)=20=EB=88=84=EB=9D=BD=EB=90=9C?= =?UTF-8?q?=20clear=20=EB=B0=8F=20=EA=B8=B0=ED=83=80=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/histogram/histogram_cl.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/histogram/histogram_cl.cpp b/src/histogram/histogram_cl.cpp index 4cb8fec09a9..6cb9cee1022 100644 --- a/src/histogram/histogram_cl.cpp +++ b/src/histogram/histogram_cl.cpp @@ -173,6 +173,7 @@ get_null_frequency (THREAD_ENTRY *thread_p, const char *tbl_name, const char *at if (obj_tmpl == NULL) { error = ER_FAILED; + dbt_abort_object (obj_tmpl); goto end; } @@ -180,6 +181,7 @@ get_null_frequency (THREAD_ENTRY *thread_p, const char *tbl_name, const char *at if (error != NO_ERROR) { error = ER_FAILED; + dbt_abort_object (obj_tmpl); goto end; } @@ -204,7 +206,6 @@ get_null_frequency (THREAD_ENTRY *thread_p, const char *tbl_name, const char *at end: db_query_end (query_result); db_value_clear (&null_frequency_value); - assert (error == NO_ERROR); // for debug return error; } @@ -1019,7 +1020,6 @@ db_get_histogram (MOP classop, const char *attr_name, DB_OBJECT **histogram_obj) DB_OTMPL *obj_tmpl = NULL; DB_VALUE value[2]; DB_VALUE *value_ptrs[2] = { &value[0], &value[1] }; - DB_VALUE histogram_value; const char *search_attrs[2] = { "class_of", "key_attr" }; histogram_class = sm_find_class (CT_DB_HISTOGRAM_NAME); @@ -1316,6 +1316,7 @@ dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with error = db_get (histogram_obj, "histogram_values", &histogram_value); if (error != NO_ERROR) { + db_value_clear (&histogram_value); return ER_FAILED; } @@ -1323,6 +1324,8 @@ dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with error = db_get (histogram_obj, "null_frequency", &null_frequency_value); if (error != NO_ERROR) { + db_value_clear (&null_frequency_value); + db_value_clear (&histogram_value); return ER_FAILED; } @@ -1444,5 +1447,8 @@ dump_histogram (MOP classop, const char *attr_name, DB_TYPE attr_type, bool with } } + db_value_clear (&histogram_value); + db_value_clear (&null_frequency_value); + return NO_ERROR; } \ No newline at end of file